Dom節點變更檢測並錄製的簡單實現

關鍵技術

MutationObserver

MutationObserver使用來監測某個範圍內DOM的變更,如節點的增減、屬性的變更,文本節點的變化等。至關於DOM的改變就會觸發MutationObserver這個事件,可是這個事件是異步觸發的,會把DOM的變更封裝成一個數組進行統一更新的,這點和react中的setState很是相像。css

構造函數

var observer = new MutationObserver(function (mutations, observer) {
  mutations.forEach(function(mutation) {
    console.log(mutation);
  });
})
複製代碼

在調用時,觀察者對象會傳給該函數兩個參數:html

  • MutationObserver接受一個callback參數,用來處理節點變化的回調函數,返回兩個參數,mutations和observer。react

  • mutations:節點變化記錄列表git

  • observer:MutationObserver的實例對象。github

方法

MutationObserver對象有三個方法,分別以下:web

  • observe:設置觀察目標,接受兩個參數,target:觀察目標,options:經過對象成員來設置觀察選項canvas

  • disconnect:阻止觀察者觀察任何改變數組

  • takeRecords:清空記錄隊列並返回裏面的內容promise

observe方法中經常使用的options參數有已下幾個選項:瀏覽器

  • childList:設置true,表示觀察目標子節點的變化,好比添加或者刪除目標子節點,不包括修改子節點以及子節點後代的變化

  • attributes:設置true,表示觀察目標屬性的改變

  • characterData:設置true,表示觀察目標數據的改變

  • subtree:設置爲true,目標以及目標的後代改變都會觀察

使用示例

如今有一個id爲target的節點

<div id='target' class='block'>

</div>
複製代碼

對該dom進行監聽並測試

var target=document.getElementById('target');
var i=0
var observe=new MutationObserver(function (mutations,observe) {
    i++  
});
observe.observe(target,{ childList: true});
target.appendChild(docuemnt. createElement ('span')); 
target.appendChild(docuemnt. createElement ('div'));
console.log(i)  //1
複製代碼

錄製回放操做的簡單實現

初始思路:使用MutationObserver監聽整個頁面,每當有頁面變更,則將頁面的html轉換成圖片進行隊列存儲,回放用戶操做即不停從隊列中取出元素展現

Html轉Canvas

這裏咱們直接使用html2canvas這個第三方庫官方地址,基於html2canvas.js可將一個元素渲染爲canvas,只須要簡單的調用html2canvas(element[, options]),下列html2canvas方法會返回一個包含有canvas元素的promise:

html2canvas(document.body).then(function(canvas) {
    document.body.appendChild(canvas);
});
複製代碼

Canvas轉Img

上一步生成的canvas即爲包含目標元素的canvas元素對象。實現保存圖片的目標只須要將canvas轉image便可。經過canvas的toDataURL方法將canvas輸出爲data: URI類型的圖片base64地址,再將該圖片地址賦值給元素的src屬性便可。

示例

<canvas id="canvas" width="5" height="5">
</canvas>
複製代碼

獲取該圖片,直接能夠用toDataURL轉成圖片,默認爲 PNG 格式

var canvas = document.getElementById("canvas");
var dataURL = canvas.toDataURL();
console.log(dataURL);
// "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNby...
複製代碼

最後,經過定時器將img不停的插入到img標籤的src中,實現回放的效果。

Canvas在高分屏中一些缺陷的解決方法

Canvas在高分屏中繪製圖片會有模糊的效果,其實不僅是繪製圖片時會出現模糊的問題,高清屏的設備中任何繪製在 canvas 中的圖形(包括文字)都會出現模糊的問題。

這是由於HIDPI的屏幕上的像素其實是邏輯像素,咱們若是當成正常的像素(css中設置的像素)使用它,如咱們在css中設置100px時,在例如iphone4S(devicePixelRatio爲2)上,實際渲染的是200px的物理像素。因此當咱們向這種高分辨率的屏幕添加img的時候,咱們的圖像及其餘一些圖形文字都會受到devicePixelRatio的影響會變得模糊。
解決方法很簡單,就是將 canvas 的高和寬分別乘以 devicePixelRatio將其放大,而後又用 CSS 將高和寬限制成初始的大小。

Demo效果

這裏爲了簡化操做,作捉了兩個按鈕作添加和刪除元素,實際狀況中,不只須要對dom節點的操做進行監聽,例如用戶的點擊、停留、軌跡等行爲數據都須要進行採集分析。

方案優化

在Web中, 圖形圖像的操做以及存儲會消耗大量的性能, 經過使用html快照來替代圖像快照能夠大幅的提升性能以達到生成可用狀態,可是須要作不少的處理,當咱們存儲的是html的快照鏈時,想要在客戶端進行用戶操做回放,咱們須要構建沙盒環境對html從新進行渲染,有一些工具如parse5能夠進行html的序列化和解析操做,「視頻回放」其實就是 HTML DOM 的變化增量及快照。
在html的解析過程當中須要要對dom快照進行一點的處理,如:

  • 禁止表單提交

  • 禁止跳轉、window.open等操做

  • js腳本的執行(由於咱們只是須要dom結構的變化)等

  • 瀏覽器端存必定量的增量快照後再一塊兒發送到服務端,減小網絡開銷;也包括屢次增量以後再進行一次全量,對齊真實狀態。

  • 數據脫敏

  • 經過 DocumentFragment 提升平臺回放效率。

能夠參考開源方案RRWeb:github.com/rrweb-io/rr…

基於上述技術還能夠實現哪些小功能(思路)

網頁中長按保存截圖(針對移動端)

捕捉長按的操做,而後經過咱們上面的,實現轉canvas轉img的操做

網頁中實現撤銷操做

記錄用戶的每次的dom操做放到一個棧中,每次用戶觸發撤銷操的時候從棧中取出一個元素,能夠還原上次的dom結構,從而實現了撤銷的操做

有關動態顯示的部分

例如根據文本內容是否超出來動態控制是否顯示Tooltip,文本末尾顯示其餘內容等

相關文章
相關標籤/搜索