【问题标题】:Watching for DOM changes, the elegant way观察 DOM 变化,优雅的方式
【发布时间】:2012-07-14 13:15:11
【问题描述】:

我需要观察特定 DOM 元素的任何子元素的属性更改。到目前为止,我一直在使用mutation events

问题是 - 他们是错误的:例如在 Chromium 下,DOMAttrModified 没有被解雇,但 DOMSubtreeModified 被解雇了。这个问题很容易解决:因为根据规范,如果任何其他事件被触发,DOMSubtreeModified 就会被触发,所以我只听了DOMSubtreeModified

无论如何,Chromium 在最近的版本中,如果属性被修改,就会停止触发任何东西。

然而,新的Mutation Observer API 却完美无缺。

直到现在,我只需要在特定元素的子树发生任何更改时触发回调 - 只是因为没有其他东西应该改变 - 所以我通过使用突变事件和突变观察者(如果可用)解决了我的问题在同一段代码中。

但是,现在我需要对事件进行更强大的过滤(例如,在新节点上、在已删除节点上) - 那么是否有 一个库,可能是一个 jQuery 插件,它允许我可以优雅地使用 both 这些 API - MutationObserver(如果可用)和突变事件作为后备,具有过滤特定事件类型(例如添加元素、更改属性)的能力。

例如

$("#test").watch({onNewElement: 1}, function(newElement){})
$("#test").watch({onNewAttribute: 1}, function(modifiedElement) {})

或者没有 jQuery

watchChanges("#test", {onNewElement: 1}, function(newElement){})
watchChanges("#test", {onNewAttribute: 1}, function(modifiedElement){})

【问题讨论】:

  • 一些搜索发现了这个,但它只支持新的API:code.google.com/p/mutation-summary。我还发现了这个,这似乎是您所要求的简单版本:stackoverflow.com/questions/10868104/…
  • 我还发现了突变摘要,但它不支持突变事件作为后备。您发布的线程的第一个答案基本上是我在代码中观察属性变化所做的。在相同的原则下,可以构建一个库,允许使用突变观察者和(作为后备)事件来监视特定的 DOM 事件。这就是我需要的。
  • +1:我真的很喜欢“最佳实践”问题。

标签: jquery html dom


【解决方案1】:

这行得通吗?

http://darcyclarke.me/development/detect-attribute-changes-with-jquery/

$.fn.watch = function(props, callback, timeout){
    if(!timeout)
        timeout = 10;
    return this.each(function(){
        var el      = $(this),
            func    = function(){ __check.call(this, el) },
            data    = { props:  props.split(","),
                        func:   callback,
                        vals:   [] };
        $.each(data.props, function(i) { data.vals[i] = el.css(data.props[i]); });
        el.data(data);
        if (typeof (this.onpropertychange) == "object"){
            el.bind("propertychange", callback);
        } else if ($.browser.mozilla){
            el.bind("DOMAttrModified", callback);
        } else {
            setInterval(func, timeout);
        }
    });
    function __check(el) {
        var data    = el.data(),
            changed = false,
            temp    = "";
        for(var i=0;i < data.props.length; i++) {
            temp = el.css(data.props[i]);
            if(data.vals[i] != temp){
                data.vals[i] = temp;
                changed = true;
                break;
            }
        }
        if(changed && data.func) {
            data.func.call(el, data);
        }
    }
}

【讨论】:

  • 我看到了,但它只是用于属性。另外,即使浏览器可能支持 DOMAttrModified,它也会退回到 setInterval。
  • @Ivo 对。不过这里有一个想法——你能控制 dom 发生的所有这些变化吗?您是否考虑过覆盖 jquery 操作方法来触发更改/追加/删除事件(但这是假设所有更改都通过 jquery 发生)。我知道这需要做很多工作,而且并不完全符合您的要求,但可以完成工作。
  • 我很久以前就已经完成了这项工作——我使用突变事件和观察者来监视属性,并且我只使用事件来监视 DOM 上新添加的东西——我是由于我正在关注通过 contenteditable/WYSIHTML5 编辑器所做的更改,因此无法完全控制。但这一切都适用于我计划支持的浏览器。这更像是一个“最佳方法”问题。给 jQuery 打猴子补丁似乎是个坏主意。 Monkey-patching DOM API 可能更合适,但我仍然不确定。
【解决方案2】:

为了使用 jQuery 进行有效的 DOM 监控,您可以查看使用 Live Query 优化版本的 jQuery Behavior Plugin(免责声明:我是作者)。我在几个产品中使用了 3 年,没有任何问题。

编辑:监听属性更改的工作方式如下:

$.behavior({
    'div:first': {
        'changeAttr': function (event, data) {
            console.log('Attribute "' +  data.attribute + '" changed from "' + data.from + '" to "' + data.to + '"');
        }
    }
});

$('div:first').attr('foo', 'bar');

【讨论】:

    猜你喜欢
    • 2014-02-15
    • 2013-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 2017-09-17
    • 2018-12-15
    • 1970-01-01
    相关资源
    最近更新 更多