使用JavaScript怎么实现网页截的图

  

今天就跟大家聊聊有关使用JavaScript怎么实现网页截图,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

Canvas 实现

如何将dom转换成canvas图片?自然是要一点点画到canvas里,想想都是件麻烦事。通过分析github的知名截图库 niklasvh/html2canvas (7k+ star)的源码,梳理了其大致的思路:

  • 递归取出目标模版的所有DOM节点,填充到一个rederList,并附加是否为顶层元素/包含内容的容器 等信息

  • 通过z-index postion float等css属性和元素的层级信息将rederList排序,计算出一个canvas的renderQueue

  • 遍历renderQueue,将css样式转为setFillStyle可识别的参数,依据nodeType调用相对应canvas方法,如文本则调用fillText,图片drawImage,设置背景色的div调用fillRect等

  • 将画好的canvas填充进页面

无论是排序优先级的计算还是从css到canvas的转换,毫无疑问都是些巨麻烦的事,尤其是放在真实的业务场景里,DOM模版中往往会包含复杂的样式与排版,html2canvas 足足用了20多个js来实现这层转换,复杂成度可见一斑。索性,我们不需要再重新造一遍轮子。

使用canvas转化的话灵活性较高,环境依赖上也只需要确保浏览器支持canvas就可以了,但它有个显著的缺点:慢。原因自然是因为大量的计算与递归调用,这是无可避免的。不过html2canvas代码中大量使用了Promise,所以html2canvas 支持异步操作。

限制:

  • 无法跨域跨域资源

  • 无法渲染iframe,flash等内容,但目前支持svg

值得一提的是,尽管html2canvas主页表示它还处于实验室环境,但自14年起便已经被Twitter 等用在了生产环境,所以虽然有诸多限制,稳定性应该还是保障的。

canvas如此复杂,那么有没有一种更简单的方法呢?

自然是有的,那便是SVG

SVG实现

首先,svg本来就是矢量图形;其次,svg是可以用xml描述的;再其次,用来描述svg的标签里有个 foreignObject标签,这个标签可以加载其它命名空间的xml(xhtml)文档。也就是说,如果使用svg的话,我们不再需要一点点的遍历,转换节点;不用再计算复杂的元素优先级,只需要一股脑的将要渲染的DOM扔进就好了,剩下的就交给浏览器去渲染。

让我们理一理思路:

  • 首先,我们要声明一个基础的svg模版,这个模版需要一些基础的描述信息,最重要的,它要有这对标签

  • 将要渲染的DOM模版模版嵌入foreignObject

  • 利用Blob构建svg图像

  • 取出URL,赋值给

  
  ,,,& lt; h2 ,祝辞Hello  World
  & lt;才能/div> 
//此代码仅在chrome测试下通过   function  html2Svg  (domStr), {,   ,,,,,//创建模版字符串   ,,,,var  svgXML=,,,,,”& lt; svg  xmlns=癶ttp://www.w3.org/2000/svg",宽度=?00“,身高=?00“比;   ,,,,,,,& lt; foreignObject 宽度=?00%“,身高=啊?00%;在$ {generateXML (html)} & lt;/foreignObject>   ,,,,,,& lt;/svg>   ,,,,,//利用Blob创建svg   ,,,,,var  svg =, new  Blob ([svgXML],,{类型:& # 39;图像/svg + xml # 39;})   ,,,,,//利用DOMURL.createObjectURL取出对象   ,,,,,var  url =, window.URL.createObjectURL (svg);   ,,,,,var  img =, new 图像()   ,,,,,img.src =, url   ,,,,,return  img   ,,,}//,由于“foreignObject”只能引用XML文档,//,所以我们需要对DOM进行格式化   function  generateXML  (domStr), {,   ,,,var  doc =, document.implementation.createHTMLDocument (& # 39; & # 39;);   ,,,,,doc.write (html);   ,,,,,doc.documentElement.setAttribute (& # 39; xmlns # 39;,, doc.documentElement.namespaceURI);   ,,,,,doc =, parseStyle (doc)   ,,,,,console.log (doc)   ,,,,,html =, (new  XMLSerializer) .serializeToString (doc) .replace (& # 39; & lt; ! DOCTYPE  html> & # 39;, & # 39; & # 39;);   ,,,,,return  html   }

可以看到按这个思路来实现非常简单,并且没有了复杂的计算和递归,渲染速度自然要优于前者。然而使用svg,需要考虑诸多的限制问题。一个最为严肃的问题在于:svg无法加载外部资源,也就是说,在svg里面,无论是还是或css中者的背景图,这些资源都是无法加载的。在使用帆布实现时,因为我们是一个节点一个节点去画,所以不存在资源引用的问题。但使用svg实现,相当于我们把文档交给svg再来来渲染一遍,这对于我们来说是其实是无法控制的黑盒操作,是受svg限制的

使用JavaScript怎么实现网页截的图