摘要:的出現就是為了解決帶來的問題。對于,它是其中這兩個屬性不管是哪種觀察方式都會有返回值,其他屬性返回值與觀察方式有關,比如只有當或者為時才有返回值,只有改變屬性時,才有返回值等。
MutationObserver翻譯過來就是變動觀察器,字面上就可以理解這是用來觀察Node(節點)變化的。MutationObserver是在DOM4規范中定義的,它的前身是MutationEvent事件,該事件最初在DOM2事件規范中介紹,到來了DOM3事件規范中正式定義,但是由于該事件存在兼容性以及性能上的問題被棄用。
MutationEvent雖然MutationEvent已經被棄用,但是我們還是需要了解它,可能你會為了瀏覽器兼容性的問題而遇到它(萬惡的瀏覽器兼容性)。
MutationEvent總共有7種事件:DOMNodeInserted、DOMNodeRemoved、DOMSubtreeModified、DOMAttrModified、
DOMCharacterDataModified、DOMNodeInsertedIntoDocument和DOMNodeRemovedFromDocument。
MutationEvent的兼容性:
MutationEvent在IE瀏覽器中最低支持到IE9
在webkit內核的瀏覽器中,不支持DOMAttrModified事件
IE,Edge以及Firefox瀏覽器下不支持DOMNodeInsertedIntoDocument和DOMNodeRemovedFromDocument事件
MutationEvent中的所有事件都被設計成無法取消,如果可以取消MutationEvent事件則會導致現有的DOM接口無法對文檔進行改變,比如appendChild,remove等添加和刪除節點的DOM操作。
MutationEvent中最令人詬病的就是性能以及安全性的問題,比如下面這個例子:
document.addEventListener("DOMNodeInserted", function() { var newEl = document.createElement("div"); document.body.appendChild(newEl); });
document下的所有DOM添加操作都會觸發DOMNodeInserted方法,這時就會出現循環調用DOMNodeInserted方法,導致瀏覽器崩潰。還有就是MutationEvent是事件機制,因此會有一般事件都存在的捕獲和冒泡階段,此時如果在捕獲和冒泡階段又對DOM進行了操作會拖慢瀏覽器的運行。
另一點就是MutationEvent事件機制是同步的,也就是說每次DOM修改就會觸發,修改幾次就觸發幾次,嚴重降低瀏覽器的運行,嚴重時甚至導致線程崩潰
var i=0; block.addEventListener("DOMNodeInserted", function(e) { i++ }); block.appendChild(docuemnt.createTextNode("1")); console.log(i) //1 block.appendChild(docuemnt.createTextNode("2")); console.log(i) //2 block.appendChild(docuemnt.createTextNode("3")); console.log(i) //3
再看個例子:
Text
block.addEventListener("DOMNodeInserted", function(e) { console.log("1"); //1 }); span.appendChild(docuemnt.createTextNode("other Text"));
span元素中添加節點會觸發block中的DOMNodeInserted事件,可是你只想觀察block的變化,不想觀察block中子節點的變化,這時你不得不在DOMNodeInserted事件中進行過濾,把對span的操作忽略掉,這無疑增加了操作的復雜性。
MutationObserverMutationObserver的出現就是為了解決MutationEvent帶來的問題。
先看一下MutationObserver的瀏覽器兼容性:
我們可以看到MutationObserver在IE中最低要就是IE11,如果你的網站不需要支持IE或者只支持到IE11,那么你可以放心的使用MutationObserver,否則你可能需要用到上面提到的MutationEvent事件,當然如果你的網站還要支持IE8及以下版本,那么你只能和Mutation說拜拜了。
MutationObserver是一個構造器,接受一個callback參數,用來處理節點變化的回調函數,返回兩個參數,mutations:節點變化記錄列表(sequence
var observe = new MutationObserver(function(mutations,observer){ })
MutationObserver對象有三個方法,分別如下:
observe:設置觀察目標,接受兩個參數,target:觀察目標,options:通過對象成員來設置觀察選項
disconnect:阻止觀察者觀察任何改變
takeRecords:清空記錄隊列并返回里面的內容
關于observe方法中options參數有已下幾個選項:
childList:設置true,表示觀察目標子節點的變化,比如添加或者刪除目標子節點,不包括修改子節點以及子節點后代的變化
attributes:設置true,表示觀察目標屬性的改變
characterData:設置true,表示觀察目標數據的改變
subtree:設置為true,目標以及目標的后代改變都會觀察
attributeOldValue:如果屬性為true或者省略,則相當于設置為true,表示需要記錄改變前的目標屬性值,設置了attributeOldValue可以省略attributes設置
characterDataOldValue:如果characterData為true或省略,則相當于設置為true,表示需要記錄改變之前的目標數據,設置了characterDataOldValue可以省略characterData設置
attributeFilter:如果不是所有的屬性改變都需要被觀察,并且attributes設置為true或者被忽略,那么設置一個需要觀察的屬性本地名稱(不需要命名空間)的列表
下表描述了MutationObserver選項與MutationEvent名稱之間的對應關系:
MutationEvent | MutationObserver options |
---|---|
DOMNodeInserted | { childList: true, subtree: true } |
DOMNodeRemoved | { childList: true, subtree: true } |
DOMSubtreeModified | { childList: true, subtree: true } |
DOMAttrModified | { attributes: true, subtree: true } |
DOMCharacterDataModified | { characterData: true, subtree: true } |
從上表我們也可以看出相比與MutationEvent而言MutationObserver極大地增加了靈活性,可以設置各種各樣的選項來滿足程序員對目標的觀察。
我們簡單看幾個例子:
target的第一個子節點target的后代
1.callback的回調次數
var target=document.getElementById("target"); var i=0 var observe=new MutationObserver(function (mutations,observe) { i++ }); observe.observe(target,{ childList: true}); target.appendChild(docuemnt.createTextNode("1")); target.appendChild(docuemnt.createTextNode("2")); target.appendChild(docuemnt.createTextNode("3")); console.log(i) //1
MutationObserver的callback回調函數是異步的,只有在全部DOM操作完成之后才會調用callback。
2.當只設置{ childList: true}時,表示觀察目標子節點的變化
var observe=new MutationObserver(function (mutations,observe) { debugger; console.log(mutations); //observe.discount(); }); observe.observe(target,{ childList: true}); target.appendChild(document.createTextNode("新增Text節點")); //增加節點,觀察到變化 target.childNodes[0].remove(); //刪除節點,可以觀察到 target.childNodes[0].textContent="改變子節點的后代"; //不會觀察到
如果想要觀察到子節點以及后代的變化需設置{childList: true, subtree: true}
attributes選項用來觀察目標屬性的變化,用法類似與childList,目標屬性的刪除添加以及修改都會被觀察到。
3.我們需要注意的是characterData這個選項,它是用來觀察CharacterData類型的節點的,只有在改變節點數據時才會觀察到,如果你刪除或者增加節點都不會進行觀察,還有如果對不是CharacterData類型的節點的改變不會觀察到,比如:
observe.observe(target,{ characterData: true, subtree: true}); target.childNodes[0].textContent="改變Text節點"; //觀察到 target.childNodes[1].textContent="改變p元素內容"; //不會觀察到 target.appendChild(document.createTextNode("新增Text節點")); //不會觀察到 target.childNodes[0].remove(); //刪除TEXT節點也不會觀察到
我們只需要記住只有對CharacterData類型的節點的數據改變才會被characterData為true的選項所觀察到。
4.最后關注一個特別有用的選項attributeFilter,這個選項主要是用來篩選要觀察的屬性,比如你只想觀察目標style屬性的變化,這時可以如下設置:
observe.observe(target,{ attributeFilter: ["style"], subtree: true}); target.style="color:red"; //可以觀察到 target.removeAttribute("name"); //刪除name屬性,無法觀察到
disconnect方法是用來阻止觀察的,當你不再想觀察目標節點的變化時可以調用observe.disconnect()方法來取消觀察。
takeRecords方法是用來取出記錄隊列中的記錄。它的一個作用是,比如你對一個節點的操作你不想馬上就做出反應,過段時間在顯示改變了節點的內容。
var observe=new MutationObserver(function(){}); observe.observe(target,{ childList: true}); target.appendChild(document.createTextNode("新增Text節點")); var record = observe.takeRecords(); //此時record保存了改變記錄列表 //當調用takeRecords方法時,記錄隊列被清空因此不會觸發MutationObserver中的callback回調方法。 target.appendChild(document.createElement("span")); observe.disconnect(); //停止對target的觀察。 //MutationObserver中的回調函數只有一個記錄,只記錄了新增span元素 //之后可以對record進行操作 //...
MutationRecord
變動記錄中的屬性如下:
type:如果是屬性變化,返回"attributes",如果是一個CharacterData節點(Text節點、Comment節點)變化,返回"characterData",節點樹變化返回"childList"
target:返回影響改變的節點
addedNodes:返回添加的節點列表
removedNodes:返回刪除的節點列表
previousSibling:返回分別添加或刪除的節點的上一個兄弟節點,否則返回null
nextSibling:返回分別添加或刪除的節點的下一個兄弟節點,否則返回null
attributeName:返回已更改屬性的本地名稱,否則返回null
attributeNamespace:返回已更改屬性的名稱空間,否則返回null
oldValue:返回值取決于type。對于"attributes",它是更改之前的屬性的值。對于"characterData",它是改變之前節點的數據。對于"childList",它是null
其中 type、target這兩個屬性不管是哪種觀察方式都會有返回值,其他屬性返回值與觀察方式有關,比如只有當attributeOldValue或者characterDataOldValue為true時oldValue才有返回值,只有改變屬性時,attributeName才有返回值等。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90787.html
摘要:后來尤雨溪了解到是將回調放入的隊列。而且瀏覽器內部為了更快的響應用戶,內部可能是有多個的而的的優先級可能更高,因此對于尤雨溪采用的,甚至可能已經多次執行了的,都沒有執行的,也就導致了我們更新操 原發于我的博客。 前一篇文章已經詳細記述了Vue的核心執行過程。相當于已經搞定了主線劇情。后續的文章都會對其中沒有介紹的細節進行展開。 現在我們就來講講其他支線任務:nextTick和micro...
摘要:該區域代表可以被所控制的畫布。那么現在第二個問題,識別該文檔,這或許不是大部分用戶的需求,但小部分用戶并不意味著人數少。因此一個基于的請求于標準內提出。 前言 作為程序員,技術的落實與鞏固是必要的,因此想到寫個系列,名為 why what or how 每篇文章試圖解釋清楚一個問題。 這次的 why what or how 主題:現在幾乎所有人都知道了 HTML5 ,那么 H5 到底相...
摘要:倡導開發者盡量不直接操作,但有的時候由于各種需求讓開發者不得不這樣做,于是的實現就是讓開發者在修改數據后,能夠在數據更新到后才執行對應的函數,從而獲取最新的數據。 Vue 倡導開發者盡量不直接操作 DOM,但有的時候由于各種需求讓開發者不得不這樣做,于是 nextTick 的實現就是讓開發者在修改數據后,能夠在數據更新到 DOM 后才執行對應的函數,從而獲取最新的 DON 數據。 原文...
閱讀 2492·2021-09-28 09:36
閱讀 1486·2021-09-22 15:33
閱讀 3636·2019-08-30 15:44
閱讀 1743·2019-08-29 13:14
閱讀 3132·2019-08-29 11:17
閱讀 1441·2019-08-29 11:03
閱讀 2905·2019-08-26 17:10
閱讀 681·2019-08-26 12:13