JavaScript是怎样事情的:运用 MutationObserver 跟踪 DOM 的变化

这是特地探究 JavaScript 及其所构建的组件的系列文章的第10篇。

想浏览更多优良文章请猛戳GitHub博客,一年百来篇优良文章等着你!

假如你错过了前面的章节,能够在这里找到它们:

  1. JavaScript 是怎样事情的:引擎,运转时和挪用客栈的概述!
  2. JavaScript 是怎样事情的:深切V8引擎&编写优化代码的5个技能!
  3. JavaScript 是怎样事情的:内存治理+怎样处置惩罚4个罕见的内存走漏 !
  4. JavaScript 是怎样事情的:事宜轮回和异步编程的兴起+ 5种运用 async/await 更好地编码体式格局!
  5. JavaScript 是怎样事情的:深切探究 websocket 和HTTP/2与SSE +怎样挑选准确的途径!
  6. JavaScript 是怎样事情的:与 WebAssembly比较 及其运用场景 !
  7. JavaScript 是怎样事情的:Web Workers的构建块+ 5个运用他们的场景!
  8. JavaScript 是怎样事情的:Service Worker 的生命周期及运用场景!
  9. JavaScript 是怎样事情的:Web 推送关照的机制!

《JavaScript是怎样事情的:运用 MutationObserver 跟踪 DOM 的变化》

Web 应用顺序在客户端变得越来越重,缘由很多,比方须要更雄厚的 UI 来包容更庞杂的应用顺序供应的内容,及时盘算等等。庞杂性的增添使得在 Web 应用顺序生命周期的每一个给定时刻都很难晓得 UI 的确实状况。

而当你在搭建某些框架或许库的时刻,甚至会越发难题,比方,前者须要依据 DOM 来作出反应并实行特定的行动。

概述

Mutation Observer API 用来看管 DOM 变动。DOM 的任何变动,比方节点的增减、属性的变动、文本内容的变动,这个 API 都能够获得关照。

概念上,它很靠近事宜,能够理解为 DOM 发作变动就会触发 Mutation Observer 事宜。然则,它与事宜有一个实质差别:事宜是同步触发,也就是说,DOM 的变动立时会触发响应的事宜;Mutation Observer 则是异步触发,DOM 的变动并不会立时触发,而是要比及当前一切 DOM 操纵都完毕才触发。

如许设想是为了敷衍 DOM 变动频仍的特性。举例来说,假如文档中一连插进去1000个 <li>元素,就会一连触发1000个插进去事宜,实行每一个事宜的回调函数,这极能够形成浏览器的卡顿;而 Mutation Observer 完整差别,只在 1000 个段落都插进去完毕后才会触发,而且只触发一次。

Mutation Observer有以下特性:

  • 它守候一切剧本使命完成后,才会运转,即采纳异步体式格局
  • 它把 DOM 变动纪录封装成一个数组举行处置惩罚,而不是一条条地一般处置惩罚 DOM 变动
  • 它即能够视察发作在 DOM 节点的一切变动,也能够视察某一类变动

为何要要监听 DOM?

在很多状况下,MutationObserver API 都能够派上用场。比方:

  • 你愿望关照 Web 应用顺序访问者,他当前地点的页面发作了一些变动。
  • 你正在开辟一个新的 JavaScript 框架,须要依据 DOM 的变化动态加载 JavaScript 模块。
  • 或许你正在开辟一个所见即所得(WYSIWYG) 编辑器,试图完成取消/重做功用。经由过程应用 MutationObserver API,你能够晓得在任何给定的点上举行了哪些变动,因而能够轻松地取消这些变动。

《JavaScript是怎样事情的:运用 MutationObserver 跟踪 DOM 的变化》

这些只是 MutationObserver 能够供应协助的几个例子。

MutationObserver 用法

在应用顺序中完成 MutationObserver 相称简朴。你须要经由过程传入一个函数来建立一个 MutationObserver 实例,每当有变化发作,这个函数将会被挪用。函数的第一个参数是变动数组,每一个变化都邑供应它的范例和已发作的变化的信息。

var mutationObserver = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log(mutation);
  });
});

这个被建立的对象有三个要领:

  • observe  — 启动监听
  • disconnect — 用来住手视察
  • takeRecords — 返用来消灭变动纪录,即不再处置惩罚未处置惩罚的变动。

observe()

observe 要领用来启动监听,它接收两个参数。

  1. 第一个参数:所要视察的 DOM 节点
  2. 第二个参数:一个设置对象,指定所要视察的特定变

下面的片断展现了怎样最先启动监听(observe  ):

// 最先侦听页面的根 HTML 元素中的变动。
mutationObserver.observe(document.documentElement, {
  attributes: true,
  characterData: true,
  childList: true,
  subtree: true,
  attributeOldValue: true,
  characterDataOldValue: true
});

如今,假定 DOM 中有一些异常简朴的 div:

