如果我使用 setAttribute,MutationObserver 会挂起
MutationObserver hangs if I use setAttribute
我有一个观察者,它会监听listitem
div属性的任何变化,如果属性发生变化,它会将该div的背景颜色设置为红色。
实际上,您可以自己轻松测试它。打开Chrome的书签管理器,在控制台中启动此脚本,然后单击任何书签或文件夹。它将被涂成红色。
问题在代码块的中间提到:如果我使用 setAttribute
,脚本将被挂起。
第一种方法(使用 style.attributeName
)不适合我,因为在我的实际代码中,我使用自定义属性,而不是 background-color
。
这个问题看起来很奇怪。它可以通过什么方式解决?
<div role="listitem"></div>
<div role="listitem"></div>
<div role="listitem"></div>
<script>
var target = document.querySelectorAll("[role='listitem']");
for (var i = 0; i < target.length; i++) {
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// The Problem
// ===========
// This work well
mutation.target.style.backgroundColor = "red";
// But this doesn't
// mutation.target.setAttribute("style", "background-color: red;");
});
});
// configuration of the observer
var config = { attributes: true };
// pass in the target node, as well as the observer options
observer.observe(target[i], config);
}
</script>
您通过更改属性来响应每个属性更改。这会导致问题也就不足为奇了:你会让观察者再次开火。显然,即使您设置了相同的值,setAttribute
也会更新属性对象(我认为这并非不合理,尽管有点令人惊讶)。
相反,我只会在它确实需要更改时才设置它:
if (mutation.target.getAttribute("yourattr") != targetvalue) {
mutation.target.setAttribute("yourattr", targetvalue);
}
我已经检查过将属性设置为相同值是否会再次触发观察者(无论如何,在 Chrome 上):
var target = document.getElementById("target");
var counter = 0;
var observer = new MutationObserver(function() {
++counter;
console.log(Date.now() + ": " + counter);
if (counter < 10) {
console.log("Inside handler: Setting data-foo to bar");
target.setAttribute("data-foo", "bar");
} else {
console.log("Inside handler: Stopped, to avoid looping forever");
}
});
observer.observe(target, {attributes: true});
console.log("Initial change: Setting data-something-else to testing");
target.setAttribute("data-something-else", "testing");
<div id="target"></div>
因此,首先检查可以防止这种情况发生:
var target = document.getElementById("target");
var observer = new MutationObserver(function() {
console.log(Date.now() + ": In handler");
if (target.getAttribute("data-foo") != "bar") {
console.log("Inside handler: Setting data-foo to bar");
target.setAttribute("data-foo", "bar");
} else {
console.log("Inside handler: No need to set it, it's already set");
}
});
observer.observe(target, {attributes: true});
console.log("Initial change: Setting data-something-else to testing");
target.setAttribute("data-something-else", "testing");
<div id="target"></div>
相关文章:
- 没有找到相关文章