2016-02-09 3 views
8

Этот вопрос является продолжением this. Однако нет необходимости читать предыдущие, я просто даю ссылку заинтересованным читателям.Подключите и отключите MutationObserver

Существует наблюдатель, который будет реагировать на каждый элемент с некоторым классом, как это было предложено @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();, но он также не работает.

ответ

2

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>


UPDATE

В соответствии с просьбой, вышеупомянутый подход положить внутрь моего первого примера в другом (в связи) вопрос. В принципе, это просто внешняя функция для создания наблюдателей.

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>

4

На самом деле вам не нужно использовать несколько экземпляров для наблюдения за несколькими элементами узла DOM.
Вы можете использовать один наблюдатель мутаций для наблюдения за несколькими элементами узла DOM.
Чтобы повторно подключить наблюдателя после его отсоединения, вам не нужно воссоздавать новый экземпляр наблюдателя мутации, вы можете просто просто вызвать метод observe в уже созданном экземпляре, но только после его отсоединения.

disconnect()

Останавливает экземпляр MutationObserver от получения уведомлений о DOM мутаций. До тех пор, пока не будет использован метод observe(), обратный вызов наблюдателя не будет вызван.

Вызов метода observe() на элемент, который уже наблюдается, не окажет никакого влияния на наблюдение. По крайней мере, если вы используете один и тот же экземпляр наблюдателя для наблюдения.

ПРИМЕЧАНИЕ. Добавление наблюдателя к элементу аналогично addEventListener, если вы наблюдаете за элементом несколько раз, это не имеет значения. Значение, если вы дважды наблюдаете за элементом, обратный вызов наблюдения не срабатывает дважды, и вам не придется дважды выполнять отключение(). Другими словами, как только элемент наблюдается, наблюдение его снова с тем же экземпляром наблюдателя ничего не сделает. Однако, если объект обратного вызова отличается, он, конечно, добавит к нему другого наблюдателя.

Вот пример использования одного экземпляра наблюдателя, наблюдающего атрибут width нескольких элементов изображения. В примере используется таймаут для установки случайного значения для каждого атрибута ширины изображения. Функция обратного вызова выводит изменения и отключает наблюдателя, а затем снова запускает весь процесс.

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" width="300"> 
 
<span></span> 
 
<img class="my-images" src="http://placehold.it/300x200?text=image" width="300"> 
 
<span></span> 
 
<img class="my-images" src="http://placehold.it/300x300?text=image" width="300">

Смежные вопросы