在 TamperMonkey 中经常需要在等待页面加载所有(或特定)元素后再去进行操作, 以前用的方法是通过 setTimeout
循环每隔一段时间检查一下 DOM 是否可以通过 document.querySelector
拿到. 下面分享使用原生的 MutationObserver
接口方式实现, 效率更高. MDN 介绍
The MutationObserver interface provides the ability to watch for changes being made to the DOM tree. It is designed as a replacement for the older Mutation Events feature, which was part of the DOM3 Events specification.
/**
* Wait for an element before resolving a promise
* @param {String} querySelector - Selector of element to wait for
* @param {Integer} timeout - Milliseconds to wait before timing out, or 0 for no timeout
*/
function waitForElement(querySelector, timeout) {
return new Promise((resolve, reject) => {
var timer = false;
if (document.querySelectorAll(querySelector).length) return resolve();
const observer = new MutationObserver(() => {
if (document.querySelectorAll(querySelector).length) {
observer.disconnect();
if (timer !== false) clearTimeout(timer);
return resolve();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
if (timeout) timer = setTimeout(() => {
observer.disconnect();
reject();
}, timeout);
});
}
// Use case
waitForElement(".cards-container", 10000).then(function () {
// ...
})
对于需要持续监测页面元素改变, 从而触发相应动作的场景, 参考下面写法:
// 定义监测触发的具体动作
const observer = new MutationObserver(changedNodes => {
changedNodes.forEach(node => {
console.log(node)
})
});
// 开始监测整个 body 元素
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true
});
这里监测的是所有 body 里面元素发生的所有变化, 如果有具体目标 DOM 也可以缩小监测的范围. 另外这里的动作只是将 changedNodes
即发生变化的节点在控制台进行输出.
MutationObserver()
构造函数接受的是一个 callback 回调函数 MDN 文档, 回调函数中处理的对象是一个 MutationRecord 类型的数组, 对应代码中我写的 changedNodes
, 关于 MutationRecord 类型的属性:
-
MutationRecord.addedNodes
The nodes added by a mutation. Will be an empty NodeList if no nodes were added. -
MutationRecord.attributeName
The name of the changed attribute as a string, or null. -
MutationRecord.removedNodes
The nodes removed by a mutation. Will be an empty NodeList if no nodes were removed. -
MutationRecord.oldValue
The value depends on the MutationRecord.type:- For attributes, it is the value of the changed attribute before the change.
- For characterData, it is the data of the changed node before the change.
- For childList, it is null.
-
MutationRecord.target
The node the mutation affected, depending on the MutationRecord.type.- For attributes, it is the element whose attribute changed.
- For characterData, it is the CharacterData node.
- For childList, it is the node whose children changed.
举个栗子
百度首页的热搜是一个异步加载的列表, 用 MutationObserver 实现对热搜列表的实时监测, 如果内容发生改变的时候打印到 Console.
先确定热搜对应 DOM 的特征, 是放在一个 .hot-news-wrapper
类的 <div></div>
中.
在 Console 中使用这个类名进行选择测试
document.querySelectorAll('.hot-news-wrapper')
观察结果列表中只有一个对象, 确定可以直接用这个类名来定位目标 DOM
在百度首页创建新的 TM 脚本:
// ==UserScript==
// @name Dev-Mutation-test
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://www.baidu.com/
// @icon https://www.google.com/s2/favicons?sz=64&domain=baidu.com
// @grant none
// ==/UserScript==
const observer = new MutationObserver(changedNodes => {
Array.from(changedNodes).forEach(node => {
console.log(node)
})
})
observer.observe(document.querySelector('.hot-news-wrapper'), {
childList: true,
subtree: true,
attributes: true
})
刷新页面, 清空 Console 后点 换一换
观察实时输出的结果:文章来源:https://www.toymoban.com/news/detail-731180.html
文章来源地址https://www.toymoban.com/news/detail-731180.html
到了这里,关于TM/GM 使用 MutationObserver 检查页面元素加载完成的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!