如果我使用 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>
我有一个观察者,它监听 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>