Pergunta

Eu preciso aproveitar este evento DOM. IE tem onPropertyChange, que faz o que eu preciso fazer também. Webkit não parece apoiar este evento, no entanto. Existe uma alternativa que eu poderia usar?

Foi útil?

Solução

Embora Chrome faz não eventos expedição DOMAttrModified, os observadores de mutação mais lightweighted são suportados desde 2011 e estes trabalho para alterações de atributo também.

Aqui está um exemplo para o corpo do documento:

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

Para uma mudança atributo simples, a declaração console.log iria imprimir:

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

Console:

> color red black

Outras dicas

Se você está feliz com apenas detectar chamadas para setAttribute() (em oposição a monitorar todas as modificações de atributos), então você poderia sobrepor-se que o método em todos os elementos com:

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

Eu tive a mesma pergunta e estava pensando em modificar setAttribute, então vendo que Sean fez , Copiei isso. Funcionou muito bem, exceto que ele estava atirando quando um atributo foi repetidamente definido para o mesmo valor, então eu adicionei um cheque para minha cópia para pular disparando o evento se o valor não está sendo alterado. Eu também acrescentou val = String(val), com base no argumento de que setAttribute irá coagir números para strings, por isso a comparação deve antecipar isso.

Minha versão modificada é:

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

Por favor, consulte código: https://github.com/meetselva/attrchange/blob/master/attrchange.js 'DOMAttrModified' + ( 'PropertyChange' para IE) são usadas lá como no seu caso. Se não é adequado para você, a solução "feio" que pode satisfazer essa demanda deve ser setInterval (function () {}, atraso) veja Caso contrário Sean Hogan post acima.

A solução fornecida pela @Filip está perto (e pode ter trabalhado no momento), mas agora você precisa solicitar a entrega do valor do atributo de idade.

Assim, você vai querer mudar:

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

a esta:

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

Caso contrário, você não verá os oldValues ??(você vai ter nulo em vez.) Isto foi testado no Chrome 34.0.1847.131 (Official Desenvolver 265.687) m.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top