开发者

is there an alternative to DOMAttrModified that will work in webkit

开发者 https://www.devze.com 2022-12-13 14:26 出处:网络
I need to leverage this DOM event. I开发者_Python百科E has onpropertychange, which does what I need it to do also. Webkit doesn\'t seem to support this event, however. Is there an alternative I could

I need to leverage this DOM event. I开发者_Python百科E has onpropertychange, which does what I need it to do also. Webkit doesn't seem to support this event, however. Is there an alternative I could use?


Although Chrome does not dispatch DOMAttrModified events, the more lightweighted mutation observers are supported since 2011 and these work for attribute changes, too.

Here is an example for the document body:

var element = document.body, bubbles = false;

var observer = new WebKitMutationObserver(function (mutations) {
  mutations.forEach(attrModified);
});
observer.observe(element, { attributes: true, subtree: bubbles });

function attrModified(mutation) {
  var name = mutation.attributeName,
    newValue = mutation.target.getAttribute(name),
    oldValue = mutation.oldValue;

  console.log(name, newValue, oldValue);
}

For a simple attribute change, the console.log statement would print:

<body color="black">
<script type="text/html">
document.body.setAttribute("color", "red");
</script>
</body>

Console:

> color red black


If you are happy with merely detecting calls to setAttribute() (as opposed to monitoring all attribute modifications) then you could over-ride that method on all elements with:

Element.prototype._setAttribute = Element.prototype.setAttribute
Element.prototype.setAttribute = function(name, val) { 
 var e = document.createEvent("MutationEvents"); 
 var prev = this.getAttribute(name); 
 this._setAttribute(name, val);
 e.initMutationEvent("DOMAttrModified", true, true, null, prev, val, name, 2);
 this.dispatchEvent(e);
}


I had the same question and was thinking of modifying setAttribute, so seeing what Sean did, I copied that. Worked great, except that it was firing when an attribute was repeatedly set to the same value, so I added a check to my copy to skip firing the event if the value is not being changed. I also added val = String(val), based on the rationale that setAttribute will coerce numbers to strings, so the comparison should anticipate that.

My modified version is:

var emulateDOMAttrModified = {

  isSupportedNatively: function () {
    var supported = false;
    function handler() {
      supported = true;
    }
    document.addEventListener('DOMAttrModified', handler);
    var attr = 'emulateDOMAttrModifiedTEST';
    document.body.setAttribute(attr, 'foo'); // aka $('body').attr(attr, 'foo');
    document.removeEventListener('DOMAttrModified', handler);
    document.body.removeAttribute(attr);
    return supported;
  },

  install: function () {
    if (!this.isSupportedNatively() &&
      !Element.prototype._setAttribute_before_emulateDOMAttrModified) {
      Element.prototype._setAttribute_before_emulateDOMAttrModified = Element.prototype.setAttribute
      Element.prototype.setAttribute = function(name, val) {
        var prev = this.getAttribute(name);
        val = String(val); /* since attributes do type coercion to strings,
           do type coercion here too; in particular, D3 animations set x and y to a number. */
        if (prev !== val) {
          this._setAttribute_before_emulateDOMAttrModified(name, val);
          var e = document.createEvent('MutationEvents');
          e.initMutationEvent('DOMAttrModified', true, true, null, prev, val, name, 2);
          this.dispatchEvent(e);
        }
      };
    }
  }

};

// Install this when loaded.  No other file needs to reference this; it will just make Chrome and Safari
// support the standard same as Firefox does.
emulateDOMAttrModified.install();


Please refer code: https://github.com/meetselva/attrchange/blob/master/attrchange.js 'DOMAttrModified' + ('propertychange' for IE) are used there like in your case. If it's not suitable for you, the "ugly" solution that can satisfy this demand should be setInterval(function(){}, delay) Otherwise see Sean Hogan post above.


The solution provided by @Filip is close (and may have worked at the time) but now you need to request delivery of the old attribute value.

Thus, you'll want to change :

observer.observe(element, { attributes: true, subtree: bubbles });

to this:

observer.observe(element, { attributes: true, attributeOldvalue:true, subtree: bubbles });

Otherwise, you won't see the oldValues (you'll get null instead.) This was tested in Chrome 34.0.1847.131 (Official Build 265687) m.

0

精彩评论

暂无评论...
验证码 换一张
取 消