【问题标题】:jQuery Event : Detect changes to the html/text of a divjQuery 事件:检测对 div 的 html/文本的更改
【发布时间】:2013-03-17 11:10:06
【问题描述】:

我有一个 div,它的内容一直在变化,ajax requestsjquery functionsblur 等等。

有没有一种方法可以在任何时间点检测到我的 div 上的任何变化?

我不想使用任何间隔或检查的默认值。

这样就可以了

$('mydiv').contentchanged() {
 alert('changed')
}

【问题讨论】:

  • @Rob 这将keypress 事件绑定到可编辑的<div> 元素。我不确定那里的解决方案是否适用于此。他们绝对不会对元素的内容进行任何程序化更改。

标签: jquery jquery-ui


【解决方案1】:

如果你不想使用计时器并检查innerHTML,你可以试试这个事件

$('mydiv').on('DOMSubtreeModified', function(){
  console.log('changed');
});

更多细节和浏览器支持数据是Here

【讨论】:

  • Mozilla 33:陷入元素 的递归。需要另辟蹊径
  • 这很严重不要使用这个事件它会崩溃你所有的工作因为它一直被解雇。而是使用下面的事件 $('.myDiv').bind('DOMNodeInserted DOMNodeRemoved', function() { });
  • 对于那些寻找非折旧答案的人:Scroll down
  • @IsaiyavanBabuKaran 请问您有什么解决方案来复制与未弃用的答案完全相同的代码?
【解决方案2】:

使用 JavaScript MutationObserver:

// Select the target node.
var target = document.querySelector('mydiv')

// Create an observer instance.
var observer = new MutationObserver(function(mutations) {
    console.log(target.innerText);   
});

// Pass in the target node, as well as the observer options.
observer.observe(target, {
    attributes:    true,
    childList:     true,
    characterData: true
});

详见 MDN 文档;这应该是work in pretty much all current browser,包括IE11。

【讨论】:

  • 这是正确的答案,因为现在这比使用 DOMSubtreeModified 更受欢迎
  • 即使我给出了正确的选择器,我也遇到了错误。 “VM21504:819 未捕获的类型错误:无法在‘MutationObserver’上执行‘观察’:参数 1 不是‘节点’类型。”
  • @samir 找不到您选择的元素时出现错误。当您的代码执行时,您尝试观察的元素可能不存在。 This answer很有用
  • 我将在此处进行此 sn-p。 HTMLElement.prototype.onDOMSubtreeModified = function(c, o = {attributes: true, childList: true, characterData: true}){return new MutationObserver((m) => {c.call(this, m);}).observe(this, o);};
【解决方案3】:

Since $("#selector").bind() is deprecated,你应该使用:

$("body").on('DOMSubtreeModified', "#selector", function() {
    // code here
});

【讨论】:

  • 这是区别因素,附加的# 表示符号必须位于选择器之前。
  • 它确实有效。Changin #selector for #mydiv 成功了,谢谢
【解决方案4】:

你可以试试这个

$('.myDiv').bind('DOMNodeInserted DOMNodeRemoved', function() {

});

但这可能无法在 Internet Explorer 中使用,尚未测试过

【讨论】:

  • 注意!:如果您将其用作触发器并且对页面进行了很多更改 - 它将运行您的函数 X 次(甚至可能 X=1,000 或更多),这可能非常效率低下。一个简单的解决方案是定义一个“正在运行”的布尔变量,它将... if(running == true){return} ...如果您的代码已经在运行,则无需运行它。在 if 逻辑之后设置 running=true,在函数退出之前设置 running=false。您还可以使用计时器将您的功能限制为只能每 X 秒运行一次。运行=真; setTimeout(function(){running=false},5000); (或更好的东西)
  • 我在一个选择框上使用了它,该框有添加和删除的选项。添加项目时效果很好,但删除似乎落后了 1 个项目。当最后一个选项被删除时,它不会触发。
  • @JxAxMxIxN 您还可以通过再次清除和设置超时来增加超时计时器:clearTimeout(window.something); window.something = setTimeout(...);
  • 同意 - 你的方式就是要走的路 - 自从学习 Python 以来,我已经清除了许多跨多种语言的糟糕编码实践(不是全部,只是很多;)
【解决方案5】:

您正在寻找MutationObserverMutation Events。既不受任何地方的支持,也不受开发者世界的喜爱。

如果您知道(并且可以确保)div 的大小会发生变化,您可以使用crossbrowser resize event

【讨论】:

【解决方案6】:

以下代码适用于我:

$("body").on('DOMSubtreeModified', "mydiv", function() {
    alert('changed');
});

【讨论】:

  • 这与@Artley 的答案相同
  • @Black 谢谢!我刚刚检查了Artley的答案。下次我会处理的。
【解决方案7】:

这个问题没有内置的解决方案,这是你的设计和编码模式的问题。

您可以使用发布者/订阅者模式。为此,您可以使用 jQuery 自定义事件或您自己的事件机制。

首先,

function changeHtml(selector, html) {
    var elem = $(selector);
    jQuery.event.trigger('htmlchanging', { elements: elem, content: { current: elem.html(), pending: html} });
    elem.html(html);
    jQuery.event.trigger('htmlchanged', { elements: elem, content: html });
}

现在您可以订阅 divhtmlchanged/divhtmlchanged 事件,如下所示,

$(document).bind('htmlchanging', function (e, data) {
    //your before changing html, logic goes here
});

$(document).bind('htmlchanged', function (e, data) {
    //your after changed html, logic goes here
});

