序言:canvas真的很重要,闲来无事大家可以多玩玩,在做这个的时候我也是一直在尝试不使用第三方库直接canvas绘制然后转成base64
1.什么场景下使用
当你需要前端将将页面截图成图片分享到微信时,这个时候你就应该想到canvas,当然比较成熟的库就是html2canvas.此外还有dom-to-image
2.html2canvas原理是什么
集合了业内两种实现思路,一种是canvas,另一种是svg,具体使用哪种需要看具体场景,有兴趣的可以拜读下源码
2.1 canvas
- 递归取出目标模版的所有DOM节点,填充到一个 rederList ,并附加是否为顶层元素/包含内容的容器 等信息
- 通过 z-index、 postion float 等css属性和元素的层级信息将 rederList 排序,计算出一个canvas的renderQueue
- 遍历renderQueue,将css样式转为 setFillStyle 可识别的参数,依据nodeType调用相对应canvas方法,如文本则调用 fillText ,图片 drawImage ,设置背景色的div调用 fillRect 等
- 将画好的canvas填充进页面,利用canvas.toDataURL()转成base64
2.2 svg
- 首先,我们要声明一个基础的svg模版,这个模版需要一些基础的描述信息,最重要的,它要有 这对标签
- 将要渲染的DOM模版嵌入 foreignObject
- 利用 Blob 构建svg图像
- 取出URL,赋值给img
3.如何使用
//html2canvas(targetDom).then(canvas => { // append canvas to page });
html2canvas(this.$refs.imageSave, {
useCORS: true
}).then((canvas) => {
let dataURL = canvas.toDataURL('image/jpeg', 0.6)
})
4.遇到的问题
4.1 如何控制分享图片大小
直接控制生成canvas的style
html2canvas(this.$refs.imageSave, {
useCORS: true
}).then((canvas) => {
canvas.style.width = imgWidth * 0.8 + 'px'
canvas.style.height = 400 + 'px'
let dataURL = canvas.toDataURL('image/jpeg', 0.6)
})
4.2 跨域?一步一个坑!
坑1:
解决方案:useCORS: true
坑2:
看到ACAO不要多想,
1.服务器配置了吗 配置对了吗(域名,端口), 别小看端口,线下测试环境一般是带端口的,线上一般不带,运维说必须要带,默认是80, 千万别信!!!, 带上你就别想绕过去,因为带了80端口坑了我半天,才有了后边的bug
2.还是这个问题,当你配错一次之后,以后配对也不好使了,就问你气不气,没关系毕竟他之前是好使的,这个时候你要想到的就是 缓存 (没错这个东西你想要的时候不来不想要的时候他就一直在这里),我们的解决办法加个字符串
不要用随机字符串,他会击穿cdn,很关键
this.imgUrl = this.$route.query.imgUrl + '?v=234'
坑3:
点击分享太快,图片还没有加载完成,不要小觑这个也可能造成acao
解决方案:加入img onload
坑4:
和客户端交互
解决方案: base64你不知道的事
坑5:
ios9 以下 调用html2canvas img src base64格式的图片不展示
解决方案:降低html2canvas版本 到 1.0.0-rc.0
原因追溯:
装包法缩小范围:通过装不同版本的包发现 1.0.0-rc.0 升级到 1.0.0-rc.1出现了问题
查看github 提交记录,发现有如下改动
进入修改细节查看,基本定位是
具体代码如下
后边拿到测试机自己修改看下,然后提个pr,就酱
4.3 其他坑
4.3.1 background 比 img 模糊,尽量多使用 img
4.3.2 ios 8 不支持 flex 详见: www.jianshu.com/p/059e7b6cc…
4.3.3 position:absolute fixed 不支持
写在最后:有bug没关系,不要慌,google + github 的 issue + 经验脑洞 bug 就能解决
参考地址: