MutationObserver——监测DOM节点的改变

引言

NGA论坛的默认布局把“魔兽世界”板块放在了“网事杂谈”板块的下面,对于我这种只看WoW板块的人来说有些不方便,那么如何把WoW板块移到上边呢? 按照往常的经验,我们可以用UserScript来修改网页DOM对象,这也许并不是什么难事,于是我就去找“网事杂谈”板块的HTML代码:<span id="indexBlockother2" class="indexblock">...</span>。有了Id就可以像往常一样这么写UserScript了:

var = indexBlockother2 = document.getElementById('indexBlockother2');
indexBlockother2.parentNode.appendChild(indexBlockother2);

然而,把写好的UserScript拉进Tampermonkey运行后发现并没有产生预期的效果,为什么呢?我们发现,页面中indexBlockother2的父级元素indexBlockLeft的子节点并不是加载网页时就存在的,而是由其它js注入的!正因为有这么一个注入node的过程,页面加载后就立即执行的脚本是找不到indexBlockother2的,此时该node还未注入呢。那么我们该如何解决这个异步问题?

简单暴力的方法——setTimeout

既然页面加载完成后立即寻找节点不行,那么我们设置定时等一会儿总行吧。于是有了下面这样的代码。执行脚本后得到了预期的效果。但是用setTimeout来解决Async问题是在太水了吧?于是找了找资料^1,发现了MutationObserver这个Web API。

setTimeout("indexBlockother2.parentNode.appendChild(indexBlockother2)", 3000)

异步问题异步解决——MutationObserver

学习一个新方法,首先肯定先去看其官方文档^2。这是一个HTML5的新特性,它提供了一种能在某个范围内的DOM树发生变化时作出适当反应的能力。按照官方文档的说明,我们需要先找到被观察的目标节点,在本案例中就是indexBlockother2的父节点indexBlockLeft:var target = document.getElementById ("indexBlockLeft");然后是配置被观察节点的行为选项:var config = { attributes: true, childList: true, characterData: true };最后就是写回调函数了,就是原来的操作:indexBlockLeft.appendChild (indexBlockother2)。写完之后,拖进Tampermonkey中运行,it works! 精简后的完整代码:

// 配置观察选项:
var config = { attributes: true, childList: true, characterData: true }
// 创建观察者对象
var observer = new MutationObserver( mutations => {
    indexBlockLeft.appendChild(indexBlockother2);
    observer.disconnect();  //停止观察
});
// 传入目标节点和观察选项
observer.observe(indexBlockLeft, config);