飞书文档复制网页内容的功能, 如下:
小王思考了片刻…
功能拆解:
要实现这个功能, 要拆分为4个步骤:
- 获得选中内容所属的 div
- 把选中内容的div 转换成canvas
- 转换canvas到二进制图像
- 复制二进制图像到剪贴板
由于小王的业务只需要复制固定区域的div, 所以第一步可以忽略, 简化成:
代码语言:javascript复制
const element = document.getElementById("target");
转换div成 canvas:
时间已经很晚了, 小王咳了一杯咖啡, 继续奋战. 小王苦思冥想, 要怎么把div转换成 canvas. 他琢磨:
- 递归遍历 DOM 树:
- 会从指定的根元素开始,递归遍历整个 DOM 树。
- 对于每个遇到的元素, 分析其样式、位置、大小等属性。
- 处理样式和布局:
- 通过读取元素的 CSS 样式,如颜色、背景、边框等, 复制元素的视觉表现。
- 它会计算元素的盒模型、定位、层叠等布局信息,以确定元素在最终图片中的位置。
- …
小王这时候已经觉得很累了, 于是索性打开浏览器搜索, 结果第一页就看到了: html2canvas. 他看了一眼, github 29K stars. 他查看了一下调用api:
代码语言:javascript复制
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
});
它正是小王需要的!
于是小王在项目中命令行输入:
代码语言:javascript复制
npm install --save html2canvas
然后小王在业务代码中敲下了:
代码语言:javascript复制
function copyDivToImage() {
const element = document.getElementById("target");
html2canvas(element).then(canvas => {
// canvas 拿到了, 然后呢
}
}
转换canvas到二进制图像
小王犹豫, 为什么要转成二进制图像呢, 我直接复制 base64 字符不行吗. 不过很快, 小王就意识到了, 剪贴版API 不支持base64字符串的类型. 于是他翻开 mdn 文档:
HTMLCanvasElement: toBlob() method - Web APIs | MDN (mozilla.org)
代码语言:javascript复制
function copyDivToImage() {
const element = document.getElementById("target");
html2canvas(element).then(canvas => {
canvas.toBlob(
(blob) => {
// 复制文件到剪贴板
},
"image/jpeg", // 文件的格式
1 // 图像压缩质量 0-1
);
});
}
复制二进制图像到剪贴板
这一步小王已经先前看过 MDN 文档了, ClipboardItem - Web APIs | MDN (mozilla.org) 可以直接调用浏览器的 navigator api :
代码语言:javascript复制
function copyDivToImage() {
const element = document.getElementById("target");
html2canvas(element).then(canvas => {
canvas.toBlob(
(blob) => {
// 复制文件到剪贴板
try {
await navigator.clipboard.write([
// eslint-disable-next-line no-undef
new ClipboardItem({
[blob.type]: blob
})
]);
console.log("图像已成功复制到剪��板");
} catch (err) {
console.error("无法复制图像到剪贴板", err);
}
},
"image/jpeg", // 文件的格式
1 // 图像压缩质量 0-1
);
});
}
小王遇到挫折
所有代码已经就绪, 小王随即启动项目, 运行他刚刚编写好的完美的代码. 不出所料, 他遇到了挫折:
小王看到这个报错, 完全没有头绪, 幸好有多年的开发经验, 他遇到这种问题的时候并没有慌张, 内心想, “第一次跑通常这样!”. 随即他打开百度搜索, 有一个回答引起了小王的注意:
原来, 小王是在 http 环境调试的, 他修改了代理的配置, 换成了 https 环境下调试本地代码.
然而让小王没有想到的是, 程序还是没有如期运行, 小王遇到了第二个挫折:
小王崩溃了 “这是什么鬼. 明明都是按照API文档写的!”
原来, 浏览器剪贴板对 jpeg的支持不大好, 于是小王把 canvas.toBlob()
的参数改成了 "image/png”.
他再次运行代码, 他成功了: