你不知道的 DOM 变动观察器:Mutation observer

使用 MutationObserver,我们可以监测到我们不需要的元素何时出现在我们的 DOM 中,并将其删除。

还有一些其他情况,例如第三方脚本会将某些内容添加到我们的文档中,并且我们希望检测出这种情况何时发生,以调整页面,动态调整某些内容的大小等。

MutationObserver 使我们能够实现这种需求。

用于架构


从架构的角度来看,在某些情况下,MutationObserver 有不错的作用。

假设我们正在建立一个有关编程的网站。自然地,文章和其他材料中可能包含源代码段。

在 HTML 标记(markup)中的此类片段如下所示:



// 这里是代码

let hello = "world";

为了提高可读性,同时对其进行美化,我们将在我们的网站上使用 JavaScript 语法高亮显示库,例如 Prism.js[3]。为了使用 Prism 对以上代码片段进行语法高亮显示,我们调用了 Prism.highlightElem(pre),它会检查此类 pre 元素的内容,并为这些元素添加特殊的标签(tag)和样式,以进行彩色语法高亮显示,类似于你在本文的示例中看到的那样。

那么,我们应该在什么时候执行该高亮显示方法呢?我们可以在 DOMContentLoaded 事件中执行,或者将脚本放在页面的底部。DOM 就绪后,我们可以搜索元素 pre[class*="language"] 并对其调用 Prism.highlightElem

// 高亮显示页面上的所有代码段

document.querySelectorAll(‘pre[class*=“language”]’).forEach(Prism.highlightElem);

到目前为止,一切都很简单,对吧?我们找到 HTML 中的代码片段并高亮显示它们。

现在让我们继续。假设我们要从服务器动态获取资料。我们将 在本教程的后续章节[4] 中学习进行此操作的方法。目前,只需要关心我们从网络服务器获取 HTML 文章并按需显示:

let article = /* 从服务器获取新内容 */

articleElem.innerHTML = article;

新的 article HTML 可能包含代码段。我们需要对其调用 Prism.highlightElem,否则它们将不会被高亮显示。

对于动态加载的文章,应该在何处何时调用 Prism.highlightElem

我们可以将该调用附加到加载文章的代码中,如下所示:

let article = /* 从服务器获取新内容 */

articleElem.innerHTML = article;

let snippets = articleElem.querySelectorAll(‘pre[class*=“language-”]’);

snippets.forEach(Prism.highlightElem);

……但是,想象一下,如果代码中有很多地方都是在加载内容:文章,测验和论坛帖子等。我们是否需要在每个地方都附加一个高亮显示调用,以在内容加载完成后,高亮内容中的代码。那很不方便。

并且,如果内容是由第三方模块加载的,该怎么办?例如,我们有一个由其他人编写的论坛,该论坛可以动态加载内容,并且我们想为其添加语法高亮显示。没有人喜欢修补第三方脚本。

幸运的是,还有另一种选择。

我们可以使用 MutationObserver 来自动检测何时在页面中插入了代码段,并高亮显示它们。

因此,我们在一个地方处理高亮显示功能,从而使我们无需集成它。

动态高亮显示示例

这是一个工作示例。

如果你运行这段代码,它将开始观察下面的元素,并高亮显示现在此处的所有代码段:

let observer = new MutationObserver(mutations => {

for(let mutation of mutations) {

// 检查新节点,有什么需要高亮显示的吗?

for(let node of mutation.addedNodes) {

// 我们只跟踪元素,跳过其他节点(例如文本节点)

if (!(node instanceof HTMLElement)) continue;

// 检查插入的元素是否为代码段

if (node.matches(‘pre[class*=“language-”]’)) {

Prism.highlightElement(node);

}

// 或者可能在子树的某个地方有一个代码段?

for(let elem of node.querySelectorAll(‘pre[class*=“language-”]’)) {

Prism.highlightElement(elem);

}

}

}

});

let demoElem = document.getElementById(‘highlight-demo’);

observer.observe(demoElem, {childList: true, subtree: true});

下面有一个 HTML 元素,以及使用 innerHTML 动态填充它的 JavaScript。

请先运行前面那段代码(上面那段,观察元素),然后运行下面这段代码。你将看到 MutationObserver 是如何检测并高亮显示代码段的。

