2009-12-10 4 views
21

J'ai besoin de tirer parti de cet événement DOM. IE a onpropertychange, qui fait ce que j'ai besoin de faire aussi. Cependant, Webkit ne semble pas supporter cet événement. Y a-t-il une alternative que je pourrais utiliser?est-il une alternative à DOMAttrModified qui fonctionnera dans webkit

+0

j'ai pu trouver quelque chose à partir de cette [http://www.west-wind.com/Weblog/posts/453942.aspx](http: //www.west-wind.com/Weblog/posts/453942.aspx) – blockhead

+0

Basé sur la [solution par David Walsh] (http://davidwalsh.name/detect-node-insertion) J'ai créé une petite bibliothèque à attraper les insertions DOM. Si vous pouvez écrire un sélecteur CSS correspondant à l'élément après le changement qui vous intéresse, il s'agit d'une solution valide. Il couvre plus de navigateurs que DOM Mutation Observers. Voir: https: // github.com/naugtur/insertionQuery – naugtur

Répondre

24

Bien que Chrome ne distribue pas DOMAttrModified événements , les observateurs de mutation les plus légers sont pris en charge depuis 2011 et ceux-ci travaillent aussi pour les changements d'attributs.

Voici un exemple pour le corps du document:

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

Pour un simple changement d'attribut, la déclaration console.log imprimera:

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

Console:

> color red black

+2

Il semble que cela ne fonctionne pas actuellement en combinaison avec la propriété CSS3 "resize: both". L'observateur ne détectera pas les modifications apportées à l'élément par l'utilisateur en faisant glisser le handle de redimensionnement. – cburgmer

+0

Y a-t-il un moyen de voir d'où vient le changement? J'ai un élément dont la classe est modifiée quelque part par JS, et j'essaie de comprendre d'où, mais la trace de pile de l'événement de Chrome ne montre pas le code qui a initié l'événement. –

+1

il est à noter que 'DOMAttrModified' se déclenche immédiatement lorsque l'attribut change, mais les observateurs de mutation mettent en file d'attente un événement. Il y a donc une différence pas si subtile entre les deux. –

13

Si vous êtes satisfait de simplement la détection des appels à setAttribute() (par opposition à la surveillance de l'attribut toutes les modifications), vous pouvez l'emporter sur cette méthode sur tous les éléments avec:

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); 
} 
0

Veuillez vous référer au code:'DOMAttrModified' + ('propertychange' pour IE) sont utilisés ici comme dans votre cas. Si cela ne vous convient pas, la solution "laide" qui peut satisfaire cette demande devrait être réglée surInterval (function() {}, delay) Sinon, voir Sean Hogan ci-dessus.

+0

L'URL n'est pas valide –

0

La solution fournie par @Filip est proche (et peut avoir fonctionné à ce moment-là) mais vous devez maintenant demander la livraison de l'ancienne valeur d'attribut.

Ainsi, vous aurez envie de changer:

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

à ceci:

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

Sinon, vous ne verrez pas les oldValues ​​(. Vous aurez null à la place) Cela a été testé dans Chrome 34.0.1847.131 (Official Build 265687) m.

3

J'avais la même question et je pensais à modifier setAttribute, donc en voyant what Sean did, j'ai copié cela. Fonctionne bien, sauf qu'il se déclenche quand un attribut a été réglé à la même valeur, donc j'ai ajouté une vérification à ma copie pour sauter l'événement si la valeur n'est pas modifiée. J'ai également ajouté val = String(val), basé sur la logique que setAttribute va contraindre des nombres à des chaînes, donc la comparaison devrait anticiper cela.

Ma version modifiée est:

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