本次做h5 活动,遇到一个需求,点击button 把html 生成图片,长按保存功能 由于html的结构比较复杂,使用canvas 直接画相对来说增加了不小工作量,所以使用html2canvas ,html2canvas的使用比较简单,但是坑也很多
老生常谈的跨域问题
谈到跨域问题,应该只要入了canvas toDataURL 转成图片的坑就应该遇到过这个问题,如果不进行跨域处理生成图片不能跨域的图片会空白处理 这个没有好的解决方案, 图片服务器需要配置Access-Control-Allow-Origin 由于公司的开发build 与 js 是两个团队在做,build 团队的图片地址都是不可跨域的,而且页面所以的图片设置都是background image 的形式,针对这个问题我做了如下处理
- 把之前build 图片下载重新上传到支持跨域的cnd 服务器
- 把需要生成图片的html css 样式背景图片进行重写
当然这样还没有结束,配置html2canvas
html2canvas(dom, {
backgroundColor: null,
canvas,
//allowTaint: true,
useCORS: true
})
复制代码
useCORS 设置允许跨域,特别提醒 allowTaint 也是允许跨域,但是这个允许跨域只是允许你跨域生成canvas ,但是还是不能把canvas转化成图片,要想解决toDataURL 的跨域问题,还需要使用useCORS。但是这两个属性不能共生
生成的图片模糊
把scale 设置成二倍直接上代码
* 根据window.devicePixelRatio获取像素比
*/
function DPR() {
if (window.devicePixelRatio && window.devicePixelRatio > 1) {
return window.devicePixelRatio;
}
return 1;
}
.....
// DOM 节点计算后宽高
const width = parseValue(box.width);
const height = parseValue(box.height);
// 获取像素比
const scaleBy = DPR()*2;
// 创建自定义 canvas 元素
var canvas = document.createElement('canvas');
// 设定 canvas 元素属性宽高为 DOM 节点宽高 * 像素比
canvas.width = width * scaleBy;
canvas.height = height * scaleBy;
// 设定 canvas css宽高为 DOM 节点宽高
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
// 获取画笔
const context = canvas.getContext('2d');
// 将所有绘制内容放大像素比倍
context.scale(scaleBy, scaleBy);
// imageSmoothingEnabled Canvas 2D API 用来设置图片是否平滑的属性,true表示图片平滑(默认值),false表示图片不平滑,默认的改变大小的算法会造成图片模糊并且破坏图片原有的像素。 如果那样的话,设置属性值为false。
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
.....
html2canvas(dom, {
backgroundColor: null,
canvas,
width: width, // 设置width
height: height, // 设置height
scale: scaleBy,// 设置scaleBy
useCORS: true
})
复制代码
过程中使用的雪碧图最容易出现模糊的情况,所以图片需要使用2倍图
生成图片过程中会出现html闪现
可能这个题目不是很好的描述问题。我先描述一下问题所在,由于html2canvas 生成图片所在的html 必须是真实存在的,否则生成canvas为空白。也就是需要生成html不能设置 disabled: none; visibility: hidden; 等属性。 因此表明在调用html2canvas 生成canvas 过程中必须dom 节点渲染完成。因此这就会导致在生成canvas 会出现原有html 的闪现 这个问题其实也比较好解决,用了一个小技巧,使用top 属性,把html 移除视野 top:100%
当然这个解决方案比较多,目前我用的是这个
动态渲染html 生成canvas会出现样式错乱
这个问题,本身需要生成的html 中有一部分是轮播图,这样html dom 会动态渲染, 解决方案很简单,取消轮播图,直接用 v-if(注:工程使用vue 开发)判定进行html 渲染,取消轮播
生成的图片background-repeat: no-repeat;不生效,导致图片重复
这个问题我也没找到原因,结果就是虽然设置了background-repeat: no-repeat; 但是图片底部会出现大约1像素的重复。 由于没有找到根本原因,使用了最直接的的方案解决,直接把图片高度增加2像素,成功避免了这个问题。(哈哈哈哈,我真是一个投机取巧的鬼才)
html2canvas 不支持 display: -webkit-box
由于代码中有段文字需要多行末尾省略号,所以出现如下css
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
复制代码
在html2canvas中,会将css中的display中的值映射成一个数字,而在下图的映射表中,只要找到了flex的映射值,并没有--webkit-flex的映射值,所以-webkit-flex被映射成了DISPLAY.NONE,从而导致了isVisible的计算值返回了false,最终导致了无法生成想要的canvas
解决方案不使用flex布局,js 实现文字溢出,此方案仅限于文字个数具体的情况下,所以比较局限,大家有好的方案欢迎补充 css
height:2倍的line-height; /*根据实际需求更改*/
display:inline-block;
复制代码
js
contentText(num){
const ellipsis = oldContentText.length > num?'...':''
return oldContentText.slice(0,num) + ellipsis
}
复制代码