亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

淺析js實現(xiàn)網(wǎng)頁截圖的兩種方式

 更新時間:2019年11月01日 08:37:26   投稿:zx  
這篇文章主要介紹了淺析js實現(xiàn)網(wǎng)頁截圖的兩種方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

Web端的截圖(生成圖片)并不算是個高頻的需求,資料自然也不算多,查來查去,也不過Canvas 和 SVG兩種實現(xiàn)方案,原理大概相似,都非真正義上的截圖而是把DOM轉(zhuǎn)為圖片,然而實現(xiàn)方式卻截然不同。

Canvas 實現(xiàn)

如何將dom轉(zhuǎn)換成canvas圖片?自然是要一點點畫到canvas里,想想都是件麻煩事。通過分析github的知名截圖庫 niklasvh/html2canvas (7k+ star)的源碼,梳理了其大致的思路:

  • 遞歸取出目標模版的所有DOM節(jié)點,填充到一個rederList,并附加是否為頂層元素/包含內(nèi)容的容器 等信息
  • 通過z-index postion float等css屬性和元素的層級信息將rederList排序,計算出一個canvas的renderQueue
  • 遍歷renderQueue,將css樣式轉(zhuǎn)為setFillStyle可識別的參數(shù),依據(jù)nodeType調(diào)用相對應canvas方法,如文本則調(diào)用fillText,圖片drawImage,設置背景色的div調(diào)用fillRect等
  • 將畫好的canvas填充進頁面

無論是排序優(yōu)先級的計算還是從css到canvas的轉(zhuǎn)換,毫無疑問都是些巨麻煩的事,尤其是放在真實的業(yè)務場景里,DOM模版中往往會包含復雜的樣式與排版,html2canvas 足足用了20多個js來實現(xiàn)這層轉(zhuǎn)換,復雜成度可見一斑。索性,我們不需要再重新造一遍輪子。

使用canvas轉(zhuǎn)化的話靈活性較高,環(huán)境依賴上也只需要確保瀏覽器支持canvas就可以了,但它有個顯著的缺點:慢。原因自然是因為大量的計算與遞歸調(diào)用,這是無可避免的。不過html2canvas代碼中大量使用了Promise,所以html2canvas 支持異步操作。

限制:

  • 無法跨域跨域資源
  • 無法渲染iframe,flash等內(nèi)容,但目前支持svg

值得一提的是,盡管html2canvas主頁表示它還處于實驗室環(huán)境,但自14年起便已經(jīng)被Twitter 等用在了生產(chǎn)環(huán)境,所以雖然有諸多限制,穩(wěn)定性應該還是保障的。

canvas如此復雜,那么有沒有一種更簡單的方法呢?

自然是有的,那便是SVG

SVG實現(xiàn)

首先,svg本來就是矢量圖形;其次,svg是可以用xml描述的;再其次,用來描述svg的標簽里有個 foreignObject標簽,這個標簽可以加載其它命名空間的xml(xhtml)文檔。也就是說,如果使用svg的話,我們不再需要一點點的遍歷,轉(zhuǎn)換節(jié)點;不用再計算復雜的元素優(yōu)先級,只需要一股腦的將要渲染的DOM扔進<foreignObject></foreignObject>就好了,剩下的就交給瀏覽器去渲染。

讓我們理一理思路:

  • 首先,我們要聲明一個基礎的svg模版,這個模版需要一些基礎的描述信息,最重要的,它要有<foreignObject></foreignObject>這對標簽
  • 將要渲染的DOM模版模版嵌入foreignObject
  • 利用Blob構(gòu)建svg圖像
  • 取出URL,賦值給
  <div id='text'>
    <h1 style="background-color: #ccc;width: 200px;height: 200px;" >Hello World</h1>
  </div>
//此代碼僅在chrome測試下通過
function html2Svg (domStr) { 
      //創(chuàng)建模版字符串
      var svgXML=
      `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
        <foreignObject width="100%" height="100%">${generateXML(html)}</foreignObject>
       </svg>`
      //利用Blob創(chuàng)建svg
      var svg = new Blob([svgXML], {type: 'image/svg+xml'})
      //利用DOMURL.createObjectURL取出對象
      var url = window.URL.createObjectURL(svg);
      var img = new Image()
      img.src = url
      return img
    }

// 由于`foreignObject`只能引用XML文檔,
// 所以我們需要對DOM進行格式化
function generateXML (domStr) { 
    var doc = document.implementation.createHTMLDocument('');
      doc.write(html);
      doc.documentElement.setAttribute('xmlns', doc.documentElement.namespaceURI);
      doc = parseStyle(doc)
      console.log(doc)
      html = (new XMLSerializer).serializeToString(doc).replace('<!DOCTYPE html>','');
      return html
}

