单击事件停止MutationOberserver

问题描述

我有一个动态的DOM结构,其中的节点一直都在插入和删除,为了对新节点做出反应,我使用的是MutationObserver,当用户单击Button时它会被激活。每当用户单击该按钮时,MutationObserver将运行两个函数,并且当我观察到的DOM结构发生更改时,这些函数将继续运行。

要做的是一旦用户再次单击按钮就断开MutationObservers(假设是第一次单击,然后对元素进行排序,再次单击并停止对元素进行排序)。每当用户单击按钮时,我都会传递一个布尔值(goSortDom)(如果为true,则执行操作并观察,如果为false,则停止观察)。问题是当goSortDom = false时我尝试断开观察者的连接时,它们将永远不会断开连接,并且功能将继续运行。

我对mutationObservers来说还很陌生,所以我不知道我的做法是否是一种不好的做法,这就是为什么我也将非常欣赏这些建议的原因。

$(document).ready(function () {
  // Function 1: Assign Priorities
  function assignChatPriority(arrayParent) {
     //Assign Priorities
     //Observe if time change,if change re-assign priority to dom node
     timeInQueueDomObserver.observe(
     $(incomingChat).find(".time_cell")[0],configtimeInQueue
  }

  // Function 2: Reorder DOM
  function orderIncomingChats() {
    //Reorder DOM save DOM elements to Array
    //Replace original DOM with new sorted DOM 
  }

  //Declaring DOM Observers for Time in Queue and DOM container dynamics
  var incomingChatsDomObserver = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      if (mutation.addednodes.length) {
        for (let i = 0; i < mutation.addednodes.length; i++) {
          if (
            mutation.addednodes[i].attributes["data-priority"] === undefined
          ) {
            runExtensionFunctions();
          }
        }
      }
    });
  });
  var timeInQueueDomObserver = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      if (
        mutation.addednodes.length === 1 &&
        mutation.addednodes[0].nodeType === Node.TEXT_NODE &&
        mutation.removednodes.length === 1 &&
        mutation.removednodes[0].nodeType === Node.TEXT_NODE
      ) {
        runExtensionFunctions();
      }
    });
  });

  //Obervers Configuration
  let configChatsContainer = {
    childList: true,};
  let configtimeInQueue = {
    childList: true,};
  if (goSortDom) {
    //boolean is true go ahead run functions and observe
    assignChatPriority(incomingChatsRows);
    orderIncomingChats();
    incomingChatsDomObserver.observe(
      incomingChatsContainer[0],configChatsContainer
    );
  } else {
    //disconnect observers: WON'T WORK
    incomingChatsDomObserver.disconnect();
    timeInQueueDomObserver.disconnect();
  }
}

解决方法

您可以在传递给.ready()的此函数中初始化并使用MutationObserver的incomingChatsDomObservertimeInQueueDomObserver。我没有看到外部参考。在这种情况下,if (goSortDom)将只为初始化的MutationObserver评估一次。此后,函数结束并且引用丢失。再次调用该函数将创建 new MutationObserver,并且connect()调用将引用那些新的MutationObserver而不是已经观察到的旧变量!

是否可能要实现的是将MutationObserver的初始化和引用移到此函数之外,并在那里使用它?还是断开自己内部的MutationObservers?

让我尝试一下。由于这不是完整的代码,因此我无法自己对其进行测试:

  1. 想法(移动参考):
// ANSWERER: Now the references are outside the ready function. If the ready function is done,this references still exist. 
  //Declaring DOM Observers for Time in Queue and DOM container dynamics
  var incomingChatsDomObserver = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      if (mutation.addedNodes.length) {
        for (let i = 0; i < mutation.addedNodes.length; i++) {
          if (
            mutation.addedNodes[i].attributes["data-priority"] === undefined
          ) {
            runExtensionFunctions();
          }
        }
      }
    });
  });
  var timeInQueueDomObserver = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      if (
        mutation.addedNodes.length === 1 &&
        mutation.addedNodes[0].nodeType === Node.TEXT_NODE &&
        mutation.removedNodes.length === 1 &&
        mutation.removedNodes[0].nodeType === Node.TEXT_NODE
      ) {
        runExtensionFunctions();
      }
    });
  });

// ANSWERER: This is now possible  
function disconnectObservers() {
    incomingChatsDomObserver.disconnect();
    timeInQueueDomObserver.disconnect();
}