一个具有 id="highlight-demo" 的示例元素,运行上面那段代码来观察它。

下面这段代码填充了其 innerHTML,这导致 MutationObserver 作出反应,并突出显示其内容:

let demoElem = document.getElementById(‘highlight-demo’);

// 动态插入带有代码段的内容

demoElem.innerHTML = `下面是一个代码段:

 let hello = "world!"; 
另一个代码段:
.class { margin: 5px; } 

`;

现在我们有了 MutationObserver,它可以跟踪观察到的元素中的,或者整个 document 中的所有高亮显示。我们可以在 HTML 中添加/删除代码段,而无需考虑高亮问题。

其他方法


有一个方法可以停止观察节点:

  • observer.disconnect() —— 停止观察。

当我们停止观察时,观察器可能尚未处理某些更改。在种情况下,我们使用:

  • observer.takeRecords() —— 获取尚未处理的变动记录列表,表中记录的是已经发生,但回调暂未处理的变动。

这些方法可以一起使用,如下所示:

// 如果你关心可能未处理的近期的变动

// 那么,应该在 disconnect 前调用获取未处理的变动列表

let mutationRecords = observer.takeRecords();

// 停止跟踪变动

observer.disconnect();

observer.takeRecords() 返回的记录被从处理队列中移除:

回调函数不会被 observer.takeRecords() 返回的记录调用。

垃圾回收:

观察器在内部对节点使用弱引用。也就是说,如果一个节点被从 DOM 中移除了,并且该节点变得不可访问,那么它就可以被垃圾回收。

《大厂前端面试题解析+Web核心总结学习笔记+企业项目实战源码+最新高清讲解视频》无偿开源 徽信搜索公众号【编程进阶路】

观察到 DOM 节点这一事实并不能阻止垃圾回收。

总结

MutationObserver 可以对 DOM 的变化作出反应 —— 特性(attribute),文本内容,添加/删除元素。

我们可以用它来跟踪代码其他部分引入的更改,以及与第三方脚本集成。

MutationObserver 可以跟踪任何更改。config “要观察的内容”选项用于优化,避免不必要的回调调用以节省资源。


现代 JavaScript 教程:开源的现代 JavaScript 从入门到进阶的优质教程。React 官方文档推荐,与 MDN 并列的 JavaScript 学习教程[5]。

在线免费阅读:https://zh.javascript.info


参考资料

[1]

MutationRecord: https://dom.spec.whatwg.org/#mutationrecord

[2]

MutationRecord: https://dom.spec.whatwg.org/#mutationrecord

[3]

Prism.js: https://prismjs.com/

[4]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DOM Inspector是Mozilla Firefox的一个扩充套件,官方中文版上称之为DOM观察器,在安装Mozilla Firefox时,可以在自订安装中选择是否安装DOM Inspector,如果在安装Mozilla Firefox时没有选择自订安装以安装DOM Inspector,则可以在 Mozilla 的 DOM Inspector 网址进行安装。 Ajax应用程式中经常操作DOM Tree,您可以直接使用DOM Inspector来观察DOM Tree中对应於网页画面的哪个元件,执行Mozilla Firefox官方中文版的「工具/DOM观察器」,可以显示DOM Inspector视窗,在网址列输入网址,并按下「观察」按钮,即可开始观察DOM与网页的对应,对应的画面会以红色方框闪烁显示。 如果您想要找寻特定的DOM节点,则可以执行「搜寻/寻找节点」,搜寻的方式可以有依「Id」、「Tag」或「Attr」等来进行搜寻。 在找到想观察的节点后,可以在左边的窗格观察到该节点的各种属性,预设是显示JavaScript物件的各种属性,例如可在下图中,观察到onmouseover与onmouseoout的事件处理者分别是getBookData()与clearData(): 例如可以切换至DOM Node的检视模式,您也可以在某个属性上按右键「编辑」,直接改变某个DOM的属性值,像是改变src属性: 您甚至可以选定一个DOM节点,在JavaScript检视中,按右键「执行JavaScript」… 您还可以在 Introduction to the DOM Inspector 找到一些关於DOM Inspector的介绍。 安装方式:使用直接把该文件拖动到fifefox上或使用firefox-文件-打开-选择下载的文件-确定。。。即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值