可以看到按這個思路來實現(xiàn)非常簡單,并且沒有了復雜的計算和遞歸,渲染速度自然要優(yōu)于前者。然而使用svg,需要考慮諸多的限制問題。一個最為嚴肅的問題在于:SVG無法加載外部資源,也就是說,在svg里面,無論是還是 或者css中的背景圖,這些資源都是無法加載的。在使用canvas實現(xiàn)時,因為我們是一個node一個node去畫,所以不存在資源引用的問題。但使用svg實現(xiàn),相當于我們把文檔交給SVG再來來渲染一遍,這對于我們來說是其實是無法控制的黑盒操作,是受SVG限制的

萬幸,一個昵稱為Christoph Burgmer的小哥寫了一個名為rasterizeHTML.js 的庫,通過一系列的hack技巧替我們繞過了許多限制。我知道你很好奇他是怎么做到的。 簡單來講,rasterizeHTML.js在我們的基礎實現(xiàn)上做了這些hack:

  • 將<img/>的url 轉(zhuǎn)為 dataURI
  • 將background-color從style中取出,修改url后重新插入樣式表
  • 將link的的樣式通過ajax down下來然后注入<style></sytle>
  • 詳見源碼...

當然, rasterizeHTML.js能幫我們做的也不過是處理資源引用問題和瀏覽器兼容問題,更多的SVG的限制是無法繞過的,該庫的文檔正式列出了足足一整頁的限制,讓人讀完后心中一涼。比如:

  • 跨域資源無法加載
  • 如lazyload等通過js加載的資源無法加載
  • 內(nèi)聯(lián)或js操作background-image無法加載
  • 詳見文檔

思考下rasterizeHTML.js的原理便可理解這些限制無法避免的原因: rasterizeHTML.js只能對已經(jīng)存在的靜態(tài)資源進行處理,而對js動態(tài)生成并不能實時處理。

目前rasterizeHTML.js已經(jīng)被用于知乎-意見反饋功能。

參考

源碼https://developer.mozilla.org/en-US/docs/Web/API/CanvasAPI/DrawingDOMobjectsintoacanvas

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 詳解js中的幾種常用設計模式

    詳解js中的幾種常用設計模式

    這篇文章主要介紹了js中的幾種設計模式,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-07-07
  • js控制div及網(wǎng)頁相關屬性的代碼

    js控制div及網(wǎng)頁相關屬性的代碼

    js控制div及相關屬性,對于需要控制頁面內(nèi)的元素的朋友可以參考下。
    2009-12-12
  • layer.open關閉父窗口 以及調(diào)用父頁面的方法

    layer.open關閉父窗口 以及調(diào)用父頁面的方法

    今天小編就為大家分享一篇layer.open關閉父窗口 以及調(diào)用父頁面的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • 移動端如何用下拉刷新的方式實現(xiàn)上拉加載

    移動端如何用下拉刷新的方式實現(xiàn)上拉加載

    這篇文章主要介紹了移動端如何用下拉刷新的方式實現(xiàn)上拉加載,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-12-12
  • 使用js在layui中實現(xiàn)上傳圖片壓縮

    使用js在layui中實現(xiàn)上傳圖片壓縮

    這篇文章主要介紹了使用js在layui中實現(xiàn)上傳圖片壓縮,layui 是一款采用自身模塊規(guī)范編寫的前端 UI 框架,js上傳圖片壓縮百度有很多方法,,需要的朋友可以參考下
    2019-06-06
  • JS在if中的強制類型轉(zhuǎn)換方式

    JS在if中的強制類型轉(zhuǎn)換方式

    大家都知道JS在很多情況下會進行強制類型轉(zhuǎn)換,最常見的方式有兩種,在文章均給大家提到,下面小編給大家?guī)砹薐S在if中的強制類型轉(zhuǎn)換,感興趣的朋友一起看看吧
    2018-07-07
  • JavaScript實現(xiàn)命名空間的多種方式

    JavaScript實現(xiàn)命名空間的多種方式

    隨著項目規(guī)模的不斷擴大,如何有效地組織和管理代碼成為一個重要的課題,命名空間是解決這一問題的有效手段之一,它可以幫助我們避免全局變量污染,減少變量名沖突的問題,從而提高代碼的可維護性和模塊化程度,本文介紹了JavaScript實現(xiàn)命名空間的多種方式
    2024-11-11
  • JavaScript實現(xiàn)帶音效的煙花特效

    JavaScript實現(xiàn)帶音效的煙花特效

    這篇文章主要為大家介紹了通過JavaScript實現(xiàn)的帶音效的煙花特效,文中的示例代碼簡潔易懂,對我們學習JavaScript有一定的幫助,感興趣的可以了解一下
    2021-12-12
  • javascript 對象比較實現(xiàn)代碼

    javascript 對象比較實現(xiàn)代碼

    js對象比較實現(xiàn)代碼。
    2009-04-04
  • JavaScript基于setTimeout實現(xiàn)計數(shù)的方法

    JavaScript基于setTimeout實現(xiàn)計數(shù)的方法

    這篇文章主要介紹了JavaScript基于setTimeout實現(xiàn)計數(shù)的方法,涉及javascript中setTimeout方法的使用技巧,需要的朋友可以參考下
    2015-05-05

最新評論