成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

MutationObserver 監(jiān)聽 DOM 樹變化

psychola / 1051人閱讀

摘要:是用于代替作為觀察樹結(jié)構(gòu)發(fā)生變化時(shí),做出相應(yīng)處理的。觸發(fā)回調(diào)前返回最新的批量變化。發(fā)生相應(yīng)變動(dòng)時(shí),不再調(diào)用回調(diào)函數(shù)。其中數(shù)組也會(huì)作為,觀察者初始化時(shí)的回調(diào)函數(shù)的第一個(gè)參數(shù)。如果為,則表示需要記錄變動(dòng)前的屬性值。

MutationObserver 是用于代替 MutationEvents 作為觀察 DOM 樹結(jié)構(gòu)發(fā)生變化時(shí),做出相應(yīng)處理的 API 。為什么要使用 MutationObserver 去代替 MutationEvents 呢,我們先了解一下 MutationEvents

MutationEvents

它簡(jiǎn)單的用法如下:

document.getElementById("list").addEventListener(
  "DOMSubtreeModified",
  () => {
    console.log("列表中子元素被修改")
  },
  false
)
// Mutation 事件列表
DOMAttrModified // 監(jiān)聽元素的修改
DOMAttributeNameChanged
DOMCharacterDataModified
DOMElementNameChanged
DOMNodeInserted // 監(jiān)聽新增
DOMNodeRemoved // 監(jiān)聽刪除
DOMNodeInsertedIntoDocument
DOMSubtreeModified // 監(jiān)聽子元素的修改

其中 DOMNodeRemovedDOMNodeInsertedDOMSubtreeModified分別用于監(jiān)聽元素子項(xiàng)的刪除,新增,修改(包括刪除和新增),DOMAttrModified 是監(jiān)聽元素屬性的修改,并且能夠提供具體的修改動(dòng)作。

Mutation Events 遇到的問題

IE9 不支持 MutationEvents。Webkit 內(nèi)核不支持 DOMAttrModified 特性,DOMElementNameChangedDOMAttributeNameChanged 在 Firefox 上不被支持。

性能問題 1. MutationEvents 是同步執(zhí)行的,它的每次調(diào)用,都需要從事件隊(duì)列中取出事件,執(zhí)行,然后事件隊(duì)列中移除,期間需要移動(dòng)隊(duì)列元素。如果事件觸發(fā)的較為頻繁的話,每一次都需要執(zhí)行上面的這些步驟,那么瀏覽器會(huì)被拖慢。 2. MutationEvents 本身是事件,所以捕獲是采用的是事件冒泡的形式,如果冒泡捕獲期間又觸發(fā)了其他的 MutationEvents 的話,很有可能就會(huì)導(dǎo)致阻塞 Javascript 線程,甚至導(dǎo)致瀏覽器崩潰。

Mutation Observer

MutationObserver 是在 DOM4 中定義的,用于替代 MutationEvents 的新 API,它的不同于 events 的是,所有監(jiān)聽操作以及相應(yīng)處理都是在其他腳本執(zhí)行完成之后異步執(zhí)行的,并且是所以變動(dòng)觸發(fā)之后,將變得記錄在數(shù)組中,統(tǒng)一進(jìn)行回調(diào)的,也就是說,當(dāng)你使用 observer 監(jiān)聽多個(gè) DOM 變化時(shí),并且這若干個(gè) DOM 發(fā)生了變化,那么 observer 會(huì)將變化記錄到變化數(shù)組中,等待一起都結(jié)束了,然后一次性的從變化數(shù)組中執(zhí)行其對(duì)應(yīng)的回調(diào)函數(shù)。

特點(diǎn)

所有腳本任務(wù)完成后,才會(huì)運(yùn)行,即采用異步方式

DOM 變動(dòng)記錄封裝成一個(gè)數(shù)組進(jìn)行處理,而不是一條條地個(gè)別處理 DOM 變動(dòng)。

可以觀察發(fā)生在 DOM 節(jié)點(diǎn)的所有變動(dòng),也可以觀察某一類變動(dòng)

