You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React useRef获取Canvas时getContext is not a function报错

报错原因
  • 你将ref直接绑定到了react-signature-canvas组件上,此时canvasRef.current拿到的是该组件的实例对象,不是原生canvas DOM元素,组件实例本身不存在getContext方法,直接调用就会触发你看到的类型错误。
  • 你注释掉的尺寸调整逻辑本身也存在问题:getContext返回的是绘图上下文对象,不是DOM元素,不存在style属性,直接给ctx设置style本身就不符合API规范;且直接修改canvas的width属性如果不同步处理画布缩放、重绘逻辑,会导致已绘制的签名拉伸变形。
修复方案
  1. 修正ref的类型定义,匹配react-signature-canvas的实例类型,不要直接标注为HTMLCanvasElement
  2. 通过组件实例提供的getCanvas()方法获取底层原生canvas DOM元素,再执行DOM相关操作
  3. 调整尺寸时先固定画布原有宽高比,同步处理设备像素比避免绘制模糊,若需要保留已绘制的签名,调整尺寸前先暂存签名数据,尺寸修改完成后重新绘制到画布上,保证内容不丢失、不变形

修复后的完整代码如下:

import { useRef, useEffect } from 'react'
import SignaturePad from 'react-signature-canvas'
// TS场景可引入对应实例类型
// import type { SignaturePad as SignaturePadRef } from 'react-signature-canvas'

const SignatureInput = () => {
  // TS场景下将ref类型替换为SignaturePadRef
  const canvasRef = useRef<any>(null)

  useEffect(() => {
    if (!canvasRef.current) return
    // 通过组件实例方法获取原生canvas
    const canvas = canvasRef.current.getCanvas()
    const ctxContainer = document.getElementById('ctxContainer')
    if (!canvas || !ctxContainer) return

    // 暂存已绘制的签名数据,避免调整尺寸后内容丢失
    const existingSignature = canvasRef.current.toData()
    // 获取父容器宽度,保留原画布宽高比
    const containerWidth = ctxContainer.clientWidth
    const originalRatio = canvas.height / canvas.width
    // 处理设备像素比,避免高清屏绘制模糊
    const dpr = window.devicePixelRatio || 1

    // 设置canvas样式宽高
    canvas.style.width = '100%'
    canvas.style.height = `${containerWidth * originalRatio}px`
    // 设置canvas实际像素宽高
    canvas.width = containerWidth * dpr
    canvas.height = containerWidth * originalRatio * dpr
    
    // 校正上下文缩放比例
    const ctx = canvas.getContext('2d')
    if (ctx) {
      ctx.scale(dpr, dpr)
    }

    // 重绘之前暂存的签名
    if (existingSignature?.length) {
      canvasRef.current.fromData(existingSignature)
    }
  }, [])

  const save = () => {
    if (!canvasRef.current) return
    // 调用组件实例方法获取签名图片
    const signImg = canvasRef.current.toDataURL()
    console.log('saved!', signImg)
  }

  return (
    <div id="ctxContainer" className="signatureInput__option-draw">
      <SignaturePad
        ref={canvasRef}
        canvasProps={{
          className: 'signatureInput__option-draw__canvas',
        }}
        onEnd={save}
      />
    </div>
  )
}

export default SignatureInput

注意:如果你的父容器尺寸是响应式变化的,需要给上述尺寸调整逻辑添加resize事件监听,在容器尺寸变化时重新执行校正逻辑。

内容的提问来源于stack exchange,提问作者Nick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 09:48:15