在DOM属性更改上触发事件

时间:2010-12-30 10:29:45

标签: javascript jquery events dom javascript-events

有没有办法在属性更改时触发事件(可能是自定义)?

让我们说,当IMG src被更改或DIV的innerHtml?

6 个答案:

答案 0 :(得分:50)

注意:截至2012年,Mutation Events已从标准中删除,现已弃用。请参阅其他答案或文档,了解如何使用替代品MutationObserver

您指的是DOM Mutation Events。这些事件的浏览器支持很差(但正在改进)。 Mutation Events plugin for jQuery可能会帮助你。

答案 1 :(得分:38)

如何设置MutationObserver,主要是从MDN复制的,但为了清晰起见,我添加了自己的评论。

window.MutationObserver = window.MutationObserver
    || window.WebKitMutationObserver
    || window.MozMutationObserver;
// Find the element that you want to "watch"
var target = document.querySelector('img'),
// create an observer instance
observer = new MutationObserver(function(mutation) {
     /** this is the callback where you
         do what you need to do.
         The argument is an array of MutationRecords where the affected attribute is
         named "attributeName". There is a few other properties in a record
         but I'll let you work it out yourself.
      **/
}),
// configuration of the observer:
config = {
    attributes: true // this is to watch for attribute changes.
};
// pass in the element you wanna watch as well as the options
observer.observe(target, config);
// later, you can stop observing
// observer.disconnect();

希望这有帮助。

答案 2 :(得分:5)

如果你只需要一些特定的东西,那么一个简单的setInterval()将起作用,通过每隔几毫秒检查一次目标属性:

var imgSrc = null;
setInterval(function () {
   var newImgSrc = $("#myImg").attr("src");
   if (newImgSrc !== imgSrc) {
      imgSrc = newImgSrc;
      $("#myImg").trigger("srcChange");
   }
}, 50);

然后绑定到自定义“srcChange”事件:

$("#myImg").bind("srcChange", function () {....});

答案 3 :(得分:4)

没有可以挂钩的本地dom更改事件。

好文章here试图以jquery插件的形式提供解决方案。

文章中的代码

$.fn.watch = function(props, callback, timeout){
    if(!timeout)
        timeout = 10;
    return this.each(function(){
        var el      = $(this),
            func    = function(){ __check.call(this, el) },
            data    = { props:  props.split(","),
                        func:   callback,
                        vals:   [] };
        $.each(data.props, function(i) {
              data.vals[i] = el.css(data.props[i]); 
        });
        el.data(data);
        if (typeof (this.onpropertychange) == "object"){
            el.bind("propertychange", callback);
        } else if ($.browser.mozilla){
            el.bind("DOMAttrModified", callback);
        } else {
            setInterval(func, timeout);
        }
    });
    function __check(el) {
        var data    = el.data(),
            changed = false,
            temp    = "";
        for(var i=0;i < data.props.length; i++) {
            temp = el.css(data.props[i]);
            if(data.vals[i] != temp){
                data.vals[i] = temp;
                changed = true;
                break;
            }
        }
        if(changed && data.func) {
            data.func.call(el, data);
        }
    } }

答案 4 :(得分:0)

Mats' answer启发MDN's MutationObserver Example usage之外:

如果您的选项包含<property>: true,并且您打算在MutationObserver的回调函数中更改 target 的此属性,请使用以下命令防止递归调用 - 直到脚本超时,堆栈溢出等:

...
// Used to prevent recursive calls of observer's callback function
// From https://stackoverflow.com/questions/4561845/firing-event-on-dom-attribute-change
let insideInitialObserverCallback = false

let callback = function(mutationsList) {
    insideInitialObserverCallback = ! insideInitialObserverCallback
    if ( insideInitialObserverCallback ) {

        // ... change target's given property ...       

    }
})

let observer = new MutationObserver(callback);
...

答案 5 :(得分:0)

我遇到了同样的问题,我必须找到某些特定DOM元素的track属性更改。我使用了MutationObserver。

但是在使用MutationObserver时,我还面临着另一种复杂性。 MutationObserver在观察变化时需要一些目标元素。

在使用SPA(使用AJAX,Angular,react或任何其他JavaScript框架)时,您可能已经意识到所有元素都是动态的。 那将很难设定目标。

这里提供了一些解决方案,其中我在DOM上应用了MutationObserver,然后在任何元素的某些属性发生更改时发出了customEvent。

然后按照我们的要求在下一步中过滤自定义事件。

 // code to change image src in each 1000ms.
        count = 0;
        setInterval(function() {
            dimension = `${600+count}x${400+count}`;
            document.querySelector('div.image-box img').src = `https://dummyimage.com/${dimension}/000/fff`;
            document.querySelector('div.image-box img').alt = dimension;
            count++;
        }, 1000);

        function startMutationObserver(tNode, c) {
            // Select the node that will be observed for mutations
            const targetNode = tNode ? tNode : document;

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

            // Callback function to execute when mutations are observed
            const callback = function(mutationsList, observer) {
                for (let mutation of mutationsList) {
                    if (mutation.type === 'childList') {
                        targetNode.dispatchEvent(new CustomEvent('newChild', {
                            detail: mutation
                        }));
                    } else if (mutation.type === 'attributes') {
                        targetNode.dispatchEvent(new CustomEvent('attributeChange', {
                            detail: mutation
                        }));
                    }
                }
            };

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

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

            // Later, you can stop observing
            // observer.disconnect();
        }
        // call this function to start observing DOM element change
        startMutationObserver(document);

        // code to listen custom event and filter custom event as per requirement
        document.addEventListener('attributeChange', function(e) {
            // console.log(e);
            const ele = e.detail;

            if (ele.target.matches('div.image-box img') && ele.attributeName == 'src') {

                var src = e.detail.target.getAttribute('src');
                var alt = e.detail.target.getAttribute('alt');
                console.log(src, alt);

            }
        })
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div class="image-box">
        <img src="https://dummyimage.com/600x400/000/fff" alt="600x400">
    </div>

</body>

</html>

我希望这将帮助您跟踪任何属性更改,还可以插入新元素。 让我们尝试一下,让我知道您是否遇到任何问题。