Web應用程序在客戶端愈來愈重要,緣由不少,好比須要更豐富的用戶界面來容納更復雜的應用程序必須提供的功能,實時計算等等。node
複雜性的增長使得在Web應用程序的生命週期中的每一個特定時刻都很難知道UI的確切狀態。web
若是你正在構建某種框架或僅僅是一個庫,這會變得更加困難,例如,它必須做出反應並執行某些依賴於DOM的操做。瀏覽器
MutationObserver是現代瀏覽器提供的Web API,用於檢測DOM中的變化。使用此API,能夠偵聽新添加或刪除的節點,屬性更改或文本節點文本內容的更改。網絡
你爲何想這麼作?框架
MutationObserver API在不少狀況下能夠很是方便地使用。例如:編輯器
這些只是MutationObserver如何提供幫助的幾個例子。函數
在你的應用中實現MutationObserver至關容易。您須要經過傳遞一個函數來建立一個MutationObserver實例,該函數在每次發生突變時都會被調用。函數的第一個參數是在一個批次中發生的全部改變的集合。每一個改變都提供有關其類型和已發生變化的信息。
MutationObserver API,您能夠在任何給定的位置知道進行了哪些更改,所以您能夠輕鬆地撤消它們。性能
var mutationObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { console.log(mutation); }); });
建立的對象有三個方法:優化
如下片斷顯示瞭如何開始觀察:動畫
// Starts listening for changes in the root HTML element of the page. mutationObserver.observe(document.documentElement, { attributes: true, characterData: true, childList: true, subtree: true, attributeOldValue: true, characterDataOldValue: true });
如今假設你有一些簡單的DIV在DOM中:
<div id="sample-div" class="test"> Simple div </div>
使用jQuery,你你能夠移除div的class屬性:
$("#sample-div").removeAttr("class");
正如咱們開始觀察的那樣,在調用mutationObserver.observe(...)以後,咱們將在相應的MutationRecord的控制檯中看到一個日誌:
這是由刪除class屬性引發的變異。
最後,爲了在完成後中止觀察DOM,能夠執行如下操做:
// Stops the MutationObserver from listening for changes. mutationObserver.disconnect();
現在,MutationObserver獲得了普遍的支持:
然而,MutationObserver並不老是可用的。那麼在MutationObserver出現以前開發者會採起什麼措施呢?
還有其餘幾個選項可用:
最簡單和最簡單的方式是經過輪詢。使用瀏覽器setInterval WebAPI,您能夠設置一個任務,按期檢查是否發生了任何更改。固然,這種方法會顯着下降網絡應用程序/網站的性能。
在2000年,引入了MutationEvents API。雖然有用,但DOM中的每一次更改都會觸發突變事件,這又會致使性能問題。如今,MutationEvents API已被棄用,很快,現代瀏覽器將再也不支持它。
這是MutationEvents的瀏覽器支持:
一個有點奇怪的選擇是依賴CSS動畫。這聽起來有點混亂。基本上,這個想法是建立一個動畫,一旦一個元素被添加到DOM就會觸發該動畫。動畫開始的那一刻,animationstart事件將被觸發:若是您已將事件處理程序附加到該事件,則您將確切知道元素什麼時候添加到DOM。 動畫的執行時間應該很小,以致於用戶幾乎看不到它。
首先,咱們須要一個父元素,在其中咱們想要聽節點插入:
<div id=」container-element」></div>
爲了得到節點插入的句柄,咱們須要設置一系列關鍵幀動畫,這些動畫將在插入節點時開始:
@keyframes nodeInserted { from { opacity: 0.99; } to { opacity: 1; } }
在建立關鍵幀後,須要將動畫應用到您想要的元素上。請注意,持續時間較短 - 他們正在放鬆瀏覽器中的動畫腳印:
#container-element * { animation-duration: 0.001s; animation-name: nodeInserted; }
這將動畫添加到容器元素的全部子節點。當動畫結束時,插入事件將觸發。
咱們須要一個JavaScript函數做爲事件監聽器。在該函數中,必須進行初始event.animationName檢查以確保它是咱們想要的動畫。
var insertionListener = function(event) { // Making sure that this is the animation we want. if (event.animationName === "nodeInserted") { console.log("Node has been inserted: " + event.target); } }
顯示是時候添加監聽器到父容器了:
document.addEventListener(「animationstart」, insertionListener, false); // standard + firefox document.addEventListener(「MSAnimationStart」, insertionListener, false); // IE document.addEventListener(「webkitAnimationStart」, insertionListener, false); // Chrome + Safari
CSS動畫的瀏覽器支持:
與上述解決方案相比,MutationObserver具備許多優勢。 從本質上講,它涵蓋了DOM中可能發生的每個變化,而且它在批處理中引起更改時更加優化。最重要的是,全部主要的現代瀏覽器都支持MutationObserver,以及一些使用MutationEvents的polyfill。