admin管理员组

文章数量:1399991

I need to prevent DOM-Change using mutationobserver.

I had (past) the following code to prevent specific changes:

document.bind("DOMSubtreeModified", function() {
   document.find('.Xx.xJ:Contains("wham")').closest("[jsmodel='XNmfOc']").hide();
});

Because of performance reasons I did not want to check the plete document on any dom-change but only added contents so I changed to this (now):

 var observer = new MutationObserver(function (mutations) {
        mutations.forEach(function (mutation) {
            [].slice.call(mutation.addedNodes).forEach(function (addedNode) {
               StartFilter(addedNode);                    

            });
        });
    });

    observer.observe(document, {
        childList: true,
        subtree:true,
        characterData:true,
        attributes:true        
    });

function StartFilter(newNode) {
   $(newNode).find('.Xx.xJ:Contains("wham")').closest("[jsmodel='XNmfOc']").hide();
}

But this does not really work. My guess is that "newNode" is not really a reference to the DOM-Element. (The selector is valid, "$(newNode).find('.Xx.xJ:Contains("wham")').closest("[jsmodel='XNmfOc']")" returns an element).

I did not find any method/property to reject a dom-change in MutationObserver. Is there a way to achieve what I want WITHOUT checking the whole document each time?

I need to prevent DOM-Change using mutationobserver.

I had (past) the following code to prevent specific changes:

document.bind("DOMSubtreeModified", function() {
   document.find('.Xx.xJ:Contains("wham")').closest("[jsmodel='XNmfOc']").hide();
});

Because of performance reasons I did not want to check the plete document on any dom-change but only added contents so I changed to this (now):

 var observer = new MutationObserver(function (mutations) {
        mutations.forEach(function (mutation) {
            [].slice.call(mutation.addedNodes).forEach(function (addedNode) {
               StartFilter(addedNode);                    

            });
        });
    });

    observer.observe(document, {
        childList: true,
        subtree:true,
        characterData:true,
        attributes:true        
    });

function StartFilter(newNode) {
   $(newNode).find('.Xx.xJ:Contains("wham")').closest("[jsmodel='XNmfOc']").hide();
}

But this does not really work. My guess is that "newNode" is not really a reference to the DOM-Element. (The selector is valid, "$(newNode).find('.Xx.xJ:Contains("wham")').closest("[jsmodel='XNmfOc']")" returns an element).

I did not find any method/property to reject a dom-change in MutationObserver. Is there a way to achieve what I want WITHOUT checking the whole document each time?

Share Improve this question edited Oct 30, 2017 at 13:54 Pacerier 89.9k111 gold badges385 silver badges644 bronze badges asked Jan 7, 2015 at 22:32 Ole AlbersOle Albers 9,30513 gold badges82 silver badges179 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

It's unclear to me whether the NodeList returned by a mutation observer is "live", in the sense that changes to nodes in that list are immediately be reflected on the DOM. But that doesn't matter, since you're only using it to create jQuery wrapped set. The basic code you've got above works as intended (see simplified snippet below), which implies that there's something else preventing your hide() call from working as expected.

My best understanding is that you can't intercept and prevent changes to the DOM--the MutationObserver is fired after the associated mutation has already occurred. That means you're not interrupting or intercepting the mutation, but rather reacting to it. In your case, that could lead to unexpected "flashing" behavior as nodes are added and then removed. A better solution in that case would be to style newly-added nodes to be hidden by default, and then add a class/style to either display them or remove them from the DOM in the mutation observer filter.

var container = document.querySelector('.container');
var addNodeButton = document.querySelector('#add');
var addNodeWithHideButton = document.querySelector('#addWithHide');

var makeAddNode = function(includeHide) {
  return function() {
    var p = document.createElement('p');
    var s = document.createElement('span');
    var msg = 'Appended at ' + new Date().getTime();
    if (includeHide) {
      msg += ' (hide)';
    }
    var t = document.createTextNode(msg);
    s.appendChild(t);
    p.appendChild(s);
    container.appendChild(p);
    console.log('appended::', p);
  };
};

var makeNode = makeAddNode(false);
var makeNodeWithHidden = makeAddNode(true);

addNodeButton.addEventListener('click', makeNode);
addNodeWithHideButton.addEventListener('click', makeNodeWithHidden);

var toArray = function() {
  return [].slice.call(arguments);
};

var observer = new MutationObserver(function (mutations) {
  mutations.forEach(function (mutation) {
    toArray(mutation.addedNodes).forEach(function (addedNode) {
      StartFilter(addedNode);
    });
  });
});

observer.observe(document, {
  childList: true,
  subtree:true,
  characterData:true,
  attributes:true
});

function StartFilter(newNode) {
  var $n = $(newNode);
  console.log('$n::', $n);
  $n.find('span:contains(hide)').fadeOut(1500);
  //   $(newNode).find('.Xx.xJ:Contains("wham")').closest("[jsmodel='XNmfOc']").hide();
}
.container {
  width: 80%;
  border: 1px solid green;
  padding: 1rem;
  margin: 1rem auto;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button id="add">Add node without "hide"</button>
<button id="addWithHide">Add node with "hide"</button>
<div class="container"></div>

Since the existing answers lack clarity, here’s a more detailed explanation:

MutationObserver captures DOM changes (mutations) before the paint event occurs, meaning that these changes are observed before the animation frame. This timing is critical because it allows you to intercept and adjust modifications to the DOM before they are rendered on the screen.

With MutationObserver, you can:

  • Observe attribute changes and prevent them from being visually rendered.
  • Re-add removed elements or remove added elements in the DOM, effectively undoing these changes before they bee visible.
  • Rollback other types of mutations, giving you control over visual changes at a fine-grained level.

This behavior enables modifications to be managed or blocked before any visual impact, which can be useful in scenarios where you want to manage DOM stability, limit unwanted changes, or defer heavy layout operations.

For further reading and more on how the paint pipeline works, see the Chromium documentation:
Chromium Paint Stages

Hope this helps clarify!

本文标签: javascriptCan MutationObserver make changes just right before mutationStack Overflow