最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Reconnect and disconnect a MutationObserver - Stack Overflow

programmeradmin5浏览0评论

This question is the sequel of this one. However, it is not necessary to read the previous, I'm just giving a link for interested readers.

There is an observer, which will react on every element with some class, as @Shomz suggested:

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);
}

So, there are two closely intertwined questions.

1) For some reasons, the observer may be disconnected. How I can reconnect it? I tried to use observer.observe, but it doesn't work here.

2) And the second question, what is the way to manually disconnect an observer? I tried to use observer.disconnect();, but it is also doesn't work.

This question is the sequel of this one. However, it is not necessary to read the previous, I'm just giving a link for interested readers.

There is an observer, which will react on every element with some class, as @Shomz suggested:

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);
}

So, there are two closely intertwined questions.

1) For some reasons, the observer may be disconnected. How I can reconnect it? I tried to use observer.observe, but it doesn't work here.

2) And the second question, what is the way to manually disconnect an observer? I tried to use observer.disconnect();, but it is also doesn't work.

Share Improve this question edited May 23, 2017 at 10:29 CommunityBot 11 silver badge asked Feb 9, 2016 at 11:23 john c. j.john c. j. 1,1755 gold badges36 silver badges91 bronze badges 2
  • I'm just curious, is there any reason that you use a for loop instead of target.forEach() ? – Viktor Borítás Commented Dec 22, 2021 at 1:17
  • @ViktorBorítás It was the time when I just started to leard JavaScript. I'm sure that I simply didn't know about target.forEach() – john c. j. Commented Dec 26, 2021 at 2:10
Add a comment  | 

2 Answers 2

Reset to default 14

You actually do not have to use several instances to observe more than one DOM node element.
You can use one mutation observer to observe several DOM node elements.
To reconnect the observer after it has been disconnected you do not have to recreate a new instance of the mutation observer, you can just simply call the observe method on the already create instance again, but only after it has been disconnected.

disconnect()

Stops the MutationObserver instance from receiving notifications of DOM mutations. Until the observe() method is used again, observer's callback will not be invoked.

Calling the observe() method on an element that is already being observed will not have any effect on the observation. At least if you are using the same observer instance for the observation.

NOTE: Adding an observer to an element is just like addEventListener, if you observe the element multiple times it does not make a difference. Meaning if you observe element twice, the observe callback does not fire twice, nor will you have to run disconnect() twice. In other words, once an element is observed, observing it again with the same observer instance will do nothing. However if the callback object is different it will of course add another observer to it.

Here is an example using one observer instance observing the width attribute of a few image elements. The example is using a timeout to set a random value for each image width attribute. The callback function will output the changes and disconnect the observer and then start the whole process over again.

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="https://via.placeholder.com/300x100?text=image" width="300">
<span></span>
<img class="my-images" src="https://via.placeholder.com/300x200?text=image" width="300">
<span></span>
<img class="my-images" src="https://via.placeholder.com/300x400?text=image" width="300">

1) For some reasons, the observer may be disconnected. How I can reconnect it? I tried to use observer.observe, but it doesn't work here.

2) And the second question, what is the way to manually disconnect an observer? I tried to use observer.disconnect();, but it is also doesn't work.

You are on the right track, but the thing is you're trying to use the observer variable outside of the function it's defined in, meaning outside of its scope, so it doesn't exist (returns undefined).

See my updated example of your original code. I've moved the observers into an array and made it accessible outside of that function, so you can disconnect and reconnect them normally.

The issue was just keeping references to observers, just like you were keeping references to the target elements.

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>


UPDATE

As requested, the above approach put inside my first example in the other (linked) question. Basically, just an externalized function for creating observers.

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>

发布评论

评论列表(0)

  1. 暂无评论