firing event on DOM attribute change

2018-12-31 20:45发布

问题:

is there any way to trigger event (may be custom) on attribute change?

Let\'s say, when IMG src is changed or DIV\'s innerHtml?

回答1:

Note: As of 2012, Mutation Events have been removed from the standard and are now deprecated. See other answers or documentation for how to use their replacement, MutationObserver.

You are referring to DOM Mutation Events. There is poor (but improving) browser support for these events. Mutation Events plugin for jQuery might get you some of the way.



回答2:

How to setup a MutationObserver, mostly copied from MDN but I\'ve added my own comments for clarity.

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();

Hope this helps.



回答3:

If you only need something specific then a simple setInterval() will work, by checking the target attribute(s) every few milliseconds:

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

Then bind to the custom \"srcChange\" event:

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


回答4:

There is no native dom changed event you can hook into.

Good article here which tries to provide a solution in the form of a jquery plugin.

Code from article

$.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);
        }
    } }


回答5:

In addition to Mats\' answer inspired by MDN\'s MutationObserver Example usage:

If your options contain <property>: true and you plan to change this property of target inside MutationObserver\'s callback function, use the following to prevent recursive calls – until script timeout, stack overflow or the like:

...
// 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);
...