重新连接和断开 MutationObserver
Posted
技术标签:
【中文标题】重新连接和断开 MutationObserver【英文标题】:Reconnect and disconnect a MutationObserver 【发布时间】:2016-05-19 08:43:52 【问题描述】:这个问题是this one 的续集。不过前面的没必要看,我只是给有兴趣的读者提供一个链接。
正如@Shomz 建议的那样,有一个观察者,它将对具有某个类的每个元素做出反应:
var target = document.querySelectorAll(".someclass");
for (var i = 0; i < target.length; i++)
create(target[i]);
function create(t)
var observer = new MutationObserver(function(mutations)
mutations.forEach(function(mutation)
var foo = t.getAttribute("aaa")
if (foo == "vvv")
t.style.backgroundColor = "red";
);
);
var config =
attributes: true
;
observer.observe(t, config);
所以,有两个紧密交织的问题。
1) 由于某些原因,观察者可能会断开连接。我怎样才能重新连接它?我尝试使用observer.observe
,但在这里不起作用。
2)第二个问题,手动断开观察者的方法是什么?我尝试使用observer.disconnect();
,但它也不起作用。
【问题讨论】:
我只是好奇,你有什么理由使用for
循环而不是target.forEach()
吗?
@ViktorBorítás 那是我刚刚开始学习 javascript 的时候。我确定我根本不知道target.forEach()
【参考方案1】:
1) 由于某些原因,观察者可能会断开连接。我怎样才能重新连接它?我尝试使用observer.observe,但在这里不起作用。
2)第二个问题,手动断开观察者的方法是什么?我尝试使用observer.disconnect();,但它也不起作用。
你在正确的轨道上,但问题是你试图在它定义的函数之外使用 observer
变量,这意味着在它的范围之外,所以它不存在(返回未定义)。
查看我更新后的原始代码示例。我已将观察者移动到一个数组中,并使其可以在该函数之外访问,因此您可以正常断开和重新连接它们。
问题只是保留对观察者的引用,就像您保留对目标元素的引用一样。
var msg = document.getElementById('msg');
var target = document.querySelectorAll(".someClass");
// an array of observers
var observers = [];
// configuration of the observer
var config = attributes: true ;
for (var i = 0; i < target.length; i++)
// create an observer instance
observers[i] = new MutationObserver(function(mutations)
mutations.forEach(function(mutation)
var foo = mutation.target.getAttribute("bgColor")
if (foo)
mutation.target.style.backgroundColor = foo;
);
);
// pass in the target node, as well as the observer options
observers[i].observe(target[i], config);
msg.textContent = 'Starting timeouts';
// let's change an attribute in a second
setTimeout(function()
target[2].setAttribute('bgColor', 'red');
msg.textContent = 'Mutation observer should change the box to red';
, 2000);
setTimeout(function()
target[2].setAttribute('bgColor', 'green');
msg.textContent = 'Mutation observer should change the box to green';
, 4000);
setTimeout(function()
observers[2].disconnect();
msg.textContent = 'Mutation observer disconnected';
, 6000);
setTimeout(function()
target[2].setAttribute('bgColor', 'blue');
msg.textContent = 'Mutation observer tries to change the box to blue, but is disconnected';
, 8000);
setTimeout(function()
target[1].setAttribute('bgColor', 'blue');
msg.textContent = 'Let\'s try another box, which is not disconnected, all good';
, 10000);
setTimeout(function()
observers[2].observe(target[2], config);
msg.textContent = 'Mutation observer reconnected';
, 12000);
setTimeout(function()
target[2].setAttribute('bgColor', 'red');
msg.textContent = 'Finally, the reconnected mutation observer should change the box to red';
, 14000);
setTimeout(function()
target[1].setAttribute('bgColor', 'white');
target[2].setAttribute('bgColor', 'white');
msg.textContent = 'Now try the manual controls below';
document.getElementById('ctrl').style.display = 'block';
, 16000);
.someClass
width: 50px;
height: 50px;
display: inline-block;
border: 1px solid black
#ctrl display: none
<div class="someClass"></div>
<div class="someClass"></div>
<div class="someClass"></div>
<div class="someClass"></div>
<p id="msg"></p>
<hr>
<div id="ctrl">
<p>Change attribute:
<button onclick="target[2].setAttribute('bgColor', 'red');">Red</button>
<button onclick="target[2].setAttribute('bgColor', 'green');">Green</button>
<button onclick="target[2].setAttribute('bgColor', 'blue');">Blue</button>
</p><p>Manage the observer
<button onclick="observers[2].disconnect();">Disconnect</button>
<button onclick="observers[2].observe(target[2], config);">Reconnect</button>
</p>
</div>
更新
根据要求,上述方法放在我在另一个(链接)问题中的第一个示例中。基本上,只是一个用于创建观察者的外化函数。
var msg = document.getElementById('msg');
var target = document.querySelectorAll(".c");
// an array of observers
var observers = [];
// configuration of the observer
var config = attributes: true ;
for (var i = 0; i < target.length; i++)
create(target[i], i);
function create(t, i)
// create an observer instance
observers[i] = new MutationObserver(function(mutations)
mutations.forEach(function(mutation)
var foo = t.getAttribute("bgColor")
if (foo)
t.style.backgroundColor = foo;
);
);
// pass in the target node, as well as the observer options
observers[i].observe(t, config);
// let's change an attribute in a second
msg.textContent = 'Starting timeouts';
// let's change an attribute in a second
setTimeout(function()
target[2].setAttribute('bgColor', 'red');
msg.textContent = 'Mutation observer should change the box to red';
, 2000);
setTimeout(function()
target[2].setAttribute('bgColor', 'green');
msg.textContent = 'Mutation observer should change the box to green';
, 4000);
setTimeout(function()
observers[2].disconnect();
msg.textContent = 'Mutation observer disconnected';
, 6000);
setTimeout(function()
target[2].setAttribute('bgColor', 'blue');
msg.textContent = 'Mutation observer tries to change the box to blue, but is disconnected';
, 8000);
setTimeout(function()
target[1].setAttribute('bgColor', 'blue');
msg.textContent = 'Let\'s try another box, which is not disconnected, all good';
, 10000);
setTimeout(function()
observers[2].observe(target[2], config);
msg.textContent = 'Mutation observer reconnected';
, 12000);
setTimeout(function()
target[2].setAttribute('bgColor', 'red');
msg.textContent = 'Finally, the reconnected mutation observer should change the box to red';
, 14000);
setTimeout(function()
target[1].setAttribute('bgColor', 'white');
target[2].setAttribute('bgColor', 'white');
msg.textContent = 'Now try the manual controls below';
document.getElementById('ctrl').style.display = 'block';
, 16000);
.c
width: 50px;
height: 50px;
display: inline-block;
border: 1px solid black
#ctrl display: none
<div class="c"></div>
<div class="c"></div>
<div class="c"></div>
<div class="c"></div>
<p id="msg"></p>
<hr>
<div id="ctrl">
<p>Change attribute:
<button onclick="target[2].setAttribute('bgColor', 'red');">Red</button>
<button onclick="target[2].setAttribute('bgColor', 'green');">Green</button>
<button onclick="target[2].setAttribute('bgColor', 'blue');">Blue</button>
</p><p>Manage the observer
<button onclick="observers[2].disconnect();">Disconnect</button>
<button onclick="observers[2].observe(target[2], config);">Reconnect</button>
</p>
</div>
【讨论】:
【参考方案2】:您实际上不必使用多个实例来观察多个 DOM 节点元素。
您可以使用一个突变观察者来观察多个 DOM 节点元素。
要在断开连接后重新连接观察器,您不必重新创建突变观察器的新实例,您只需在已创建实例上再次调用observe
方法,但必须在断开连接之后。
disconnect()
停止 MutationObserver 实例接收 DOM 突变通知。在再次使用
observe()
方法之前,观察者的回调不会被调用。
对已被观察的元素调用observe() 方法不会对观察产生任何影响。至少如果您使用相同的观察者实例进行观察。
注意:向元素添加观察者就像 addEventListener 一样,如果你多次观察元素并没有什么不同。这意味着如果您观察元素两次,则观察回调不会触发两次,您也不必运行两次 disconnect()。换句话说,一旦一个元素被观察到,用同一个观察者实例再次观察它不会做任何事情。但是,如果回调对象不同,它当然会添加另一个观察者。
这是一个使用观察者实例观察几个图像元素的宽度属性的示例。该示例使用超时为每个图像宽度属性设置随机值。回调函数将输出更改并断开观察者,然后重新开始整个过程。
var imgs = Array.prototype.slice.call( document.images ),
config = attributes: true, attributeOldValue: true ,
observer = new MutationObserver( mutationCallback );
function mutationCallback ( mutations )
mutations.forEach(function( record )
record.target.previousElementSibling.textContent = "";
record.target.previousElementSibling.textContent = "The image "
+ record.attributeName
+ " attribute changed from "
+ record.oldValue
+ " to "
+ record.target.getAttribute('width')
+ ".";
)
observer.disconnect();
startObserving( imgs );
function changeNodeAttr ( attr, nodes )
window.setTimeout(function()
nodes.forEach(function( node )
node.setAttribute( attr, Math.floor( Math.random()*( 300 - 100 + 1 ) +100 ) );
)
, 2500)
function startObserving ( nodes )
nodes.forEach(function( node )
observer.observe( node, config );
)
changeNodeAttr( "width", imgs );
startObserving( imgs );
body
font-family: sans-serif;
img
display: block;
margin-bottom: 10px;
<span></span>
<img class="my-images" src="http://placehold.it/300x100?text=image" >
<span></span>
<img class="my-images" src="http://placehold.it/300x200?text=image" >
<span></span>
<img class="my-images" src="http://placehold.it/300x300?text=image" >
【讨论】:
我不明白接受的答案,但这个答案还可以,太好了! 太棒了。玩得开心。以上是关于重新连接和断开 MutationObserver的主要内容,如果未能解决你的问题,请参考以下文章