主頁 > 企業開發 > DOM規范 - MutationObserver介面觀察DOM變化

DOM規范 - MutationObserver介面觀察DOM變化

2022-01-02 06:19:33 企業開發

一、MutationObserver 介面說明

此介面可以在 DOM 被修改時異步執行回呼,使用 MutationObserver 可以觀察整個檔案、DOM 樹的一部分,或某個元素,此外還可以觀察元素屬性、子節點、文本,或者前三者任意組合的變化,

DOM3 中新引進 MutationObserver 介面是為了取代廢棄的 DOM2 中的 MutationEvent,

二、基本用法

MutationObserver 的實體要通過 MutationObserver 建構式并傳入一個回呼函式來創建,

let observer = new MutationObserver(() => console.log('Dom was mutated~'))

1. observe() 方法

新創建的 MutationObserver 實體不會關聯 DOM 的任何部分,需要使用 ovserve()方法與 DOM 關聯起來,

此方法需傳兩個必須的引數:

  • 要觀察其變化的 DOM 節點
  • 一個 MutationObserverInit 物件

MutationObserverInit 物件:用于控制哪些方面的變化,是一個鍵/值對形式配置選項的字典,

// 創建一個觀察者(observer)并配置它觀察 body 元素上的屬性變化

let observer = new MutationObserver(() => {
  console.log('body attributes changed~')
})
observer.observe(document.body, { attributes: true })

document.body.className = 'foo'
console.log('Changed body class')

// Changed body class
// body attributes changed~

執行上述代碼后,body 元素上的任何屬性發生變化都會被這個 MutationObserver 實體發現,然后會異步執行注冊的回呼函式,而 body 元素后代的修改或其他非屬性變化修改都不會觸發回呼進入任務佇列,

注意,回呼中的 console.log()是后執行的,這表明回呼并非與實際的 DOM 變化同步執行,

2. 回呼與 MutationRecord 引數

每個回呼都會受到一個 MutationRecord 實體的陣列,MutationRecord 實體包含資訊包括發生了什么變化、以及 DOM 的哪一部分受到了影響,回呼的第二個引數是 MutationObserver 的實體,

// 連續修改會生成多個MutationRecord實體,回呼執行時會受到包含所有這些實體的陣列,順序為變化事件順序,

let observer = new MutationObserver((MutationRecords, mutationObserver) => {
  console.log(MutationRecords, mutationObserver)
})
observer.observe(document.body, { attributes: true })

document.body.setAttribute('foo', 'bar')
document.body.className = 'testName'

// [MutationRecord, MutationRecord], MutationObserver

執行效果如下圖:

MutationRecord 實體屬性說明

屬性 說明
target 被修改影響的目標節點
type 字串,表示變化的型別:"attributes"、"characterData"、"childList"
oldValue 如果在 MutationObserverInit 物件中啟用(attributeOldValue 或 characterData OldValue 為 true),"attributes" 或 "characterData" 的變化事件會設定這個屬性為被替代的值"childList" 型別的變化始終將這個屬性設定為 null
attributeName 對于 "attributes" 型別的變化,這里保存被修改屬性的名字,其他變化事件會將此設定為 null
attributeNamespace 對于使用了命名空間的 "attributes" 型別的變化,這里保存被修改屬性的名字,其他變化事件會將此設定為 null
addedNodes 對于 "childList" 型別的變化,回傳包含變化中添加節點的 NodeList,默認為空 NodeList
removedNodes 對于 "childList" 型別的變化,回傳包含變化中洗掉節點的 NodeList,默認為空 NodeList
previousSibling 對于 "childList" 型別的變化,回傳變化節點的前一個同胞 Node,默認為 null
nextSibling 對于 "childList" 型別的變化,回傳變化節點的后一個同胞 Node,默認為 null

3. disconnet() 方法

默認情況下,只要被觀察的元素不被垃圾回收,MutationObserver 的回呼就會回應 DOM 變化事件而執行,要提前終止回呼,可以呼叫 disconnet() 方法,

let observer = new MutationObserver(() => {
  console.log('body attributes changed~')
})
observer.observe(document.body, { attributes: true })
observer.disconnet()

document.body.className = 'foo'

// (沒有日志輸出)

重用 MutationObserver:呼叫 disconnet() 方法并不會結束 MutationObserver 的生命,還可以重新使用這個觀察者,再講它關聯到新的目標節點,

三、MutationObserverInit 觀察范圍

MutationObserverInit 物件用于控制對目標節點的觀察范圍,例:屬性變化、文本變化和節點變化,

