2009-12-10 56 views
21

我需要利用此DOM事件。 IE有onpropertychange,這做我也需要它做。然而,Webkit似乎不支持這個事件。有沒有其他方法可以使用?是否有替代DOMAttrModified,將在webkit中工作

+0

我能想出在此基礎上的東西[http://www.west-wind.com/Weblog/posts/453942.aspx](http: //www.west-wind.com/Weblog/posts/453942.aspx) – blockhead 2010-03-02 19:17:04

+0

基於[David Walsh的解決方案](http://davidwalsh.name/detect-node-insertion)我創建了一個小型庫捕獲DOM插入。如果您可以在您感興趣的更改之後編寫與該元素相匹配的CSS選擇器 - 這是一個有效的解決方案。它涵蓋了比DOM突變觀察者更多的瀏覽器。請參閱:https:// github。com/naugtur/insertionQuery – naugtur 2013-03-10 22:47:25

回答

24

雖然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

+2

看來,這目前不能與CSS3「resize:both」屬性結合使用。觀察者不會通過拖動調整大小手柄來獲取元素的更改。 – cburgmer 2012-08-27 10:33:19

+0

有什麼辦法可以看到變化來自哪裏?我有一個元素的類正在通過JS在某處進行更改,我試圖找出從哪裏開始,但Chrome的事件堆棧跟蹤沒有顯示啓動事件的代碼。 – 2013-05-28 19:16:00

+1

值得注意的是,當屬性改變時,DOMAttrModified立即觸發,但是突變觀察者排隊事件。所以兩者之間並沒有那麼微妙的區別。 – 2014-12-10 16:37:22

13

如果你很高興與僅僅檢測調用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); 
} 
0

請參閱代碼: https://github.com/meetselva/attrchange/blob/master/attrchange.js 'DOMAttrModified'+('propertychange'for IE)在那裏用在你的情況。如果它不適合你,那麼可以滿足這個需求的「醜陋」解決方案應該是setInterval(function(){},delay) 否則請參閱上面的Sean Hogan。

+0

網址無效 – 2015-05-11 11:35:49

0

@Filip提供的解決方案是關閉的(並且可能在當時已經工作),但現在您需要請求傳遞舊的屬性值。

因此,你會想改變:

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

這樣:

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

否則,你將不會看到oldValues(你會得到空代替)這是在Chrome 34.0.1847.131(Official Build 265687)中測試。

3

我有同樣的問題,並正在考慮修改setAttribute,所以看到what Sean did,我複製了。工作得很好,除了當屬性被重複設置爲相同的值時它被觸發,所以我添加了一個檢查到我的副本,以避免在沒有更改值時觸發事件。我還添加了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();