HTML2Canvas 截图的原理
目的:一个canvas元素,上面有绘制一系列的HTML节点
局限:canvas中没法添加具体的Html节点,它只是一张画布
通过canvas.getContext('2d')可以拿到canvas提供的2D渲染上下文,然后在里面绘制形状,文本,图象和其他对象。
文档地址:canvas
- 矩形-fillRect()
- 文本-fillText()
- 图象-drawImage()
等等...
SVG来拯救我们
可缩放矢量图(Scalable Vector Graphics, SVG),是一种可用于描述二维的矢量图,基于XML的标记语言。
SVG中有一个神奇的元素称之为foreignObject
- 文档地址foreignObject
- SVG中的
foreignObject
元素允许包含来自不同的 XML 命名空间的元素。在浏览器的上下文中,很可能是 XHTML / HTML。 - 注:ie不支持
解题思路:
- 创建一个 canvas元素
- 创建svg文件,使用 Blob构造函数
- 将svg中的值填充 foreignObject,然后填充想要
- 复制节点的 HTML
- 创建 image标签,将image.src = URL.crateObjectURL(svg)
- 在image完成读取以后,调用canvas的drawImage方法,将图片绘制到画布上
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="canvas-image"></canvas>
<div class="author" id="author" style="color: red;" >
这是模仿html2canvas使用的
</div>
<button>点击一下</button>
</body>
<script>
const drawCanvas = () => {
// canvas-image元素
const canvas = document.getElementById('canvas-image')
canvas.width = 400;
canvas.height = 400;
// 需要获取截图的内容
const element = document.getElementById('author')
const data =
"<svg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'>" +
"<foreignObject width='100%' height='100%'>" +
"<div xmlns='http://www.w3.org/1999/xhtml'>" +
element.innerHTML +
"</div>" +
"</foreignObject>" +
"</svg>"
// 创建svg文件
const svg = new Blob([data], { type: "image/svg+xml;charset=utf-8"})
// 创建一个image元素
const url = URL.createObjectURL(svg)
const image = new Image()
image.src = url;
image.addEventListener('load', () => {
const ctx = canvas.getContext('2d')
if(ctx) {
ctx.drawImage(image, 0, 0)
}
})
}
const btn = document.querySelector('button')
btn.addEventListener('click', drawCanvas)
</script>
</html>
样式没起作用,原因是我们只添加的html,并没有添加样式,如果要做到一样,需要把样式也添加到svg中去,这就是htmlCanvas简单的原理。
内部的原理主要是根据要截图元素的节点进行遍历,根据类型进行复制,添加样式,另外就是对于不支持foreignObject
,做兼容性处理。