本系列专门研究 JavaScript 及其构建组件,这是第 10 期。在识别和描述核心元素的过程当中,咱们也分享了一些构建 SessionStack 的重要法则,SessionStack 是一个 JavaScript 应用,为了帮助用户实时查看和再现他们的 web 应用程序缺陷,它须要健壮而且高性能。javascript
web 应用正在持续的愈来愈侧重客户端,这是由不少缘由形成的,例如须要更丰富的 UI 来承载复杂应用的需求,实时运算,等等。css
持续增长的复杂度使得在 web 应用的生命周期的任意时刻中获取 UI 的确切状态愈来愈困难。前端
而当你在搭建某些框架或者库的时候,甚至会更加困难,例如,前者须要根据 DOM 来做出反应并执行特定的动做。java
MutationObserver 是一个现代浏览器提供的 Web API,用于检测 DOM 的变化。借助这个 API,能够监听到节点的新增或移除,节点的属性变化或者字符节点的字符内容变化。node
为何你会想要监听 DOM?android
这里有不少 MutationObserver API 带来极大便捷的例子,好比:ios
这里有几个关于 MutationObserver 是如何带来便捷的例子。css3
将 MutationObserver
应用于你的应用至关简单。你须要经过传入一个函数来建立一个 MutationObserver
实例,每当有变化发生,这个函数将会被调用。函数的第一个参数是一个批次内全部的变化(mutation)的集合。每一个变化都会提供它的类型和已经发生的变化的信息。git
var mutationObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation);
});
});
复制代码
这个被建立的对象有三个方法:github
observe
— 开始监听变化。须要两个参数 - 你须要观察的 DOM 和一个设置对象disconnect
— 中止监听变化takeRecords
— 在回调函数调用以前,返回最后一个批次的变化。下面这个代码片断展现了如何开始观察:
// 开始监听页面中根 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 的日志:
这个是由移除 class
属性致使的变化。
最后,为了在任务结束后中止对 DOM 的观察,你能够这样作:
// 中止 MutationObserver 对变化的监听。
mutationObserver.disconnect();
复制代码
如今,MutationObserver
已经被普遍支持:
无论怎么说,MutationObserver
并非一直就有的。那么当 MutationObserver
出现以前,开发者用的是什么?
这是几个可用的其余选项:
最简单的最接近原生的方法是 polling。使用浏览器的 setInterval web 接口你能够设置一个在一段时间后检查是否有变化发生的的任务。天然,这个方法将会严重的下降应用或者网站的性能。
在 2000 年,MutationEvents API 被引入。尽管颇有用,可是每次 DOM 发生变化 mutation events 都会被触发,这将再次致使性能问题。如今 MutationEvents
接口已经被废弃,很快,现代浏览器将会彻底中止对它的支持。
这是浏览器对 MutationEvents
的支持:
一个有点奇怪的备选方案依赖于 CSS animations。这可能听起来有些让人困惑。基本上,这个方案是建立一个动画,一旦一个元素被添加到了 DOM,这个动画就将会被触发。动画开始的时候,animationstart
事件会被触发:若是你对这个事件绑定了一个处理器,你将会确切的知道元素是何时被添加到 DOM 的。动画执行的时间段很短,因此实际应用的时候它对用户是不可见的。
首先,咱们须要一个父级元素,咱们在它的内部监听节点的插入:
<div id=”container-element”></div>
复制代码
为了获得节点插入的处理器,咱们须要设置一系列的 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 + firefox
document.addEventListener(“MSAnimationStart”, insertionListener, false); // IE
document.addEventListener(“webkitAnimationStart”, insertionListener, false); // Chrome + Safari
复制代码
这是浏览器对于 CSS 动画的支持:
MutationObserver
能提供上述提到的解决方案没有的不少优势。本质上,它能覆盖到每个可能发生的 DOM 的变化,而且它会在一个批次的变化发生后被触发,这种方法使得它获得大大的优化。最重要的,MutationObserver
被全部的主流现代浏览器所支持,还有一些使用引擎下 MutationEvents 的 polyfill。
MutationObserver
在 SessionStack 库中占据了核心位置。
你一旦将 SessionStack 库整合进 web 应用,它就开始收集 DOM 变化、网络请求、错误信息、debug 信息等等,并发送到咱们的服务器。SessionStack 使用这些信息从新建立了你的用户端发生的一切,并以发生在用户端的一样的方式将产品的问题展示给你。不少用户认为 SessionStack 记录的实际是视频 -- 然而它并无。记录真实状况的视频是很耗费资源的,然而咱们收集的少许数据却很轻量,并不会影响 UX 和你的 web 应用的性能。
若是你想要尝试一下 SessionStack,这是一个免费的设计案例。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。