【问题标题】:is there an alternative to DOMAttrModified that will work in webkit是否有可以在 webkit 中使用的 DOMAttrModified 的替代方法
【发布时间】:2010-12-25 07:55:50
【问题描述】:

我需要利用这个 DOM 事件。 IE 有 onpropertychange,它也可以做我需要它做的事情。然而,Webkit 似乎不支持这个事件。有没有我可以使用的替代方案?

【问题讨论】:

标签: dom webkit mutation-events


【解决方案1】:

如果您只对检测到对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);
}

【讨论】:

    【解决方案2】:

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

    控制台:

    &gt; color red black

    【讨论】:

    • 目前看来这不能与 CSS3 "resize: both" 属性结合使用。观察者不会通过用户拖动调整大小手柄来获取对元素的更改。
    • 有什么方法可以查看更改的来源?我有一个元素,其类正在通过 JS 在某处更改,我试图找出从哪里来,但 Chrome 的事件堆栈跟踪没有显示启动事件的代码。
    • 值得注意的是,DOMAttrModified 在属性更改时立即触发,但突变观察者将事件排队。所以两者之间没有那么微妙的区别。
    • 我相信 Webkit 前缀不再需要。 caniuse.com/#search=MutationObserver
    【解决方案3】:

    请参考代码: https://github.com/meetselva/attrchange/blob/master/attrchange.js 'DOMAttrModified' + ('propertychange' for IE) 在那里使用,就像你的情况一样。如果不适合你,能满足这个需求的“丑”解决方案应该是 setInterval(function(){}, delay) 否则请参阅上面的 Sean Hogan 帖子。

    【讨论】:

      【解决方案4】:

      @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 中测试的。

      【讨论】:

        【解决方案5】:

        我有同样的问题,正在考虑修改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();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-27
          • 1970-01-01
          • 2022-08-21
          • 1970-01-01
          • 2020-03-01
          • 1970-01-01
          • 2010-09-20
          相关资源
          最近更新 更多