在工作时,需要实现一个功能:把一个HTML网页的转换为图像。我想到的第一个想法是使用第三方库,但像
dom-to-image
或使用
Chrome Headless
,如
Puppeteer
。那如何使用
纯Javascript
解决这种需求呢?
让我们尝试在不使用任何库的情况下实现这一点。
使用Canvas将HTML网页转换为图像
由于安全原因,我们不能直接将HTML绘制到Canvas中。我们将采用另一种更安全的方法。
- 创建包含渲染内容的SVG图像
<svgxmlns="http://www.w3.org/2000/svg"width="200"height="200"></svg>
- 在SVG中插入一个
<foreignObject>
元素,它将包含HTML
<svgxmlns="http://www.w3.org/2000/svg"width="200"height="200"><foreignObjectwidth="100%"height="100%"></foreignObject></svg>
- 在
<foreignObject>
节点内添加XHTML内容
<svgxmlns="http://www.w3.org/2000/svg"width="200"height="200"><foreignObjectwidth="100%"height="100%"><divxmlns="http://www.w3.org/1999/xhtml">.
<style>em{color:red;}</style>
Hey there...
</div></foreignObject></svg>
- 创建 img 对象,并将 img 的
src
属性设置为该图像的data url
:
const tempImg = document.createElement('img')
tempImg.src ='data:image/svg+xml,'+encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml">Hey there...</div></foreignObject></svg>')
- 将此图像绘制到画布上,并设置画布为img 对象的
src
属性值:
const newImg = document.createElement('img')
newImg.src ='data:image/svg+xml,'+encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml">Hey there...</div></foreignObject></svg>')// 对图像添加事件监听
newImg.addEventListener('load', onNewImageLoad)// 将图像绘制到画布并设置img.srcfunctiononNewImageLoad(e){
ctx.drawImage(e.target,0,0)
targetImg.src = canvas.toDataURL()}
完整代码
<html><head><metacharset="UTF-8"/><style>body{display: flex;flex-flow: column wrap;align-items: center;justify-content: flex-start;background-image:linear-gradient(0, rgb(169, 144, 177), rgb(205, 169, 223));}h1{margin-top: 5vh;margin-bottom: 1vh;color: white;}p{margin: 0;color: white;}</style></head><body><h1>Convert HTML into Image!<h1/><script>const{ body }= document;const canvas = document.createElement("canvas");const ctx = canvas.getContext("2d");
canvas.width = canvas.height =100;const newImg = document.createElement("img");
newImg.addEventListener("load", onNewImageLoad);
newImg.src ="data:image/svg+xml,"+encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml"> Hey there...</div></foreignObject></svg>');const targetImg = document.createElement("img");
body.appendChild(targetImg);functiononNewImageLoad(e){
ctx.drawImage(e.target,0,0);
targetImg.src = canvas.toDataURL();}</script></body></html>
为什么使用SVG和Canvas是安全的?
SVG图像的实现有很大的限制,因为我们不允许
SVG
图像加载外部资源,即使是出现在同一个域上的资源。不允许在SVG图像中编写脚本,无法从其他脚本访问SVG图像的
DOM
, SVG图像中的
DOM
元素不能接收输入事件。因此,无法将特权信息加载到表单控件中(例如
<input type="file">
中的完整路径)并呈现它。
从安全性的角度来看,脚本不能直接接触渲染到画布的DOM节点,这一限制非常重要。
版权归原作者 前端修罗场 所有, 如有侵权,请联系我们删除。