屬性 說明
subtree boolean,表示除了目標節點,是否觀察其子樹(后代),默認為 false,只觀察目標節點的變化
attributes boolean,表示是否觀察目標節點的屬性變化,默認為 false
attributeFilter 字串陣列,表示要觀察哪些屬性的變化,把這個值設定為 true,也會將 attributes 值轉換為 true,默認為觀察所有屬性
attributeOldValue boolean,表示 MutationRecord 是否記錄變化之前的值,把這個值設定為 true,也會將 attributes 值轉換為 true,默認為 false
characterData boolean,表示修改字符資料是否觸發變化事件
characterOldValue boolean,表示 MutationRecord 是否記錄變化之前的值,把這個值設定為 true,也會將 characterData 值轉換為 true,默認為 false
childList boolean,表示修改目標節點的子節點是否觸發變化事件,默認為 false

呼叫 observe() 時,MutationObserverInit 物件中 attributes、characterData、childList 屬性必須至少有一項為 true,

<!-- 觀察子節點 -->

<body>
  <div id="con"></div>

  <script>
    const conEle = document.getElementById('con')
    let observer = new MutationObserver((MutationRecords, mutationObserver) => {
      console.log(MutationRecords)
    })
    observer.observe(conEle, { childList: true })

    conEle.appendChild(document.createElement('p'))
  </script>
</body>

// [MutationRecord]

列印效果如下圖:

四、異步回呼與記錄佇列

1. 記錄佇列

每次 MutationRecord 被添加到 MutationObserver 的記錄佇列時,僅當之前沒有已排期的微任務回呼時(佇列中微任務長度為 0),才會將觀察者注冊的回呼(在初始化 MutationObserver 時傳入)作為微任務調度到任務佇列上,這樣可以保證記錄佇列的內容不會被回呼處理兩次,

不過在回呼的微任務異步執行期間,有可能又會發生更多的變化事件,因此被處理的回呼會接收到一個 MutationRecord 實體的陣列,順序為它們進入記錄佇列的順序,回呼要負責處理這個陣列的每一個實體,因為函式退出之后這些實體就不存在了,回呼執行后,這些 MutationRecord 就用不著了,因此記錄佇列會被清空,其內容會被丟棄,

2. takeRecords() 方法

呼叫 MutationObserver 實體的 takeRecords() 方法可以清空記錄佇列,取出并回傳其中的所有 MutationRecord 實體,

這在希望斷開與觀察目標的聯系,但有希望處理由于呼叫 disconnet() 而被拋棄的記錄佇列中的 MutationRecord 實體時比較有用,

let observer = new MutationObserver((MutationRecords) => {
  console.log(MutationRecords)
})
observer.observe(document.body, { attributes: true })

document.body.className = 'foo'
document.body.className = 'bar'

console.log(111, observer.takeRecords())
console.log(222, observer.takeRecords())

// 111  [MutationRecord, MutationRecord]
// 222  []

五、記憶體與垃圾回收

將變化回呼委托給微任務來執行可以保證事件同步觸發,同時避免隨之而來的混亂,為 MutationObserver 而實作的記錄佇列,可以保證即使變化事件被爆發式的觸發,也不會顯著的拖慢瀏覽器,

無論如何,使用 MutationObserver 仍然不是沒有代價的,因此理解什么時候避免出現這種情況就很重要了,

1. MutationObserver 的參考

MutationObserver 實體與目標節點之間的參考關系是非對稱的,MutationObserver 擁有對觀察目標節點的弱參考,因為是弱參考,所以不會妨礙垃圾回收程式回收目標節點,

然而,目標節點卻擁有對 MutationObserver 的強參考,如果目標節點從 DOM 中被移除,隨后被垃圾回收,則關聯的 MutationObserver 也會被垃圾回收,

2. MutationRecord 的參考

記錄佇列中的每個 MutationRecord 實體至少包含對已有 DOM 節點的一個參考,如果變化是 childList 型別,則會包含多個節點的參考,記錄佇列和回呼處理的默認行為是耗盡這個佇列,處理每個 MutationRecord,然后讓它們超出作用域并被垃圾回收,

有時候可能需要保存某個觀察者的完整變化記錄,保存這些 MutationRecord 實體,也就會保存它們參考的節點,因而會妨礙這些節點的回收,如果需要盡快地釋放記憶體,建議從每個 MutationRecord 中抽取最有用的資訊,然后保存到一個新物件中,最后拋棄 MutationRecord,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/400321.html

標籤:其他

上一篇:javaScript系列 [09]-javaScript和JSON (拓展)

下一篇:NodeJS環境問題:Error spawn cmd ENOENT at Process...

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more