$(document).ready(function () {
  // Function 1: Assign Priorities
  function assignChatPriority(arrayParent) {
     //Assign Priorities
     //Observe if time change,if change re-assign priority to dom node
     timeInQueueDomObserver.observe(
     $(incomingChat).find(".time_cell")[0],configtimeInQueue
  }

  // Function 2: Reorder DOM
  function orderIncomingChats() {
    //Reorder DOM save DOM elements to Array
    //Replace original DOM with new sorted DOM 
  }


  //Obervers Configuration
  let configChatsContainer = {
    childList: true,};
  let configtimeInQueue = {
    childList: true,};
  if (goSortDom) {
    //boolean is true go ahead run functions and observe
    assignChatPriority(incomingChatsRows);
    orderIncomingChats();
    incomingChatsDomObserver.observe(
      incomingChatsContainer[0],configChatsContainer
    );
  } else {
    //disconnect observers: WON'T WORK
    incomingChatsDomObserver.disconnect();
    timeInQueueDomObserver.disconnect();
  }
}

  1. 版本。 MutationObserver断开自己的连接:
$(document).ready(function () {
  // Function 1: Assign Priorities
  function assignChatPriority(arrayParent) {
     //Assign Priorities
     //Observe if time change,configtimeInQueue
  }

  // Function 2: Reorder DOM
  function orderIncomingChats() {
    //Reorder DOM save DOM elements to Array
    //Replace original DOM with new sorted DOM 
  }

  //Declaring DOM Observers for Time in Queue and DOM container dynamics
  var incomingChatsDomObserver = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      if (mutation.addedNodes.length) {
        for (let i = 0; i < mutation.addedNodes.length; i++) {
          if (
            mutation.addedNodes[i].attributes["data-priority"] === undefined
          ) {
            runExtensionFunctions();
          }
        }
      }
    });
    // ANSWERER: Now the observer disconnects itself after the run. Remember: MutationObserver's disconnect itself from *everywhere*
    incomingChatsDomObserver.disconnect();
  });
  var timeInQueueDomObserver = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      if (
        mutation.addedNodes.length === 1 &&
        mutation.addedNodes[0].nodeType === Node.TEXT_NODE &&
        mutation.removedNodes.length === 1 &&
        mutation.removedNodes[0].nodeType === Node.TEXT_NODE
      ) {
        runExtensionFunctions();
      }
    });
    // ANSWERER: Now the observer disconnects itself after the run. Remember: MutationObserver's disconnect itself from *everywhere*
    timeInQueueDomObserver.disconnect();
  });

  //Obervers Configuration
  let configChatsContainer = {
    childList: true,configChatsContainer
    );
  } else {
    //disconnect observers: WON'T WORK
    incomingChatsDomObserver.disconnect();
    timeInQueueDomObserver.disconnect();
  }
}

或者,看下面。 MutationObserver绑定到了按钮对象,因此单击按钮总是引用曾经初始化的MutationObserver。这样,它们可以断开连接并重新连接(尝试在浏览器中更改div#changes):

<html>
<body>
    <button id="somebutton">bla</button>
    <div id="changes"></div>
    <script>
        document.querySelector("#somebutton").addEventListener("click",function () {
            if (!this.incomingChatsDomObserver) {
                this.incomingChatsDomObserver = new MutationObserver(function (mutations) {
                    console.log("incomingChatsDomObserver",mutations);
                });
            }

            if (!this.timeInQueueDomObserver) {
                this.timeInQueueDomObserver = new MutationObserver(function (mutations) {
                    console.log("timeInQueueDomObserver",mutations);
                });
            }

            if (this.observing) {
                this.observing = false;
                this.incomingChatsDomObserver.disconnect();
                this.timeInQueueDomObserver.disconnect();
                this.innerText = "inactive";
            } else {
                this.observing = true;
                const changingDiv = document.querySelector("#changes");
                this.incomingChatsDomObserver.observe(changingDiv,{ attributes: true });
                this.timeInQueueDomObserver.observe(changingDiv,{ attributes: true });
                this.innerText = "active";
            }
        });
    </script>
</body>
</html>
,

您的代码似乎无法识别(goSortDom)click事件。您是否尝试过将代码字符串添加到按钮单击事件中? Vue.js框架可能非常适合您的需求。除此之外,我只能告诉你的是同一件事。当dom元素动态更改时,JavaScript的行为非常奇怪。我有一个应用程序,它根据以前的选择加载了指数级的选择。每次加载新信息时,我都必须特别注意用于操纵数据的选择器。否则,无论Id或类选择器如何,JS都无法对新导入的数据起作用。我还必须使用.on(events [,选择器] [,data])Javascript函数而不是.click()jquery函数来完成工作。具体确保选择器信息已填写。
$("#myDiv").on('click','.MyDivClass',function(){'Select All and return information'};