react使用canvas手写签名优化

优化点

1、当顶部有其他元素或组件时,画板笔画起笔不在落笔位置,如添加backHome组件
2、更改清除画图时,起笔长度变长问题

BackHome.js

import React, {useImperativeHandle} from 'react'
import { useHistory } from 'react-router-dom'
import { useLocation } from 'react-router-dom'
import { Button, Divider } from 'antd'

// 使用forwardRef 可以在父组件中获取到ref
const BackHome = React.forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    ref: ref.current
  }));
  const location = useLocation();
  const history = useHistory();
  const toHome = () => {
    history.push('/')
  }
  let name = (location.state && location.state.name) || location.pathname.slice(1, location.pathname.length)
  return (
    <div ref={ref}>
      <Button onClick={toHome}>返回首页</Button>
      <div style={{'padding': '1px 0'}}>
        <Divider orientation="center">
          当前:{name}
        </Divider>
      </div>
      
    </div>
  )
})

export default BackHome;

Autograph.js

import React, { Component } from 'react'
import { Button, Divider, Row, Col } from 'antd'
import BackHome from '../component/BackHome'
class Autograph extends Component {
  state = {
    base: '' // base64形式的图片
  }
  ref=React.createRef();
  componentDidMount () {
    this.initCanvasEvent()
  }
  initCanvas () {
    // 自适应设置画布大小
    const vWidth = document.body.clientWidth
    const can = document.getElementById('canvas')
    can.width = vWidth
    can.height = vWidth
    // 画布准备
    const context = can.getContext('2d')
    // 添加背景色
    context.fillStyle = '#ccc'
    context.fillRect(0, 0, can.width, can.height)
    // 笔尖设置
    context.strokeStyle = '#000' // 笔尖颜色
    context.lineWidth = 6 // 笔尖粗度
    return {
      can,
      context
    }
  }
  initCanvasEvent () {
    // 获取canvas 及 context
    const { can, context } = this.initCanvas()
    // 顶部组件的高,解决笔记不在落笔的位置
    // console.log(this.ref.current.ref.clientHeight)
    const refHeight = this.ref.current.ref && this.ref.current.ref.clientHeight
    // 监听触屏事件
    can.addEventListener('touchstart', (e) => {
      context.beginPath()
      context.moveTo(e.touches[0].pageX, e.touches[0].pageY - refHeight)
    })
    can.addEventListener('touchmove', (e) => {
      e.preventDefault(); // 阻止页面拖动,如部分移动端,上下左右滑动手势,等
      context.lineTo(e.touches[0].pageX, e.touches[0].pageY - refHeight)
      context.stroke()
    })
    can.addEventListener('touchend', () => {
      context.closePath()
    })
  }
  blankCanvas () {
    const blank = document.createElement('canvas')
    const canImg = document.getElementById('canvas')
    blank.width = canImg.width
    blank.height = canImg.height
    // 为使空画布与现有画图相同 (可根据实际需要修改)
    const context = blank.getContext('2d')
    context.fillStyle = '#ccc'
    context.fillRect(0, 0, blank.width, blank.height)
    // 为true 则为空画图
    // console.log(canImg.toDataURL() === blank.toDataURL());
    return canImg.toDataURL() === blank.toDataURL()
  }
  getCanvasImg () {
    const isFull = this.blankCanvas()
    if (isFull) {
      // 根据项目ui组件自行更改设置
      alert('请签名')
      return
    }
    // 获取到base64代码
    // console.log(document.querySelector('canvas').toDataURL());
    this.setState({
      base: document.querySelector('canvas').toDataURL()
    })
  }
  clearCanvas () {
    // canvas每当高度或宽度被重设时,画布内容就会被清空,所以会导致之前画的圆都被删除,所以重新抽离出 initCanvas ,与事件分开
    this.initCanvas()
  }
  render () {
    return (
      <div>
        <BackHome ref={this.ref} />
        <canvas id='canvas' disable-scroll="true"></canvas>
        <Divider orientation="center">手写签名</Divider>
        <Row justify="space-around" align="middle">
          <Col>
            <Button onClick={this.getCanvasImg.bind(this)}>提交签名</Button>
          </Col>
          <Col>
            <Button onClick={this.clearCanvas.bind(this )}>清除签名</Button>
          </Col>
        </Row>
        <div style={{'wordBreak': 'break-all'}}>
          base64图片: <br/> {this.state.base}
        </div>
      </div>
    )
  }
}
export default Autograph

/*
  https://www.w3school.com.cn/tags/html_ref_canvas.asp
  https://blog.csdn.net/Luckyzhoufangbing/article/details/87784843
  https://blog.csdn.net/weixin_30471561/article/details/97082558
*/ 
原文地址:https://www.cnblogs.com/-roc/p/14566487.html