<div id="sample-div" class="test"> Simple div </div>

运用 JQuery 来移除这个 div 上的 class:

$("#sample-div").removeAttr("class");

正如我们已最先视察到的,在挪用 mutationObserver.observe(…) 以后,将在掌握台中看到响应 MutationRecord 的日记:

《JavaScript是怎样事情的:运用 MutationObserver 跟踪 DOM 的变化》

这个是由移除 class 属性致使的变化。

MutationRecord 对象包含了DOM的相干信息,有以下属性:

type:视察的变动范例(attribute、characterData或许childList)

target:发作变动的 DOM 节点

addedNodes:新增的 DOM 节点

removedNodes:删除的 DOM 节点

previousSibling:前一个同级节点,假如没有则返回 null

nextSibling:下一个同级节点,假如没有则返回 null

attributeName:发作变动的属性。假如设置了attributeFilter,则只返回预先指定的属性。

oldValue:变动前的值。这个属性只对 attribute 和 characterData 变动有效,假如发作 childList 变动,则返回 null

末了,为了在使命完成后住手视察 DOM,能够实行以下操纵:

mutationObserver.disconnect();

如今,MutationObserver 已被普遍支撑:

《JavaScript是怎样事情的:运用 MutationObserver 跟踪 DOM 的变化》

备择计划

MutationObserver 在之前还没有的,那末在 MutationObserver 还没涌现之前,开辟者采纳什么计划呢?

这是几个可用的其他选项:

  • 轮询(Polling)
  • MutationEvents
  • CSS animations

轮询(Polling)

最简朴和最简朴的要领是轮询。运用浏览器 setInterval 要领,能够设置一个使命,按期搜检是不是发作了任何变动。固然,这类要领会明显下降web 应用顺序/网站的机能。

MutationEvents

在2000年,MutationEvents API 被引入。虽然很有效,但在 DOM中 的每一次变动都邑触发转变事宜,这同样会致使机能题目。如今 MutationEvents API 已被弃用,很快当代浏览器将完整住手支撑它。

《JavaScript是怎样事情的:运用 MutationObserver 跟踪 DOM 的变化》

CSS animations

另一个有点新鲜的挑选是依靠 CSS 动画。这听起来能够有点令人困惑。基本上,我们的主意是建立一个动画,一旦元素被增加到 DOM 中,动画就会被触发。动画最先的那一刻,animationstart 事宜将被触发:假如已将事宜处置惩罚顺序附加到该事宜,那末你将确实地晓得元素什么时候被增加到 DOM 中。动画的实行时候周期应当很小,用户险些看不到它。

起首,须要一个父级元素,我们在它的内部监听节点的插进去:

<div id=”container-element”></div>

为了获得节点插进去的处置惩罚器,须要设置一系列的 keyframe 动画,当节点插进去的时刻,动画将会最先。

@keyframes nodeInserted { 
 from { opacity: 0.99; }
 to { opacity: 1; } 
}

建立 keyfram 后,还须要把它放入你想监听的元素上,注重应设置很小的 duration 值 —— 它们将会削弱动画在浏览器上留下的陈迹。

#container-element * {
  animation-duration: 0.001s;
  animation-name: nodeInserted;
}

这会将动画增加到 container-element 的一切子节点。 动画完毕时,将触发插进去事宜。

我们须要一个 JavaScript 函数作为事宜监听器。在函数中,必需举行初始的 event.animationName 搜检以确保它是我们想要的动画。

var insertionListener = function(event) {
  // Making sure that this is the animation we want.
  if (event.animationName === "nodeInserted") {
    console.log("Node has been inserted: " + event.target);
  }
}

如今是时刻为父级元素增加事宜监听了:

document.addEventListener(“animationstart”, insertionListener, false); // standard + firefox
document.addEventListener(“MSAnimationStart”, insertionListener, false); // IE
document.addEventListener(“webkitAnimationStart”, insertionListener, false); // Chrome + Safari

浏览器对CSS动画的支撑状况:

《JavaScript是怎样事情的:运用 MutationObserver 跟踪 DOM 的变化》

MutationObserver 比上述处理计划有很多长处。实质上,它涵盖了 DOM 中能够发作的每一个变动,并且在批量触发变动时,它的优化水平更高。最重要的是,一切重要的当代浏览器都支撑 MutationObserver,另有一些运用引擎下 MutationEvents 的 polyfill。

原文:

https://blog.sessionstack.com…

代码布置后能够存在的BUG没法及时晓得,预先为了处理这些BUG,花了大批的时候举行log 调试,这边顺便给人人引荐一个好用的BUG监控东西 Fundebug

你的点赞是我延续分享好东西的动力,迎接点赞!

迎接到场前端人人庭,内里会常常分享一些手艺资本。

《JavaScript是怎样事情的:运用 MutationObserver 跟踪 DOM 的变化》

    原文作者:前端小智
    原文地址: https://segmentfault.com/a/1190000017832686
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