1 问题描述
在项目中使用vue-grid-layout做可拖拽的模块,每个模块有截图下载的功能,使用了html2canvas(版本1.4.1)作为截图插件
/**
* 组件下载
*/
export function componentDownload(domId, imgName) {
setTimeout(() => {
const targetDom = document.getElementById(domId);
html2canvas(targetDom, {
scale: 1, //处理模糊问题
useCORS: true, //开启跨域,这个是必须的
backgroundColor: `#002d66`,
}).then((canvas) => {
canvas.toBlob(function (blob) {
saveAs(blob, imgName + '.png');
});
});
}, 500);
}
问题1: 多数模块下载下来的截图是空白 问题2: 部分截图背景色不一致
[问题2截图]
2问题定位
问题1: vue-grid-layout 可拖拽模块定位使用了css 中的transform: translate3d,html2canvas对 transform属性的支持尚有些问题
问题2: 原因大致和问题1相同,html2canvas对 boxshadow属性支持也是会出现问题
3问题解决
问题1
修改 html2canvas代码 src/render/stacking-context.ts,将getEffects改成下面的样子,其实就是移动了一下effects.unshift(...croplessEffects)位置,问题就解决了
getEffects(target: EffectTarget): IElementEffect[] {
let inFlow = [POSITION.ABSOLUTE, POSITION.FIXED].indexOf(this.container.styles.position) === -1;
let parent = this.parent;
const effects = this.effects.slice(0);
while (parent) {
const croplessEffects = parent.effects.filter((effect) => !isClipEffect(effect));
if (inFlow || parent.container.styles.position !== POSITION.STATIC || !parent.parent) {
inFlow = [POSITION.ABSOLUTE, POSITION.FIXED].indexOf(parent.container.styles.position) === -1;
if (parent.container.styles.overflowX !== OVERFLOW.VISIBLE) {
const borderBox = calculateBorderBoxPath(parent.curves);
const paddingBox = calculatePaddingBoxPath(parent.curves);
if (!equalPath(borderBox, paddingBox)) {
effects.unshift(
new ClipEffect(paddingBox, EffectTarget.BACKGROUND_BORDERS | EffectTarget.CONTENT)
);
}
}
effects.unshift(...croplessEffects);
} else {
effects.unshift(...croplessEffects);
}
parent = parent.parent;
}
return effects.filter((effect) => contains(effect.target, target));
}
问题2
这个没有找到好的方法,就先将src/render/canvas/canvas-renderer.ts 关于boxShadow渲染的代码先注释掉了,对截图无伤大雅,注释代码如下
/**
styles.boxShadow
.slice(0)
.reverse()
.forEach((shadow) => {
this.ctx.save();
const borderBoxArea = calculateBorderBoxPath(paint.curves);
const maskOffset = shadow.inset ? 0 : MASK_OFFSET;
const shadowPaintingArea = transformPath(
borderBoxArea,
-maskOffset + (shadow.inset ? 1 : -1) * shadow.spread.number,
(shadow.inset ? 1 : -1) * shadow.spread.number,
shadow.spread.number * (shadow.inset ? -2 : 2),
shadow.spread.number * (shadow.inset ? -2 : 2)
);
if (shadow.inset) {
this.path(borderBoxArea);
this.ctx.clip();
this.mask(shadowPaintingArea);
} else {
this.mask(borderBoxArea);
this.ctx.clip();
this.path(shadowPaintingArea);
}
this.ctx.shadowOffsetX = shadow.offsetX.number + maskOffset;
this.ctx.shadowOffsetY = shadow.offsetY.number;
this.ctx.shadowColor = asString(shadow.color);
this.ctx.shadowBlur = shadow.blur.number;
this.ctx.fillStyle = shadow.inset ? asString(shadow.color) : 'rgba(0,0,0,1)';
this.ctx.fill();
this.ctx.restore();
});
*/
4 总结
这两个问题,我是通过查询网上资料配合直觉经验解决的,当然如果一点点去调试html2canvas代码,研究渲染的过程是个扎实的办法,并且能收获更多,但是项目周期不允许啊。
再有就是调试的时候,尽可能简化问题,我一开始用了很多模块的页面做调试,浪费了很多时间。