目前,F(xiàn)irefox(14+)、Chrome(26+)、Opera(15+)、IE(11+) 和 Safari(6.1+) 支持這個(gè) API。 Safari 6.0 和 Chrome 18-25 使用這個(gè) API 的時(shí)候,需要加上 WebKit 前綴(WebKitMutationObserver)??梢允褂孟旅娴谋磉_(dá)式檢查瀏覽器是否支持這個(gè) API。

const MutationObserver =
  window.MutationObserver ||
  window.WebKitMutationObserver ||
  window.MozMutationObserver
// 監(jiān)測(cè)瀏覽器是否支持
const observeMutationSupport = !!MutationObserver
如何使用 MutationObserver

在應(yīng)用中集成 MutationObserver 是相當(dāng)簡(jiǎn)單的。通過往構(gòu)造函數(shù) MutationObserver 中傳入一個(gè)函數(shù)作為參數(shù)來初始化一個(gè) MutationObserver 實(shí)例,該函數(shù)會(huì)在每次發(fā)生 DOM 發(fā)生變化的時(shí)候調(diào)用。MutationObserver 的函數(shù)的第一個(gè)參數(shù)即為單個(gè)批處理中的 DOM 變化集。每個(gè)變化包含了變化的類型和所發(fā)生的更改。

const mutationObserver = new MutationObserver(mutations => {
  mutations.forEach(mutation => {
    console.log(mutation)
  })
})

創(chuàng)建的實(shí)例對(duì)象擁有三個(gè)方法:

observe -開始進(jìn)行監(jiān)聽。接收兩個(gè)參數(shù)-要觀察的 DOM 節(jié)點(diǎn)以及一個(gè)配置對(duì)象。

disconnect -停止監(jiān)聽變化。

takeRecords -觸發(fā)回調(diào)前返回最新的批量 DOM 變化。

observer 方法

observer 方法指定所要觀察的 DOM 元素,以及要觀察的特定變動(dòng)。

const article = document.querySelector("article")
observer.observer(article, {
  childList: true,
  arrtibutes: true
})

上面代碼分析:

指定所要觀察的 DOM 元素 article

指定所要觀察的變動(dòng)是子元素的變動(dòng)和屬性變動(dòng)。

將這兩個(gè)限定條件作為參數(shù),傳入observer 對(duì)象 observer方法。

disconnect 方法

disconnect 方法用來停止觀察。發(fā)生相應(yīng)變動(dòng)時(shí),不再調(diào)用回調(diào)函數(shù)。

const MutationObserver =
  window.MutationObserver ||
  window.WebKitMutationObserver ||
  window.MozMutationObserver
// 選擇目標(biāo)節(jié)點(diǎn)
const target = document.querySelector("#some-id")
// 創(chuàng)建觀察者對(duì)象
const observer = new MutationObserver(mutation =>  {
  mutations.forEach(function(mutation) {
    console.log(mutation.type)
  })
})
// 配置觀察選項(xiàng):
const config = { attributes: true, childList: true, characterData: true }
// 傳入目標(biāo)節(jié)點(diǎn)和觀察選項(xiàng)
observer.observe(target, config)
// 隨后,你還可以停止觀察
observer.disconnect()
takeRecord 方法

takeRecord 方法用來清除變動(dòng)記錄,即不再處理未處理的變動(dòng)。

在觀察者對(duì)象上調(diào)用 takeRecords 會(huì)返回 其觀察節(jié)點(diǎn)上的變化記錄(MutationRecord)數(shù)組。其中 MutationRecord 數(shù)組也會(huì)作為,觀察者初始化時(shí)的回調(diào)函數(shù)的第一個(gè)參數(shù)。

其包含的屬性如下:

type 如果是屬性發(fā)生變化,則返回 attributes.如果是一個(gè)CharacterData 節(jié)點(diǎn)發(fā)生變化,則返回 characterData ,如果是目標(biāo)節(jié)點(diǎn)的某個(gè)子節(jié)點(diǎn)發(fā)生了變化,則返回 childList .

