MutationObserver对象

MutationObserver (W3C DOM4)对象提供了监视对DOM树所做更改的能力,其被设计为旧的Mutation Events功能的替代品(该功能是DOM3 Events规范的一部分)。

描述

Mutation Observer用来监视DOM变动,DOM的任何变动,例如节点的增减、属性的变动、文本内容的变动,在配置之后都可以通过回调函数来获得通知。Mutation Observer类似于事件的监听DOM.addEventListener方法,都可以在触发某些变动的时候来执行回调函数,只不过Mutation Observer是异步触发,DOM的变动并不会马上触发,在等到当前所有DOM操作都结束才触发。

observe

mutationObserver.observe(target[, options])
Mutation Observerobserve()方法配置了Mutation Observer对象的回调方法,以开始接收与给定选项匹配的DOM变化的通知。

  • target: DOM树中的一个要观察变化的DOM Node,或者是被观察的子节点树的根节点。
  • options: 一个可选的MutationObserverInit对象,此对象的配置项描述了DOM的哪些变化应该提供给当前观察者的callback,在MutationObserverInit对象中childListattributescharacterData三个属性之中,至少有一个必须为true,否则会抛出TypeError异常。
    • childList:表示子节点的变动,指新增,删除或者更改字节点。
    • attributes:表示当前节点属性的变动。
    • characterData:表示节点内容或节点文本的变动。
    • subtree:表示是否将该观察器应用于该节点的所有后代节点。
    • attributeOldValue:表示观察attributes变动时,是否需要记录变动前的属性值。
    • characterDataOldValue:表示观察characterData变动时,是否需要记录变动前的值。
    • attributeFilter:表示需要观察的特定属性,比如["class","src"]。

disconnect

mutationObserver.disconnect()
Mutation Observerdisconnect()方法告诉观察者停止观察变动,可以通过调用其observe()方法来重用观察者。

takeRecords

const mutationRecords = mutationObserver.takeRecords()
Mutation ObservertakeRecords()方法返回已检测到但尚未由观察者的回调函数处理的所有匹配DOM更改的列表,使变更队列保持为空。此方法最常见的使用场景是在断开观察者之前立即获取所有未处理的更改记录,以便在停止观察者时可以处理任何未处理的更改。

示例

Mutation Observer的一个常用功能就是观察DOM元素的大小变更,通常是主动resize造成了该元素的大小发生变化,所以需要观察者来完成DOM元素大小变更的副作用。在这里完成了一个简单的示例,观察了attributeschildList两个属性值,并在attributes中使用attributeFilter来过滤只观察style属性的变动,因为在这里是使用的contenteditable来完成的DOM元素的编辑,所以是使用了childList来完成了子元素的变更观察。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mutation Observer</title>
    <style>
        #observer-dom{
            padding: 5px;
            resize: both;
            width: 300px;
            height: 200px;
            border: 1px solid #eee;
            resize: both;
            overflow: auto;
        }
        #observer-dom:empty:before {
            content: attr(data-placeholder);
            color: #aaa;
        }
        #observer-output{
            width: 300px;
            height: 200px;
            border: 1px solid #eee;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <div id="observer-dom" contenteditable data-placeholder="Enter OR Resize"></div>
    <textarea id="observer-output"></textarea>
</body>
<script>
    const target = document.getElementById("observer-dom");
    const textarea = document.getElementById("observer-output");
    textarea.value = "output: \n";

    const addOutput = log => {
        textarea.value = textarea.value + log + "\n";
        textarea.scrollTop = textarea.scrollHeight;
    }

    const config = { attributes: true, childList: true, attributeFilter: ["style"] };
    const callback = function(mutationsList, observer) {
        for(const mutation of mutationsList) {
            console.log(mutation);
            if(mutation.type === "childList"){
                addOutput("ChildListAdded: " + mutation.addedNodes.length)
            }else if(mutation.type === "attributes"){
                addOutput("AttributeNameChange: " + mutation.attributeName)
            }
        }
    };
    const observer = new MutationObserver(callback);
    observer.observe(target, config);
</script>
</html>

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://juejin.cn/post/6949832945683136542 https://developer.mozilla.org/en-US/docs/Web/API/MutationEvent https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver