面试官:请用纯 JS 实现,将 HTML 网页转换为图像

Posted 前端修罗场

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试官:请用纯 JS 实现,将 HTML 网页转换为图像相关的知识,希望对你有一定的参考价值。

在工作时,需要实现一个功能:把一个html网页的转换为图像。我想到的第一个想法是使用第三方库,但像dom-to-image或使用Chrome Headless,如Puppeteer。那如何使用javascript解决这种需求呢?

让我们尝试在不使用任何库的情况下实现这一点。

使用Canvas将HTML网页转换为图像

由于安全原因,我们不能直接将HTML绘制到Canvas中。我们将采用另一种更安全的方法。

  1. 创建包含渲染内容的SVG图像
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
</svg>
  1. 在SVG中插入一个<foreignObject>元素,它将包含HTML
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
    <foreignObject width="100%" height="100%">
    </foreignObject>
</svg>
  1. <foreignObject>节点内添加XHTML内容
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
    <foreignObject width="100%" height="100%">
        <div xmlns="http://www.w3.org/1999/xhtml">. 
          <style>emcolor:red;</style>
             Hey there...
        </div>
    </foreignObject>
</svg>
  1. 创建 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>')
  1. 将此图像绘制到画布上,并设置画布为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.src
function onNewImageLoad(e)
  ctx.drawImage(e.target, 0, 0)
  targetImg.src = canvas.toDataURL()

完整代码

<html>
<head>
    <meta charset="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);

        function onNewImageLoad(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节点,这一限制非常重要。

以上是关于面试官:请用纯 JS 实现,将 HTML 网页转换为图像的主要内容,如果未能解决你的问题,请参考以下文章

字节跳动面试官:请用JS实现Ajax并发请求控制

面试字节跳动:请用JS实现Ajax并发请求控制

用纯js就可以写一个网页!为啥还要用html和css,为啥不把html及css舍去??有这发展

js中平级数组和树形结构数据相互转换

面试官:请用通俗易懂的方式谈谈你对Spring的理解

用纯js在网页中渲染一个列表,列表中的数据用js定义一个数组,存储在数组中,至少要有两个字段