這是專門探索 JavaScript 及其所構建的組件的系列文章的第10篇。javascript
想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等着你!css
若是你錯過了前面的章節,能夠在這裏找到它們:前端
Web 應用程序在客戶端變得愈來愈重,緣由不少,例如須要更豐富的 UI 來容納更復雜的應用程序提供的內容,實時計算等等。複雜性的增長使得在 Web 應用程序生命週期的每一個給定時刻都很難知道 UI 的確切狀態。java
而當你在搭建某些框架或者庫的時候,甚至會更加困難,例如,前者須要根據 DOM 來做出反應並執行特定的動做。node
Mutation Observer API 用來監視 DOM 變更。DOM 的任何變更,好比節點的增減、屬性的變更、文本內容的變更,這個 API 均可以獲得通知。css3
概念上,它很接近事件,能夠理解爲 DOM 發生變更就會觸發 Mutation Observer 事件。可是,它與事件有一個本質不一樣:事件是同步觸發,也就是說,DOM 的變更馬上會觸發相應的事件;Mutation Observer 則是異步觸發,DOM 的變更並不會立刻觸發,而是要等到當前全部 DOM 操做都結束才觸發。git
這樣設計是爲了應付 DOM 變更頻繁的特色。舉例來講,若是文檔中連續插入1000個 <li>
元素,就會連續觸發1000個插入事件,執行每一個事件的回調函數,這極可能形成瀏覽器的卡頓;而 Mutation Observer 徹底不一樣,只在 1000
個段落都插入結束後纔會觸發,並且只觸發一次。github
Mutation Observer有如下特色:web
爲何要要監聽 DOM?編程
在不少狀況下,MutationObserver API 均可以派上用場。例如:
這些只是 MutationObserver 能夠提供幫助的幾個例子。
在應用程序中實現 MutationObserver 至關簡單。你須要經過傳入一個函數來建立一個 MutationObserver 實例,每當有變化發生,這個函數將會被調用。函數的第一個參數是變更數組,每一個變化都會提供它的類型和已經發生的變化的信息。
var mutationObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { console.log(mutation); }); });
這個被建立的對象有三個方法:
observe 方法用來啓動監聽,它接受兩個參數。
下面的片斷展現瞭如何開始啓動監聽(observe ):
// 開始偵聽頁面的根 HTML 元素中的更改。 mutationObserver.observe(document.documentElement, { attributes: true, characterData: true, childList: true, subtree: true, attributeOldValue: true, characterDataOldValue: true });
如今,假設 DOM 中有一些很是簡單的 div:
<div id="sample-div" class="test"> Simple div </div>
使用 JQuery 來移除這個 div 上的 class:
$("#sample-div").removeAttr("class");
正如咱們已經開始觀察到的,在調用 mutationObserver.observe(…)
以後,將在控制檯中看到相應 MutationRecord 的日誌:
這個是由移除 class
屬性致使的變化。
MutationRecord
對象包含了DOM的相關信息,有以下屬性:
type:觀察的變更類型(attribute、characterData或者childList)
target:發生變更的 DOM 節點
addedNodes:新增的 DOM 節點
removedNodes:刪除的 DOM 節點
previousSibling:前一個同級節點,若是沒有則返回 null
nextSibling:下一個同級節點,若是沒有則返回 null
attributeName:發生變更的屬性。若是設置了attributeFilter,則只返回預先指定的屬性。
oldValue:變更前的值。這個屬性只對 attribute 和 characterData 變更有效,若是發生 childList 變更,則返回 null
最後,爲了在任務完成後中止觀察 DOM,能夠執行如下操做:
mutationObserver.disconnect();
如今,MutationObserver
已經被普遍支持:
MutationObserver 在以前尚未的,那麼在 MutationObserver 還沒出現以前,開發者採用什麼方案呢?
這是幾個可用的其餘選項:
最簡單和最簡單的方法是輪詢。使用瀏覽器 setInterval
方法,能夠設置一個任務,按期檢查是否發生了任何更改。固然,這種方法會顯著下降web 應用程序/網站的性能。
在2000年,MutationEvents API 被引入。雖然頗有用,但在 DOM中 的每一次更改都會觸發改變事件,這一樣會致使性能問題。如今 MutationEvents API 已經被棄用,很快現代瀏覽器將徹底中止支持它。
另外一個有點奇怪的選擇是依賴 CSS 動畫。這聽起來可能有點使人困惑。基本上,咱們的想法是建立一個動畫,一旦元素被添加到 DOM 中,動畫就會被觸發。動畫開始的那一刻,animationstart
事件將被觸發:若是已經將事件處理程序附加到該事件,那麼你將確切地知道元素什麼時候被添加到 DOM 中。動畫的執行時間週期應該很小,用戶幾乎看不到它。
首先,須要一個父級元素,咱們在它的內部監聽節點的插入:
<div id=」container-element」></div>
爲了獲得節點插入的處理器,須要設置一系列的 keyframe 動畫,當節點插入的時候,動畫將會開始。
@keyframes nodeInserted { from { opacity: 0.99; } to { opacity: 1; } }
建立 keyfram
後,還須要把它放入你想監聽的元素上,注意應設置很小的 duration 值 —— 它們將會減弱動畫在瀏覽器上留下的痕跡。
#container-element * { animation-duration: 0.001s; animation-name: nodeInserted; }
這會將動畫添加到 container-element
的全部子節點。 動畫結束時,將觸發插入事件。
咱們須要一個 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。
原文:
https://blog.sessionstack.com...
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
你的點贊是我持續分享好東西的動力,歡迎點贊!