react 生成二维码海报图

840 阅读2分钟

需求

前端需要生成含有二维码的海报图,并能下载到本地

解决

1. 依赖

  • qrcode.react(还有其他生成二维码的第三方插件 自选选择)
  • html2canvas(把html转化成canvas画布)
  • save-as(下载本地)

2. 获取二维码链接


    const [qrcodeUrl, setQrurl] = useState(null)


    // 获取二维码
    const initQrcode = async () => {
        const { data } = await getQrcode()    

         // decodeURIComponent 这里解码后端传回的地址
        setQrurl(decodeURIComponent(data.link))

        // 接着生成海报
        createPoster()
    }


    useLayoutEffect(() => {
        initQrcode()
    }, [])

3. 生成海报

顺序:获取二维码 => 生成带有二维码的模板 => 利用html2canvas生成所需海报(这里需要无缝替换模板,不替换则默认显示模板,隐藏canvs海报, 下载海报时再调取canvs海报也可以)

注意:如果用vue的话,有具体的生命周期,可以确保在created前获取二维码,mounted再调用createPoster生成海报,这样才能确保模板中的二维码已经加载好了才开始生成海报。react hooks只能用两种状态区分下确保顺序

    // 为了无缝切换模板和画布
    const [showImg, setShowImg] = useState(true)
    // TODO: 为了让模板的二维码生成后画布才开始生成,否则生成的模板二维码会第一时间获取不到导致无效二维码
    // 
    const [loading, setLoading] = useState(true)

    const createPoster = () => {
        setLoading(false)

        const element = document.getElementById('posterImg')
        html2canvas(element, {
          useCORS: true, //是否尝试使用CORS从服务器加载图像 后端需要配置资源跨域
          allowTaint: false //允许跨域图片
        }).then(function (canvas) {
          const result = document.getElementById('posterResult')
          result.appendChild(canvas)
          setShowImg(false) // 生成海报后 隐藏模板图
        })
    }

4. 海报样式
    <Spin dot loading={loading}>
        // 利用showImg 无缝替换海报模板
        {showImg ? (
            <div className={`relative`}>
                // 海报模板
                <div id='posterImg'>
                    <img
                      style={{ width: 250 }}
                      src={require('../../static/images/poster.png')}
                      alt='error'
                    />

                    <QRCode
                      value={qrcodeUrl}
                      renderAs='canvas'
                      id='qrcodeImage'
                      className='absolute'
                      style={{ left: 67, top: 128 }} // 定位到海报背景图的二维码位置
                    />
                </div>
            </div>
        ) : null}
        // 生成的canvas海报
        <div id='posterResult'></div>
    </Spin>

5. 下载到本地

    const copyImage = () => {
        // 获取posterResult下的画布
        const oCanvas = document.getElementById('posterResult').getElementsByTagName('canva')[0]

        oCanvas.toBlob(function (blob) {
            saveAs(blob, 'QR code') // QR code 下载的文件名
        })
    } 

    <Button className='my-5' type='primary' onClick={copyImage}>
        下载海报
    </Button>

效果图 (左边模板图 右边canvas画布)

1669691772115.jpg

注意

若遇到跨域问题,可以尝试用以下方法解决
1、由于canvas加载的图片不支持跨域,可以尝试添加useCORS: true并在img加上 crossOrigin='anonymous'跨域属性
2、图片src加上时间戳 src=imgUrl?t=${new Date().getTime()}