现在,您必须通过此changeHtml() 函数更改您的 div 内容更改。因此,您可以监视或可以相应地进行必要的更改,因为绑定包含信息的回调数据参数。

你必须像这样改变你的 div 的 html;

changeHtml('#mydiv', '<p>test content</p>');

此外,您可以将它用于除输入元素之外的任何 html 元素。无论如何,您可以修改它以与任何元素一起使用。

【讨论】:

  • 要观察和处理对特定元素的更改,只需修改 changeHtml 函数以使用 'elem.trigger(...)' 而不是 'jQuery.event.trigger(...)' , 然后绑定到像 $('#my_element_id').on('htmlchanged', function(e, data) {...} 这样的元素
  • “这是您的设计和编码模式的问题”,如果您包含第三方脚本因此无法控制其源代码怎么办?但是您需要检测它们对一个 div 的更改?
  • @DrLightman 的经验法则是选择提供回调事件的第三方库
【解决方案8】:

使用MutationObserver,如Mozilla提供的这个sn-p中所见,改编自this blog post

或者,您可以使用 JQuery 示例seen in this link

Chrome 18+、Firefox 14+、IE 11+、Safari 6+

// Select the node that will be observed for mutations
var targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true };

// Callback function to execute when mutations are observed
var callback = function(mutationsList) {
    for(var mutation of mutationsList) {
        if (mutation.type == 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type == 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Later, you can stop observing
observer.disconnect();

【讨论】:

    【解决方案9】:

    尝试了上面给出的一些答案,但那些触发事件两次。如果您可能需要,这里是可行的解决方案。

    $('mydiv').one('DOMSubtreeModified', function(){
        console.log('changed');
    });
    

    【讨论】:

      【解决方案10】:

      您可以将 div 的旧 innerHTML 存储在变量中。设置间隔以检查旧内容是否与当前内容匹配。当这不是真的时,做点什么。

      【讨论】:

        【解决方案11】:

        试试 MutationObserver:

        浏览器支持:http://caniuse.com/#feat=mutationobserver

        <html>
          <!-- example from Microsoft https://developer.microsoft.com/en-us/microsoft-edge/platform/documentation/dev-guide/dom/mutation-observers/ -->
        
          <head>
            </head>
          <body>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
            <script type="text/javascript">
              // Inspect the array of MutationRecord objects to identify the nature of the change
        function mutationObjectCallback(mutationRecordsList) {
          console.log("mutationObjectCallback invoked.");
        
          mutationRecordsList.forEach(function(mutationRecord) {
            console.log("Type of mutation: " + mutationRecord.type);
            if ("attributes" === mutationRecord.type) {
              console.log("Old attribute value: " + mutationRecord.oldValue);
            }
          });
        }
              
        // Create an observer object and assign a callback function
        var observerObject = new MutationObserver(mutationObjectCallback);
        
              // the target to watch, this could be #yourUniqueDiv 
              // we use the body to watch for changes
        var targetObject = document.body; 
              
        // Register the target node to observe and specify which DOM changes to watch
              
              
        observerObject.observe(targetObject, { 
          attributes: true,
          attributeFilter: ["id", "dir"],
          attributeOldValue: true,
          childList: true
        });
        
        // This will invoke the mutationObjectCallback function (but only after all script in this
        // scope has run). For now, it simply queues a MutationRecord object with the change information
        targetObject.appendChild(document.createElement('div'));
        
        // Now a second MutationRecord object will be added, this time for an attribute change
        targetObject.dir = 'rtl';
        
        
              </script>
            </body>
          </html>

        【讨论】:

          【解决方案12】:

          DOMSubtreeModified 不是一个好的解决方案。如果您决定更改事件处理程序中的 DOM,它可能会导致 无限循环,因此它已在许多浏览器中被禁用。 MutationObserver 是更好的答案。

          MDN Doc

          const onChangeElement = (qSelector, cb)=>{
           const targetNode = document.querySelector(qSelector);
           if(targetNode){
              const config = { attributes: true, childList: false, subtree: false };
              const callback = function(mutationsList, observer) {
                  cb($(qSelector))
              };
              const observer = new MutationObserver(callback);
              observer.observe(targetNode, config);
           }else {
              console.error("onChangeElement: Invalid Selector")
           }
          }
          

          你可以像这样使用它,

          onChangeElement('mydiv', function(jqueryElement){
             alert('changed')
          })
          

          【讨论】:

            【解决方案13】:

            向 div 添加一些内容,无论是通过 jQuery 还是直接通过 de DOM-API,默认为 .appendChild() 函数。你可以做的是覆盖当前对象的.appendChild()函数,并在其中实现一个观察者。现在已经覆盖了我们的.appendChild() 函数,我们需要从另一个对象借用该函数才能附加内容。因此,我们调用另一个 div 的 .appendChild() 来最终附加内容。当然,这也适用于.removeChild()

            var obj = document.getElementById("mydiv");
                obj.appendChild = function(node) {
                    alert("changed!");
            
                    // call the .appendChild() function of some other div
                    // and pass the current (this) to let the function affect it.
                    document.createElement("div").appendChild.call(this, node);
                    }
                };
            

            在这里你可以找到一个简单的例子。我猜你可以自己扩展它。 http://jsfiddle.net/RKLmA/31/

            顺便说一句:这表明 JavaScript 符合 OpenClosed 原则。 :)

            【讨论】:

            • 它不适用于append child...我实际上是通过其他功能修改它的html。
            • 像 removeChild() replaceChild() 等。但你在 innerHTML 上是对的。你应该以某种方式避免它。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-10-09
            • 1970-01-01
            • 1970-01-01
            • 2010-11-09
            • 2012-04-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多