target 返回此次變化影響到的節(jié)點(diǎn),具體返回那種節(jié)點(diǎn)類型是根據(jù) type 值的不同而不同的,如果 type 為 attributes ,則返回發(fā)生變化的屬性節(jié)點(diǎn)所在的元素節(jié)點(diǎn),如果 type 值為 characterData ,則返回發(fā)生變化的這個(gè) characterData 節(jié)點(diǎn).如果 type 為 childList ,則返回發(fā)生變化的子節(jié)點(diǎn)的父節(jié)點(diǎn).

addedNodes 返回被添加的節(jié)點(diǎn)

removedNodes 返回被刪除的節(jié)點(diǎn)

previousSibling 返回被添加或被刪除的節(jié)點(diǎn)的前一個(gè)兄弟節(jié)點(diǎn)

nextSibling 返回被添加或被刪除的節(jié)點(diǎn)的后一個(gè)兄弟節(jié)點(diǎn)

attributeName 返回變更屬性的本地名稱

oldValue 根據(jù) type 值的不同,返回的值也會(huì)不同.如果 type 為 attributes,則返回該屬性變化之前的屬性值.如果 type 為 characterData,則返回該節(jié)點(diǎn)變化之前的文本數(shù)據(jù).如果 type 為 childList,則返回 null

observer.takeRecord()
MutationObserver 類型

MutationObserver 所觀察的 DOM 變動(dòng)(即上面代碼的 option 對(duì)象),包含以下類型:

childList:子元素的變動(dòng)

attributes:屬性的變動(dòng)

characterData:節(jié)點(diǎn)內(nèi)容或節(jié)點(diǎn)文本的變動(dòng)

subtree:所有下屬節(jié)點(diǎn)(包括子節(jié)點(diǎn)和子節(jié)點(diǎn)的子節(jié)點(diǎn))的變動(dòng)

想要觀察哪一種變動(dòng)類型,就在 option 對(duì)象中指定它的值為 true。
需要注意的是,不能多帶帶觀察 subtree 變動(dòng),必須同時(shí)指定 childList、attributes 和 characterData 中的一種或多種。

除了變動(dòng)類型,option 對(duì)象還可以設(shè)定以下屬性:

attributeOldValue:值為 true 或者為 false。如果為 true,則表示需要記錄變動(dòng)前的屬性值。

characterDataOldValue:值為 true 或者為 false。如果為 true,則表示需要記錄變動(dòng)前的數(shù)據(jù)值。

attributesFilter:值為一個(gè)數(shù)組,表示需要觀察的特定屬性(比如["class", "str"])。

創(chuàng)建 MutationObserver 并 獲取 dom 元素,定義回調(diào)數(shù)據(jù)。

// 獲取MutationObserver,兼容低版本的瀏覽器
const MutationObserver =
  window.MutationObserver ||
  window.WebKitMutationObserver ||
  window.MozMutationObserver
// 獲取dom元素
const list = document.querySelector("ol")
// 創(chuàng)建Observer
const Observer = new MutationObserver((mutations, instance) => {
  console.log(mutations)
  console.log(instance)
  mutations.forEach(mutation => {
    console.log(mutation)
  })
})

子元素的變動(dòng)

Observer.observe(list, {
  childList: true,
  subtree: true
})
// 追加div標(biāo)簽
list.appendChild(document.createElement("div"))
// 追加文本
list.appendChild(document.createTextNode("foo"))
// 移除第一個(gè)節(jié)點(diǎn)
list.removeChild(list.childNodes[0])
// 子節(jié)點(diǎn)移除創(chuàng)建的div
list.childNodes[0].appendChild(document.createElement("div"))

監(jiān)測(cè) characterData 的變動(dòng)

Observer.observe(list, {
  childList: true,
  characterData: true,
  subtree: true
})
// 將第一個(gè)子節(jié)點(diǎn)的數(shù)據(jù)改為cha
list.childNodes[0].data = "cha"

監(jiān)測(cè)屬性的變動(dòng)

