修改尚未创建的元素的首选方法(除了事件)

scr*_*agz 42 javascript jquery events mutation-events

关于将未来的操作绑定到不存在的元素存在很多问题,这些元素最终都以live/delegate回答.我想知道如何运行任意回调(例如,添加类或触发插件)匹配选择器的所有现有元素以及与尚未创建的相同选择器匹配的所有未来元素.

似乎livequery插件的主要功能使其成为核心,但另一部分,附加任意回调在某种程度上丢失了.

另一个常见的答案是事件委派,但是如果一个人无法访问创建元素以触发事件的所有供应商代码,该怎么办?


这是一些现实世界的代码:

// with livequery
$('input[type=text], input[type=password], textarea, .basic_form .block select, .order_form .form_item select, .order_form .form_item input')
    .livequery(function(){
        $(this)
            .focus(function(){
                $(this).addClass('active');
            })
            .blur(function(){
                $(this).removeClass('active');
            })
            .addClass('text');
    });

// with live
$('input[type=text], input[type=password], textarea, .basic_form .block select, .order_form .form_item select, .order_form .form_item input')
    .live('focus', function(){
            $(this).addClass('active');
        })
    .live('blur', function(){
            $(this).removeClass('active');
        });
    // now how to add the class to future elements?
    // (or apply another plugin or whatever arbitrary non-event thing)
Run Code Online (Sandbox Code Playgroud)

一种方法是监视何时添加/删除新节点并重新触发我们的选择器.感谢@arnorhs,我们知道DOMNodeInserted事件,我会忽略跨浏览器的问题,希望那些小的IE补丁有一天能够上游到jQuery或知道jQuery DOM功能可以被包装.

但是,即使我们可以确保DOMNodeInserted触发了跨浏览器,但使用多个选择器绑定它也是荒谬的.可以随时创建数百个元素,并且可能会对每个元素进行数十个选择器调用.

到目前为止我最好的主意

是否可能更好地监控DOMNodeInserted/Deleted和/或挂钩到jQuery的DOM操作例程中,只设置一个"重新初始化"应该发生的标志?然后可能只有一个定时器,每隔x秒检查一次该标志,只在DOM实际发生变化时运行所有那些选择器/回调.

如果您以快速的速度添加/删除大量元素(如动画或____),那可能仍然非常糟糕.如果x很低,每x秒重新解析一次DOM,每隔x秒可能会过于激烈,如果x很高,界面会显得迟钝.

还有其他新颖的解决方

当它让我时,我会加一个赏金.我为最新颖的解决方案添加了赏金!

基本上我所了解的是一种更加面向方面的操作DOM的方法.可以允许将来创建新元素的一个,并且应该使用初始document.ready修改来创建它们.

JS最近能够做到这么多魔术,我希望它会很明显.

jAn*_*ndy 10

在我看来,DOM Level 3事件DOMNodeInserted有助于(仅针对节点触发)和DOMSubtreeModified帮助(实际上任何修改(例如属性更改)触发)是完成该任务的最佳方法.

当然,这些事件的最大缺点是,这个世界的互联网探索者不支持他们
(......好吧,IE9确实如此).

这个问题的另一个合理的解决方案是挂钩任何可以修改DOM的方法.但接下来我们要问,这里的范围是什么?

它是否足以处理来自特定库(如jQuery)的DOM修改方法?如果由于某种原因另一个库正在修改DOM甚至是本机方法会怎样?

如果它仅适用于jQuery,我们根本不需要.sub().我们可以用以下形式编写钩子:

HTML

<div id="test">Test DIV</div>
Run Code Online (Sandbox Code Playgroud)

JS

(function(_append, _appendTo, _after, _insertAfter, _before, _insertBefore) {
    $.fn.append = function() {
        this.trigger({
            type: 'DOMChanged',
            newnode: arguments[0]
        });
        return _append.apply(this, arguments);
    };
    $.fn.appendTo = function() {
        this.trigger({
            type: 'DOMChanged',
            newnode: this
        });
        return _appendTo.apply(this, arguments);
    };
    $.fn.after = function() {
        this.trigger({
             type: 'DOMChanged',
             newnode: arguments[0]
         });
        return _after.apply(this, arguments);
    };

    // and so forth

}($.fn.append, $.fn.appendTo, $.fn.after, $.fn.insertAfter, $.fn.before, $.fn.insertBefore));

$('#test').bind('DOMChanged', function(e) {
    console.log('New node: ', e.newnode);
});

$('#test').after('<span>new span</span>');
$('#test').append('<p>new paragraph</p>');
$('<div>new div</div>').appendTo($('#test'));
Run Code Online (Sandbox Code Playgroud)

上面代码的实例可以在这里找到:http://www.jsfiddle.net/RRfTZ/1/

这当然需要完整的DOMmanip方法列表.我不确定你是否可以.appendChild()用这种方法覆盖原生方法.例如,.appendChild位于Element.prototype.appendChild,可能值得一试.

更新

我测试Element.prototype.appendChild了Chrome,Safari和Firefox中的覆盖等(官方最新版本).适用于Chrome和Safari,但不适用于Firefox!


可能还有其他方法可以解决这一要求.但是我想不出一个真正令人满意的方法,比如计算/观察节点的所有后代(需要一个interval或者timeoutseeek).

结论

DOM Level 3事件的混合,支持和挂钩的DOMmanip方法可能是您在这里可以做的最好的.


arn*_*rhs 6

我正在阅读新版本的jQuery版本1.5,我立即想到了这个问题.

使用jQuery 1.5,您可以使用名为jQuery.sub()的东西创建自己的jQuery版本.

这样你就可以在jQuery中覆盖默认的.append(),insert(),. html(),..函数,并创建一个名为"mydomchange"的自定义事件 - 而不会影响所有其他脚本.

所以你可以做这样的事情(从带有小mod的.sub()文档中复制.):

var sub$ = jQuery.sub();
sub$.fn.insert = function() {
    // New functionality: Trigger a domchange event
    this.trigger("domchange");
    // Be sure to call the original jQuery remove method
    return jQuery.fn.insert.apply( this, arguments );
};
Run Code Online (Sandbox Code Playgroud)

您必须对所有dom操作方法执行此操作...

jQuery文档中的jQuery.sub():http: //api.jquery.com/jQuery.sub/

  • 我不明白`sub`与它有什么关系.您需要覆盖原始jQuery对象,而不是subbed对象,以便第3方代码受到影响. (2认同)