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方法,将图片绘制到画布上
<!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
,做兼容性处理。