MutationObserver(上)

首先MutationObserver接口是替换废弃的MutationEvent接口(MutationEvent定义了一系列DOM变化时触发的事件,浏览器处理事件的实现机制不同导致出现了严重的的性能问题)

MutationObserver接口,可以在DOM被修改时,异步执行回调;可以观察整个文档、DOM树的一部分,或某个元素。除此,还可以观察元素属性(attributes)、子节点(childList)、文本(characterData),或者前三者任意组合的变化。

基本用法:

MutationObserver的实例需要通过调用MutationObserver构造函数并传入一个回调函数来创建

1、observe()方法:

新创建的MutationObserver实例不会关联DOM的任何部分。要把observer与DOM关联起来,需要使用observe()。这个接收两个必须的参数:observe(要观察变化的DOM节点,MutationObserverInit对象)

MutationObserverInit对象用于控制观察哪些方面的变化,是一个键/值形式配置选项的字典。

例:配置观察<body>元素上的属性变化:

    let mutation1 = new MutationObserver(()=>{console.log('<body>属性变化')});

    mutation1.observe(document.body,{attributes:true});

    执行以上代码后,<body>元素上任何属性发生变化都会被这个MutationObserver实例发现,然      后就会异步执行注册的回调函数。<body>元素后代的修改或其他非属性修改都不会触发回到进      入任务队列

    验证:

    document.body.className='foo'

    console.log('body class变化');

   // body class变化

   // <body>属性变化

    注:回调中的console.log是后执行的。说明回调并非与实际的DOM变化同步执行

2、回调与MutationRecord

每个回调都会收到一个MutationRecord实例数组。MutationRecord包含发生了什么变化以及DOM的哪部分受到了影响。因为回调执行前可能同时发生多个满足观察条件的事件,所以每次执行回调都会传入一个包含按顺序入队的MutationRecord实例的数组

let mutation2 = new MutationObserver((MutationRecords) => { console.log(MutationRecords) });

mutation2.observe(document.body, { attributes: true });

document.body.setAttribute('foo', 'bar');

// [

    //     {

    //         addedNodes:NodeList[],

    //         attributeName:"foo",

    //         attributeNamespace:null,

    //         nextSibling:null

    //         oldValue:null

    //         previousSibling:null

    //         removedNodes:NodeList[]

    //         target:body

    //         type:"attributes"

    //     }

// ]

例:涉及命名空间的类似变化

document.body.setAttributeNS('baz','foo', 'bar');

// [

    //     {

    //         addedNodes:NodeList[],

    //         attributeName:"foo",

    //         attributeNamespace:'baz',

    //         nextSibling:null

    //         oldValue:null

    //         previousSibling:null

    //         removedNodes:NodeList[]

    //         target:body

    //         type:"attributes"

    //     }

// ]

连续修改会生成多个MutationRecord实例,下次回调执行就会收到包含所有这些实例的数组,顺序为变化事件发生的顺序

document.body.className='foo';

document.body.className='bar';

document.body.className='baz';

[MutationRecord, MutationRecord, MutationRecord]

MutationRecord实例属性:

target被修改影响的目标节点
type字符串,标识变化的类型:"attributes "、 " characterData" 或 "childList"
oldValue如果在MutationObserverInit对象中启用 (attributeOldValue或characterData OldValue为true), "attributes"或"characterData"的变化事件会设置这个属性为被替代的值;"childList"类型的变化始终将这个属性设置为null
attributeName对于"attributes"类型的变化,这里保存被修改属性的名字
attributeNamespace对于使用了命名空间的"attributes"类型的变化,这里保存被修改属性的名字其他变化事件会将这个属性设置为null
addedNodes对于"childList"类型的变化,返回包含变化中添加节点的NodeList默认为空 NodeList
removedNodes对于"childList"类型的变化,返回包含变化中删除节点的NodeList删除节点的NodeList默认为空 NodeList
previousSibling对于"childList"类型的变化,返回变化节点的前一个同胞Node默认为null
nextSibling对于"childList"类型的变化,返回变化节点的后一个同胞Node默认为null

传给回调函数第二个参数是观察变化的MutationObserver实例

let mutation3 = new MutationObserver((MutationRecords,MutationObserver) => { console.log(MutationRecords,MutationObserver) });

mutation3.observe(document.body, { attributes: true });

document.body.className='foo';

3、disconnect()

默认情况下,只要被观察的元素不被垃圾回收,MutationObserver的回调就会响应DOM变化事件,从而执行。要提前终止执行回调,可以调用disconnect()

    例:正常调用,不仅会停止此后变化事件的回调,也会停止已经加入任务队列的回调

    let disconnect = new MutationObserver((MutationRecords) => {     console.log(MutationRecords)});

    disconnect.observe(document.body, { attributes: true });

    document.body.className='foo';

    disconnect.disconnect();

    document.body.className='bar';

    //没有日志输出

要想让已加入任务队列的回调执行,可以使用setTimeOut()让已经入列的回调执行完毕,再调用disconnect()

setTimeout(()=>{

        disconnect.disconnect();

        document.body.className='bar';

 },0)

// [

    //     {

    //         addedNodes:NodeList[],

    //         attributeName:"foo",

    //         attributeNamespace:null,

    //         nextSibling:null

    //         oldValue:null

    //         previousSibling:null

    //         removedNodes:NodeList[]

    //         target:body.bar

    //         type:"attributes"

    //     }

// ]

4、复用MutationObserver

多次调用observe()方法,可以重复使用一个MutationObserver对象观察多个不同的目标节点。此时,mutationRecord的target属性可以标识目标节点

let mutation4 = new MutationObserver((MutationRecords) => console.log(MutationRecords.map(x=>x.target)));

    向页面body添加两个子节点

    let childA = document.createElement('div');

         childB = document.createElement('span');

    document.body.appendChild(childA);

    document.body.appendChild(childB);

    观察两个子节点

    mutation4.observe(childA,{attributes:true})

    mutation4.observe(childB,{attributes:true})

    修改两个子节点属性

    childA.setAttribute('foo','bar')

    childB.setAttribute('foo','bar')

   //[div,span]

5、重用MutationObserver

调用disconnect()方法并不会结束MutationObserver的生命。还可以重新使用这个观察者,再将它关联到新的目标节点。

例:先断开然后又恢复了观察者与<body>元素的关联

    let mutation5 = new MutationObserver((MutationRecords) =>              MutationRecords.map((x)=>console.log(x.attributeName)));

    mutation5.observe(document.body, { attributes: true });

    这行代码会触发变化事件

    document.body.setAttribute('foo','bar')

    setTimeout(()=>{

        mutation5.disconnect();

        //这行代码不会触发变化事件

        document.body.setAttribute('bar', 'baz');

    },0)

    setTimeout(()=>{

        mutation5.observe(document.body, { attributes: true });

        //这行代码会触发变化事件

        document.body.setAttribute('baz', 'qux');

    },0)

    //foo,baz

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值