Observer.observe(list, {
  attributes: true
})
// 設(shè)置節(jié)點(diǎn)的屬性  會(huì)觸發(fā)回調(diào)函數(shù)
list.setAttribute("data-value", "111")
// 重新設(shè)置屬性 會(huì)觸發(fā)回調(diào)
list.setAttribute("data-value", "2222")
// 刪除屬性 也會(huì)觸發(fā)回調(diào)
list.removeAttribute("data-value")

屬性變動(dòng)前,記錄變動(dòng)之前的值

Observer.observe(list, {
  attributes: true,
  attributeOldValue: true
})
// 設(shè)置節(jié)點(diǎn)的屬性  會(huì)觸發(fā)回調(diào)函數(shù)
list.setAttribute("data-value", "111")
// 刪除屬性
list.setAttribute("data-value", "2222")

characterData 變動(dòng)時(shí),記錄變動(dòng)前的值。

Observer.observe(list, {
  childList: true,
  characterData: true,
  subtree: true,
  characterDataOldValue: true
})
// 設(shè)置數(shù)據(jù) 觸發(fā)回調(diào)
list.childNodes[0].data = "aaa"
// 重新設(shè)置數(shù)據(jù) 重新觸發(fā)回調(diào)
list.childNodes[0].data = "bbbb"

attributeFilter {Array} 表示需要觀察的特定屬性 比如 ["class", "src"];

Observer.observe(list, {
  attributes: true,
  attributeFilter: ["data-value"]
})
// 第一次設(shè)置屬性 data-key 不會(huì)觸發(fā)的,因?yàn)閐ata-value 不存在
list.setAttribute("data-key", 1)
// 第二次會(huì)觸發(fā)
list.setAttribute("data-value", 1)
案例分析—demo 編輯器

下面我們做一個(gè)簡(jiǎn)單的 demo 編輯器:

首先給父級(jí)元素 ol 設(shè)置 contenteditable 讓容器可編輯;

然后構(gòu)造一個(gè) observer 監(jiān)聽子元素的變化;

每次回車的時(shí)候,控制臺(tái)輸出它的內(nèi)容;

  1. 111111
const MutationObserver =
  window.MutationObserver ||
  window.WebKitMutationObserver ||
  window.MozMutationObserver
