MutationObserve的使用和應用
前言
最近接到一個項目需求,就是把另一個項目嵌入到當前項目中。要求很簡單,讓人看不出這是嵌入過來的。
本來覺得這也沒什麼,因爲以前也做過一次。
方案無非就是通過iframe
嵌入,通過postMessage
進行通信(ps
:兩個項目都是我們自己的,可以修改代碼)。
其他的一切都ok
,就有個一個問題困擾了。
我們當前的項目是一個典型的聖盃佈局,頭部和底部都要顯示內容。
而嵌入的頁面的高度是不固定的,如果固定iframe
的高度,就會出現有的頁面過短導致iframe
出現大片空白,有的頁面過長導致iframe
會出現滾動條,
所以,我需要解決的是如何隨時獲知嵌入頁面的高度。
第一種方案——輪詢
我發現只要是聽到“隨時”兩個字,肯定有一個解決方案是輪詢,但肯定馬上又否決了這個方案。
沒辦法,降低程序性能的我們不要。
第二種方案——MutationObserve
第二種方案,就要請出我們今天的主角了,MutationObserve
。
這是個少爲人知的API
,卻是被所有瀏覽器所支持(重點:ie11
支持,ie11
以下繞路,我們的項目只要支持ie11
)。
使用
使用MutationObserve
非常簡單。
首先,通過MutationObserve
構造函數,創建一個實例。
var observer = new MutationObserve(function (mutation) {
mutations.forEach(function(mutation) {
console.log(mutation);
});
})
構造函數的參數是一個回調函數,返會的參數是一個對象,屬性如下
type: 如果是屬性發生變化,則返回attributes.如果是一個CharacterData節點發生變化,則返回characterData,如果是目標節點的某個子節點發生了變化,則返回childList.
target: 返回此次變化影響到的節點,具體返回那種節點類型是根據type值的不同而不同的,如果type爲attributes,則返回發生變化的屬性節點所在的元素節點,如果type值爲characterData,則返回發生變化的這個characterData節點.如果type爲childList,則返回發生變化的子節點的父節點.
addedNodes: 返回被添加的節點
removedNodes: 返回被刪除的節點
previousSibling: 返回被添加或被刪除的節點的前一個兄弟節點
nextSibling: 返回被添加或被刪除的節點的後一個兄弟節點
attributeName: 返回變更屬性的本地名稱
oldValue: 根據type值的不同,返回的值也會不同.如果type爲attributes,則返回該屬性變化之前的屬性值.如果type爲characterData,則返回該節點變化之前的文本數據.如果type爲childList,則返回null
然後,通過實例的observe方法進行觀察目標dom
Observer.observe(targetNode, options)
// 代碼實例
var targetNode = document.body
var options = {
childList: true,
attributes: true,
subtree: true
}
Observer.observe(targetNode, options)
observe
方法接收連個參數
-
targetNode
就是你需要觀察的
DOM
對象 -
options
options
是一個MutationObserverInit
的對象,屬性如下childList: 設爲true以監視目標節點(如果subtree爲true,則包含子孫節點)添加或刪除新的子節點。默認值爲false。 subtree: 設爲true以擴展監視範圍到目標節點下的整個子樹的所有節點 attributes: 設爲true以觀察受監視元素的屬性值變更。默認值爲false。 attributeOldValue: 在attributes屬性已經設爲true的前提下,當監視節點的屬性改動時,將此屬性設爲true 將記錄任何有改動的屬性的上一個值。 attributeFilter: 要監視的特定屬性名稱的數組。如果未包含此屬性,則對所有屬性的更改都會觸發變動通知。無默認值。 characterData: 設爲true以監視指定目標節點或子節點樹中節點所包含的字符數據的變化。無默認值。(一種抽象接口,具體可以爲文本節點,註釋節點,以及處理指令節點)時,也要觀察該節點的文本內容是否發生變化 characterDataOldValue: 在characterData屬性已經設爲true的前提下,設爲true以在文本在受監視節點上發生更改時記錄節點文本的先前值
實例還有兩個方法
disconnect
終止在觀察者對象上設置的節點的變化監聽,直到重新調用observe
方法
takeRecords
在回調被觸發前返回最後一批更改,就是說當你調用了disconnect
方法,會返回最後一次的更改,而不直接終止了。
MutationsObserve
是異步的,同Promise
。
應用
回到最初的需求,如何隨時獲知ifame
嵌入的頁面的高度?
上代碼
var ele = document.documentElement
var oldHeight = null
var observer = new MutationObserve(function (mutation) {
var newHeight = ele.height
if (newHeight != oldHeight) {
oldHeight = newHeight
// 通過postMessage進行iframe之間的通信
window.top.postMessage({
type: 'IframeInnerHeight',
height: newHeight
}, '*')
}
})
var options = {
childList: true,
subtree: true,
attributes: true
}
observer.observe(ele, options)
當父級接收到頁面的高度就可重新設置Iframe
的高度,這樣兩個項目就完美的融合一起了。
思考
當我們瞭解了MutationObserve
的強大功能時,我們是否可以多想想,它還能做什麼?我們能依靠它來做什麼?
這裏推薦一篇文章,提供三個應用場景