javascript - 修改尚未创建的元素的首选方式(事件除外)

标签 javascript jquery events mutation-events

有很多关于将 future 的操作绑定(bind)到不存在的元素的问题,最终都用 live 来回答。/代表。我想知道如何运行任意回调(例如添加一个类或触发一个插件)匹配选择器的所有现有元素和匹配相同选择器的所有 future 元素 尚未创建。

似乎 livequery 插件的主要功能使其成为核心,但附加任意回调的另一部分以某种方式丢失了。

另一个常见的答案是事件委托(delegate),但如果无法访问所有正在创建元素的 vendor 代码怎么办trigger事件?


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

// 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)

一种方法是监视何时添加/删除新节点并重新触发我们的选择器。多亏了 @arnorhs 我们知道了 DOMNodeInserted 事件,我会忽略跨浏览器问题,希望那些小的 IE 补丁有一天可以登陆 jQuery 的上游或者知道可以包装 jQuery DOM 函数。

即使我们可以确保 DOMNodeInserted 触发跨浏览器,但是用多个选择器绑定(bind)到它也是荒谬的。任何时候都可以创建数百个元素,并且可能会对每个元素进行数十次选择器调用。

到目前为止我最好的想法

监控 DOMNodeInserted/Deleted 和/或挂接到 jQuery 的 DOM 操作例程以仅设置一个应该发生“重新初始化”的标志可能会更好吗?然后可能只有一个计时器每 x 秒检查一次该标志,仅在 DOM 实际更改时才运行所有这些选择器/回调。

如果您以快速的速度添加/删除大量元素(例如动画或 ____),那可能仍然很糟糕。如果 x 很低,则必须每 x 秒为每个保存的选择器重新解析一次 DOM 可能过于紧张,如果 x 很高,界面会显得迟钝。

还有其他新颖的解决方案吗?

我会在允许时添加赏金。我已经为最新颖的解决方案添加了赏金!

基本上,我得到的是一种更面向方面的方法来操纵 DOM。一个可以允许将来创建新元素,并且应该在创建它们时也应用初始 document.ready 修改。。 p>

最近 JS 能够发挥如此多的魔力,我希望它会显而易见。

最佳答案

在我看来,DOM Level 3 事件 DOMNodeInsertedhelp (仅针对节点触发)和 DOMSubtreeModifiedhelp (它会触发几乎任何修改,如属性更改)是完成该任务的最佳机会。

当然,这些事件的最大缺点是,这个世界的 Internet Explorer 不支持它们
(...好吧,IE9 可以)。

这个问题的另一个合理的解决方案是 Hook 任何可以修改 DOM 的方法。但是我们不得不问,我们的范围是什么?

仅处理来自特定库(如 jQuery)的 DOM 修改方法就足够了吗?如果出于某种原因另一个库正在修改 DOM 甚至本地方法怎么办?

如果只是为了jQuery,我们根本不需要.sub()。我们可以编写以下形式的钩子(Hook):

HTML

<div id="test">Test DIV</div>

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

可在此处找到上述代码的实例:http://www.jsfiddle.net/RRfTZ/1/

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

更新

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


可能有其他方法可以满足要求。但我想不出真正令人满意的单一方法,比如计算/观察节点的所有后代(这需要 intervaltimeouts,eeek)。

结论

DOM Level 3 事件的混合,其中受支持和 Hook 的 DOMmanip 方法可能是您在这里可以做的最好的事情。

关于javascript - 修改尚未创建的元素的首选方式(事件除外),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4893937/

相关文章:

javascript - 在 JavaScript 中调用字符串作为函数调用

jquery 动画和带有 addClass 的removeClass

jquery - css 图像一起移动而不是单独移动

c# - 通过委托(delegate)和事件调用的区别 C#

javascript - 基于 Dropdown 的 React Effector 状态管理

javascript - 如何为使用 Html5 创建的视频创建灯箱效果?

javascript - 关闭 Firefox/Internet Explorer 中的默认 CTRL-F 搜索栏

javascript - phonegap tel 软键盘完成操作

javascript - 表单验证后禁用点击提交按钮

javascript - 避免在嵌套函数 jQuery 中使用 _this