如何监听 DOM 变化

14,588 阅读3分钟

前言

在MVVM框架中,一是监听数据变化,数据驱动。

  • 我们都知道通过Object.defineProperties(),来监听数据的变化,或者使用,代理和反射。
  • 其实在MVVM中,也有操作DOM的场景。那么,我们是通过哪些API来监听DOM的变化的呢?

当我们,通过JS操作了DOM之后,我们需要通知到DOM来更新视图。在VUE中,是维护了一个异步的队列。并不是你修改了DOM就会直接更新到视图上面。

监听DOM变化的方法:

  • 轮询
  • MutationEvents(基本已废弃)
  • CSS 动画

以上三种都不是很好的方法。那么,我们今天来介绍一下,现在比较常用的:

  • MutationObserver

我们选择Mutation Observer

概述

Mutation Observer API 用来监视 DOM 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。 Mutation Observer 则是异步触发,DOM 的变动并不会马上触发,而是要等到当前所有 DOM 操作都结束才触发。 这样设计是为了应付 DOM变动频繁的特点。

举例来说,如果文档中连续插入1000个li元素,就会连续触发1000个插入事件,执行每个事件的回调函数,这很可能造成浏览器的卡顿;而 Mutation Observer 完全不同,只在 1000 个段落都插入结束后才会触发,而且只触发一次。

Mutation Observer有以下特点:

  • 等待所有脚本任务完成后,才会运行,即采用异步方式
  • 把 DOM 变动记录封装成一个数组进行处理,而不是一条条地个别处理 DOM 变动
  • 即可以观察发生在 DOM 节点的所有变动,也可以观察某一类变动

使用

var observe = new MutationObserver(function(mutations, observer){
});
var el = document.querySelector('#app');
var  options = {
  'childList': true,
  'attributes':true
} ;
observer.observe(el, options);
// 创建并返回一个 MutationObserver 实例, 并侦听el元素的变动。

小例子

MutationObserver的callback回调函数是异步的,只有在全部DOM操作完成之后才会调用callback。

<div id='target' class='block' name='target'>
    target的第一个子节点
    <p>
       <span>target的后代</span>
    </p>
</div>


var target=document.getElementById('target');
var i=0
var observe=new MutationObserver(function (mutations,observe) {
    i++   
});
observe.observe(target,{ childList: true});
target.appendChild(docuemnt.createTextNode('1'));
target.appendChild(docuemnt.createTextNode('2'));
target.appendChild(docuemnt.createTextNode('3'));
console.log(i)  //1 callback的回调次数

应用

在很多情况下,MutationObserver API 都可以派上用场。例如:

  • 你希望通知 Web 应用程序访问者,他当前所在的页面发生了一些更改。
  • 你正在开发一个新的 JavaScript 框架,需要根据 DOM 的变化动态加载 JavaScript 模块。

兼容性

看评论中,对兼容性比较关注,特贴出来。也可去mdn直接查看

总结

  • MutationObserver接口提供了监视对DOM树所做更改的能力。它被设计为旧的Mutation Events功能的替代品,该功能是DOM3 Events规范的一部分。(MDN)
  • DOM MutationObserver,在不影响浏览器性能的情况下响应DOM更改
  • 等待所有脚本任务完成后,才会运行,即采用异步方式