likes
comments
collection
share

小程序H5生成二维码海报图-插件html2canvas踩坑

作者站长头像
站长
· 阅读数 19

需求场景

将小程序H5页面(含有小程序二维码)的一部分内容,或者全部内容生成一张图片,并以图片的形式进行如下核心操作: 保存到手机,分享给朋友(调起微信分享接口)等。 微信好友可以通过图片中的二维码扫码进入对应的小程序,实现用户裂变。

小程序H5生成二维码海报图-插件html2canvas踩坑 右下角为分享出去的二维码

选择该插件(html2canvas)的原因

Html2canvas加载后将会浏览页面上的所有元素,集合所有页面元素的信息,然后用户就可以通过Html2canvas把选取的页面截图下来(通过css选择器选取你想截取的页面)。 屏幕截图基于DOM,因此可能无法真正表示真实屏幕截图的100%,因为它无法生成实际的屏幕截图,而是根据页面上的可用信息构建屏幕截图。它不需要服务器提供任何渲染,因为整个图像是在客户端的浏览器上创建的。 这就会导致Html2canvas只会渲染它认识的正确的DOM元素属性,还有很多CSS属性是不会生效的,也就渲染不出来了。 综上所述。这个插件能够满足我们的需求。

插件的基本用法

  1. npm安装 npm i html2canvas@1.0.0-rc.4 --save

  2. 项目引入 import html2canvas from 'html2canvas'

    a. 项目中采用rc.4版本。 最新rc.7版本在ios13系统中存在不兼容。

  3. 基本使用

踩坑

  1. 图片跨域导致截图对应区域空白

出现原因:因为html页面内,必定含有用户头像,二维码等后台返回的图片,html的img标签src属性不受跨域影响,故html页面不受影响 。但canvas不支持跨域。当我们尝试生成canvas时,会报错。

小程序H5生成二维码海报图-插件html2canvas踩坑

cors

什么是 cors : developer.mozilla.org/zh-CN/docs/…

cors 可以分为两种方案进行:

  • 第一种方案:cors + 插件配置项

    服务器端支持(必须):在跨域的服务器上设置header允许图片跨域 header头应设置为 Access-Control-Allow-Origin: * 小程序H5生成二维码海报图-插件html2canvas踩坑 前端支持(必须):插件配置项 useCORS: true
  • 实际项目遇到的问题:

  1. 第一个问题:后台也配置了二维码的cors,但是canvas上依然画不出二维码。此时你需要跟后台人员确认问题图片存放的cdn地址以及在当前测试环境下图片跨域是否生效,我个人是在测试环境271出问题,但是在预发以及线上环境就没问题了。

  2. 第二个问题:ios13系统中,第一次在当前页面生成canvas,微信头像会丢失的情况。ios14系统中,初始化微信头像无法显示。

    • 排查后发现,因为在HTML中,二维码对应的img标签添加了 crossOrigin='annoymous' 属性。 但是此时又延伸出问题:背景图片跟二维码的img标签如果携带该属性,为什么不出现丢失问题? • 我理解为微信头像 后台跨域配置的问题,因为其他的两张图是在公司cdn的域名下,而微信头像比较特殊,有很多种情况:有微信自己服务器 有公司cdn 同时,各个移动端浏览器厂商对跨域限制的处理不是一致的,所以不好处理。 所以为了统一,还是不加 头像 img 的标签属性 crossOrigin='annoymous'
  • 针对第二个问题的 crossOrigin='annoymous'属性 做一个扩展:

    • crossorigin - 定义从其他来源的服务器加载资源时使用的选项

    • 它有效地更改了浏览器发送的HTTP请求。如果添加了“ crossorigin”属性,则会导致将源:键值对添加到HTTP请求中,如下图所示。

小程序H5生成二维码海报图-插件html2canvas踩坑

  • 英文解释 crossorigin can be set to either “anonymous” or “use-credentials”. Both will result in adding origin: into the request. The latter however will ensure that credentials(凭据) are checked. No crossorigin attribute in the tag will result in sending a request without origin: key-value pair.

  • 如果跨域设置不正确,浏览器将会取消该请求

小程序H5生成二维码海报图-插件html2canvas踩坑

  • 第二种方案:把需要跨域的图片,全部转为base64

  • 通过canvas转图片为base64的原理:

需要创建具有正确尺寸的canvas元素,并使用drawImage函数复制图像数据。然后,可以使用该toDataURL函数获取数据:具有以64为基数编码的图像的url。请注意,图像必须已完全加载,否则将只获得一个空的(黑色,透明)图像。

• ** 具体实现流程 **

• 初始化拿到图片时, 直接将url转为base64放进src。但这种情况同样需要第一种方案中后端的cors支持,所以还是第一种方案更好。

• 与第一种方案不同的是,

• 插件配置项 useCORS: true 可以不用进行配置了。 配置了也不会受影响。

• 微信头像的img标签设置属性 crossOrigin = 'anonymous' 也不会受影响。

  • 转为base64的方案同样用到了canvas。(当然还有很多可以转base64的方法)
  • 核心步骤:img.crossOrigin = 'anonymous' 一定不要丢。

getBase64FromImageUrl = (url) => {
    return new Promise((resolve, reject) => {
      var dataURL = ''
      var img = new Image()
      img.crossOrigin = 'anonymous'
      img.src = url
      // Img.src = url + "?timeStamp=" + new Date();
      img.onload = function () {
        // 要先确保图片完整获取到,这是个异步事件
        var canvas = document.createElement('canvas') 
        var width = img.width
        var height = img.height
        canvas.width = width
        canvas.height = height
        canvas.getContext('2d').drawImage(img, 0, 0, width, height) 
        dataURL = canvas.toDataURL('image/png') 
        resolve(dataURL)
      }
    })
  }

  • 当页面含有多个图片需要转换为base64时,可以使用Promise.all进行处理。

总结

跟后台沟通cors是一切前提。 img标签的crossOrigin='annoymous'属性不能随意设置,必须跟后台沟通cors。解决问题最保险的方式是将图片全部转为base64.

2020 01 20 更新

用cors的方式请求跨域图片跟不用cors的区别。

  • 我们首先明确 给img标签加 crossOrigin属性 或者 插件配置项 useCors:true 都会导致cors的触发,区别在于一个是初始化就开始,一个是插件运行时才开始。

  • 以两个维度进行展开 :

    • 第一个维度,请求头跟响应头的改变 。

      • request header的区别 :
    
      • 非cors请求:Sec-Fetch-Mode: no-cors
    
      • cors请求:Sec-Fetch-Mode: cors ; 新增:Origin: XXX: 什么是Origin:请求从哪里发起的。
    
    • reponse header的区别: 当图片(例如二维码图片)后台配置了跨域后 响应头会增加 核心代码:

    Access-Control-Allow-Origin: * (或者 指定域名)。

转载自:https://juejin.cn/post/6920100994026061831
评论
请登录