const list = document.querySelector("ol")
const Observer = new MutationObserver((mutations, instance) => {
  mutations.forEach(mutation => {
    if (mutation.type === "childList") {
      const list_values = [].slice
        .call(list.children)
        .map(node => node.innerHTML)
        .filter(s => s !== "
") console.log(list_values) } }) }) Observer.observe(list, { childList: true })

現(xiàn)在我們繼續(xù)可以做一個(gè)類似于 input 和 textarea 中的 valueChange 的事件一樣的,監(jiān)聽值變化,之前的值和之后的值,如下代碼:

const MutationObserver =
  window.MutationObserver ||
  window.WebKitMutationObserver ||
  window.MozMutationObserver
const list = document.querySelector("ol")
const Observer = new MutationObserver((mutations, instance) => {
  mutations.forEach(mutation => {
    const enter = {
      mutation: mutation,
      el: mutation.target,
      newValue: mutation.target.textContent,
      oldValue: mutation.oldValue
    }
    console.log(enter)
  })
})

Observer.observe(list, {
  childList: true,
  attributes: true,
  characterData: true,
  subtree: true,
  characterDataOldValue: true
})
注意: 對(duì) input 和 textarea 不起作用的。
案例分析—編輯器統(tǒng)計(jì)字?jǐn)?shù)

還可以輸入100字

const MutationObserver =
  window.MutationObserver ||
  window.WebKitMutationObserver ||
  window.MozMutationObserver
const editor = document.querySelector("#editor")
const textInput = document.querySelector("#textInput")
const observer = new MutationObserver(mutations => {
  mutations.forEach(function(mutation) {
    if (mutation.type === "characterData") {
      const newValue = mutation.target.textContent
      textInput.innerHTML = `還可以輸入${1000 - newValue.length}字`
    }
  })
})
observer.observe(editor, {
  childList: true,
  attributes: true,
  characterData: true,
  subtree: true,
  characterDataOldValue: true
})

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100827.html

相關(guān)文章

  • VueJS源碼學(xué)習(xí)——MutationObserver實(shí)現(xiàn)nextTick

    摘要:倡導(dǎo)開發(fā)者盡量不直接操作,但有的時(shí)候由于各種需求讓開發(fā)者不得不這樣做,于是的實(shí)現(xiàn)就是讓開發(fā)者在修改數(shù)據(jù)后,能夠在數(shù)據(jù)更新到后才執(zhí)行對(duì)應(yīng)的函數(shù),從而獲取最新的數(shù)據(jù)。 Vue 倡導(dǎo)開發(fā)者盡量不直接操作 DOM,但有的時(shí)候由于各種需求讓開發(fā)者不得不這樣做,于是 nextTick 的實(shí)現(xiàn)就是讓開發(fā)者在修改數(shù)據(jù)后,能夠在數(shù)據(jù)更新到 DOM 后才執(zhí)行對(duì)應(yīng)的函數(shù),從而獲取最新的 DON 數(shù)據(jù)。 原文...

    xumenger 評(píng)論0 收藏0
  • JavaScript 工作原理之十-使用 MutationObserver 監(jiān)測(cè) DOM 變化

    摘要:概述是現(xiàn)代瀏覽器提供的用來檢測(cè)變化的網(wǎng)頁(yè)接口。比如通知用戶當(dāng)前所在的頁(yè)面所發(fā)生的一些變化。觸發(fā)回調(diào)前返回最新的批量變化。在函數(shù)內(nèi)部,開始必須使用代碼進(jìn)行檢查,確保是我們所監(jiān)聽的動(dòng)畫。 原文請(qǐng)查閱這里,略有刪減,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第十章。 網(wǎng)絡(luò)應(yīng)用...

    bbbbbb 評(píng)論0 收藏0
  • JavaScript 工作原理之十-使用 MutationObserver 監(jiān)測(cè) DOM 變化

    摘要:概述是現(xiàn)代瀏覽器提供的用來檢測(cè)變化的網(wǎng)頁(yè)接口。比如通知用戶當(dāng)前所在的頁(yè)面所發(fā)生的一些變化。觸發(fā)回調(diào)前返回最新的批量變化。在函數(shù)內(nèi)部,開始必須使用代碼進(jìn)行檢查,確保是我們所監(jiān)聽的動(dòng)畫。 原文請(qǐng)查閱這里,略有刪減,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第十章。 網(wǎng)絡(luò)應(yīng)用...

    zone 評(píng)論0 收藏0
  • JavaScript 工作原理之十-使用 MutationObserver 監(jiān)測(cè) DOM 變化

    摘要:概述是現(xiàn)代瀏覽器提供的用來檢測(cè)變化的網(wǎng)頁(yè)接口。比如通知用戶當(dāng)前所在的頁(yè)面所發(fā)生的一些變化。觸發(fā)回調(diào)前返回最新的批量變化。在函數(shù)內(nèi)部,開始必須使用代碼進(jìn)行檢查,確保是我們所監(jiān)聽的動(dòng)畫。 原文請(qǐng)查閱這里,略有刪減,本文采用知識(shí)共享署名 4.0 國(guó)際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第十章。 網(wǎng)絡(luò)應(yīng)用...

    Richard_Gao 評(píng)論0 收藏0
  • 如何優(yōu)雅監(jiān)聽容器高度變化

    摘要:哈哈哈哈,以上純屬虛構(gòu),不過在最近項(xiàng)目中還真遇到過對(duì)容器監(jiān)聽高寬變化在使用或滾動(dòng)插件,如果容器內(nèi)部元素有高度變化要去及時(shí)更新外部包裹容器,即調(diào)用方法。處理很簡(jiǎn)單,只需在動(dòng)畫停止事件觸發(fā)時(shí)監(jiān)聽高寬變化即可。 前言 老鳥:怎樣去監(jiān)聽 DOM 元素的高度變化呢?菜鳥:哈哈哈哈哈,這都不知道哦,用 onresize 事件鴨!老鳥扶了扶眼睛,空氣安靜幾秒鐘,菜鳥才晃過神來。對(duì)鴨,普通 DOM 元...

    hizengzeng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<