监听元素高度变化_「译」JavaScript 如何工作:用 MutationObserver 追踪 DOM 变化

MutationObserver是现代浏览器的Web API,用于检测DOM变化。它允许开发者监听节点的增删、属性变化等,广泛用于实时更新应用、动态加载模块等场景。文章介绍了如何创建和使用MutationObserver,以及在MutationObserver出现之前的几种备择方案,如polling、MutationEvents和CSS animations,强调MutationObserver的高性能和广泛浏览器支持。
摘要由CSDN通过智能技术生成

前言

关于JavaScript如何工作的文章后续会写一个系列,通过本系列文章的阅读,相信你对JavaScript应该会有比较深入的理解。当然,欢迎大家关注我,我将持续分享哪些前端层面核心的知识点,希望能给同处前端的你带来一点点收获。关于JavaScript引擎的理解也欢迎大家阅读我写的《面试官:我们来聊聊Chrome中的V8隐藏类吧》,《高手进阶之史上最全JS内存管理策略剖析》,《浏览器事件循环必知必会10点》,《「译」JavaScript是如何工作的:引擎,运行时间和调用栈的概览》等等。

1、概览

MutationObserver 是现代浏览器提供的 Web API,用于检测 DOM 的变化。借助这个 API,可以监听到DOM节点的新增,移除,节点的属性变化或者节点的内容变化。

为什么你会想要监听 DOM?

这里有很多 MutationObserver API 带来极大便捷的例子,比如:

1)你想要提醒 web 应用的用户,他现在所浏览的页面有内容发生了变化。

2)你正在使用一个全新的 JavaScript 框架,它根据 DOM 的变化动态加载 JavaScript 模块。

3)你正在开发一个 WYSIWYG 编辑器,并试着实现撤销/重做功能。借助 MutationObserver API,你在任何时间都能知道发生了什么变化,所以撤销也就非常容易。

330642edce323ba4f82a050f16220482.png

下面有几个关于 MutationObserver 是如何带来便捷的例子。

2、如何使用 MutationObserver

将 MutationObserver 应用于你的应用相当简单。你只需要通过传入一个函数来创建一个 MutationObserver 实例,每当有变化发生,这个函数将会被调用。函数的第一个参数是一个批次内所有的变化(mutation)的集合。每个变化都会提供它的类型和已经发生的变化的信息。

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

这个被创建的对象有三个方法:

1)observe — 开始监听变化。需要两个参数 - 你需要观察的 DOM 和一个设置对象

2)disconnect — 停止监听变化

3)takeRecords — 在回调函数调用之前,返回最后一个批次的变化。

下面这个代码片段展示了如何开始观察:

// 开始监听页面中根 HTML 元素中的变化。mutationObserver.observe(document.documentElement, { attributes: true, characterData: true, childList: true, subtree: true, attributeOldValue: true, characterDataOldValue: true});

现在,假设在 DOM 中你有一些非常简单的 div :

Simple div

使用 jQuery,你可以移除这个 div 的 class 属性:

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

当我们开始观察,在调用 mutationObserver.observe(...) 之后我们将会在控制台看到每个 MutationRecord 的日志:

0b716792144734688b23d331a6556e85.png

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

最后,为了在任务结束后停止对 DOM 的观察,你可以这样做:

// 停止 MutationObserver 对变化的监听。mutationObserver.disconnect();

现在,MutationObserver 已经被广泛支持:

b723cb4c046359aaa568bcdef3d38d08.png

3、有什么备择方案

实际上,MutationObserver 并不是一直就有的。那么当 MutationObserver 出现之前,开发者用的是什么?

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

1)Polling

2)MutationEvents

3)CSS animations

3.1、Polling

最简单的且最接近原生的方法是 polling。使用浏览器的 setInterval web API接口你可以设置一个在一段时间后检查是否有变化发生的的任务。自然,这个方法将会严重的降低应用或者网站的性能。

3.2、MutationEvents

在 2000 年,MutationEvents API 被引入。尽管很有用,但是每次 DOM 发生变化 mutation events 都会被触发,这将再次导致性能问题。现在 MutationEvents 接口已经被废弃,很快,现代浏览器将会完全停止对它的支持。下面浏览器对 MutationEvents 的支持:

3a06cb06243291064e0fe1b3cd0cef80.png

3.3、CSS animations方案

一个有点奇怪的备选方案是基于 CSS animations。这可能听起来有些让人困惑。基本上,这个方案是创建一个动画,一旦一个元素被添加到了 DOM,这个动画就将会被触发。动画开始的时候,animationstart 事件会被触发:如果你对这个事件绑定了一个处理器,你将会确切的知道元素是什么时候被添加到 DOM 的。动画执行的时间段很短,所以实际应用的时候它对用户是不可见的。

首先,我们需要一个父级元素,我们在它的内部监听节点的插入:

为了得到节点插入的处理器,我们需要设置一系列的 keyframe 动画,当节点插入的时候,动画将会开始。

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

keyframes 已经创建,动画还需要被应用于你想要监听的元素。注意应设置很小的 duration 值 —— 它们将会减弱动画在浏览器上留下的痕迹:

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

这为 container-element 的所有子节点都添加了动画。当动画结束后,插入的事件将会被触发。我们需要一个作为事件监听者的 JavaScript 方法。在方法内部,必须确保初始的 event.animationName 检测是我们想要的那个动画。

var insertionListener = function(event) { // 确保这是我们想要的那个动画。 if (event.animationName === "nodeInserted") { console.log("Node has been inserted: " + event.target); }}

现在是时候为父级元素添加事件监听了:

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

这是浏览器对于 CSS 动画的支持:

e733cae0afbc09c531b5e5655d5ab319.png

3.4、小结

MutationObserver 能满足上述提到的替代解决方案没有的很多优点。本质上,它能覆盖到每一个可能发生的 DOM 变化,并且它会在一个批次的变化发生后被触发,这种方法使得它得到很大的优化。最重要的是,MutationObserver 被所有的主流现代浏览器所支持,当然还有一些可以使用MutationEvents 的 polyfill。

译者注:可以参考下arrive这个公共的polyfill,通过它可以兼容所有的浏览器

下面是具体的arrive的使用实例:

// watch for creation of an element which satisfies the selector ".test-elem"$(document).arrive(".test-elem
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值