如何将 DOM 生成为图片?速度打败 html2canvas、dom-to-image
1. 复制 DOM 并序列化
const cloneNode = document.body.cloneNode(true);
const xmlSerializer = new XMLSerializer();
const html = xmlSerializer.serializeToString(cloneNode);
2. 嵌入 svg foreignObject
const svg = `
<svg
xmlns='http://www.w3.org/2000/svg'
width='${document.body.clientWidth}'
height='${document.body.clientHeight}'
>
<foreignObject
x='0'
y='0'
width='100%'
height='100%'
>
${html}
</foreignObject>
</svg>
`;
3. 通过 canvas 生成图片
const canvas = document.createElement('canvas');
canvas.width = document.body.clientWidth;
canvas.height = document.body.clientHeight;
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0);
canvas.toBlob((blob) => {
const blobURL = URL.createObjectURL(blob);
window.open(blobURL);
URL.revokeObjectURL(blobURL);
});
};
img.src = `data:image/svg+xml;charset=utf-8,${svg}`;
问题:图片内容无样式
svg 以字符串的形式通过 img src data 加载,不与当前页面共享样式。
市面上的截图插件 html2canvas、dom-to-image 都是通过内联样式的方式解决此问题。
深度遍历每个源 DOM 元素,每个 DOM 元素通过 window.getComputedStyle
方法当前元素的所有样式属性和值。
找到相应的克隆 DOM 元素,通过 getPropertyValue
方法和 setProperty
方法重新赋值。
“DOM 操作很慢”,在此也有所体现。
简单算一笔账,每个 DOM 都有 300+ 个样式属性,假设每个 DOM 都有 5 个有效样式,100 个 DOM 就需要复制样式 500 次。假设每次复制耗时 0.5 毫秒,那就需要耗时 250 毫秒。
在条件允许的情况下,可以提前准备好样式内容,嵌入 svg,移除这一环节,提升截图效率。
const svg = `
<svg
xmlns='http://www.w3.org/2000/svg'
width='${document.body.clientWidth}'
height='${document.body.clientHeight}'
>
+ <style>
+ ${svgStyle}
+ </style>
<foreignObject
x='0'
y='0'
width='100%'
height='100%'
>
${html}
</foreignObject>
</svg>
`;
移除样式同步环节之后,速度有质的提升。
问题:图片内容字体丢失
跟图片内容样式丢失原因一样,字体也需要嵌入 svg。 因为不与当前页面共享资源,字体资源引用不能使用 URL 形式,需要转换成 base64 格式。
const response = await fetch(url, { headers: { responseType: 'blob' } });
const blob = await response.blob();
const fileReader = new FileReader();
fileReader.onload = () => {
const b64 = fileReader.result;
};
fileReader.readAsDataURL(blob);
svgStyle 添加字体声明。
svgStyle += `
@font-face {
font-family: "${name}";
src: local("${name}"), url("${b64}");
}
`;
其它方式
参考
全文完,如果觉得这篇文章对你有用,欢迎 点赞 👍、评论 ✍️、收藏 👀
转载自:https://juejin.cn/post/7135449566836424734