есть ли альтернатива DOMAttrModified, которая будет работать в webkit

Мне нужно использовать это событие DOM. В IE есть onpropertychange, который делает то, что мне нужно. Однако Webkit, похоже, не поддерживает это событие. Есть ли альтернатива, которую я мог бы использовать?


person blockhead    schedule 10.12.2009    source источник
comment
Мне удалось кое-что придумать на основе этого http://www.west-wind.com/Weblog/posts/453942.aspx   -  person blockhead    schedule 02.03.2010
comment
На основе решения Дэвида Уолша я создал небольшую библиотеку для обнаружения вставок DOM. Если вы можете написать селектор CSS, который соответствует элементу после интересующего вас изменения — это правильное решение. Он охватывает больше браузеров, чем DOM Mutation Observers. См.: github.com/naugtur/insertionQuery.   -  person naugtur    schedule 11.03.2013


Ответы (5)


Хотя Chrome не отправляет события DOMAttrModified, с 2011 года поддерживаются более легкие наблюдатели мутаций, которые также работают для изменений атрибутов.

Вот пример тела документа:

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

Для простого изменения атрибута оператор console.log напечатает:

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

Консоль:

> color red black

person filip    schedule 05.05.2012
comment
Похоже, что в настоящее время это не будет работать в сочетании со свойством CSS3 resize: Both. Наблюдатель не улавливает изменения элемента, когда пользователь перетаскивает маркер изменения размера. - person cburgmer; 27.08.2012
comment
Есть ли способ увидеть, откуда произошли изменения? У меня есть элемент, класс которого где-то изменяется через JS, и я пытаюсь выяснить, откуда, но трассировка стека события Chrome не показывает код, инициировавший событие. - person Joseph Silber; 28.05.2013
comment
стоит отметить, что DOMAttrModified запускается немедленно при изменении атрибута, но наблюдатели мутаций ставят событие в очередь. Так что разница между ними не такая уж тонкая. - person Andy E; 10.12.2014
comment
Я считаю, что префикс Webkit больше не нужен. caniuse.com/#search=MutationObserver - person Daniel says Reinstate Monica; 25.11.2017

Если вас устраивает просто обнаружение вызовов setAttribute() (в отличие от отслеживания всех модификаций атрибутов), вы можете переопределить этот метод для всех элементов с помощью:

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);
}
person Sean Hogan    schedule 03.03.2010

У меня был тот же вопрос, и я думал об изменении setAttribute, поэтому, увидев что сделал Шон, я скопировал это. Работал отлично, за исключением того, что он срабатывал, когда атрибуту неоднократно устанавливалось одно и то же значение, поэтому я добавил в свою копию проверку, чтобы пропустить срабатывание события, если значение не изменяется. Я также добавил val = String(val), исходя из того, что setAttribute приведет числа к строкам, поэтому сравнение должно предвидеть это.

Моя модифицированная версия:

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();
person Bob Kanefsky    schedule 03.10.2014

Пожалуйста, обратитесь к коду: https://github.com/meetselva/attrchange/blob/master/attrchange.js 'DOMAttrModified' + ('propertychange' для IE) используются там, как и в вашем случае. Если это вам не подходит, "уродливым" решением, которое может удовлетворить это требование, должно быть setInterval(function(){}, delay). В противном случае см. сообщение Шона Хогана выше.

person user1700099    schedule 05.03.2014

Решение, предоставленное @Filip, близко (и, возможно, работало в то время), но теперь вам нужно запросить доставку старого значения атрибута.

Таким образом, вы захотите изменить:

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

к этому:

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

В противном случае вы не увидите oldValues ​​​​(вместо этого вы получите null). Это было протестировано в Chrome 34.0.1847.131 (официальная сборка 265687) m.

person user1055892    schedule 05.05.2014