重新连接和断开 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的主要内容,如果未能解决你的问题,请参考以下文章

重新连接和断开 MutationObserver

更改请求标头 SOCKET.IO(无需断开连接和重新连接)

如何从客户端断开和重新连接 socket.io?

Socket.io - 客户端断开连接后手动重新连接

Eclipse 的svn工程和svn服务器断开后怎么重新连接。 这里没有删除svn信息。

realtime.co xRTML 客户端 - 让客户端保持连接,而不是自动断开连接和重新连接