修改尚未创建的元素(除事件之外)的首选方式 [英] Preferred way of modifying elements that have yet to be created (besides events)

查看:136
本文介绍了修改尚未创建的元素(除事件之外)的首选方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关将未来操作绑定到不存在的元素有很多问题,所有这些都会以 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功能(){
$(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 ',function(){
$(this).removeClass('active');
});
//现在如何将类添加到未来元素?
//(或应用另一个插件或任何非事件事件)






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



然而,即使我们可以确保DOMNodeInserted被触发的跨浏览器,也可以用多个选择器绑定它。可以随时创建数以百计的元素,并且可以在每个元素上进行数十个选择器调用。



到目前为止我最好的想法



可能会更好地监视DOMNodeInserted / Deleted和/或挂钩到jQuery的DOM操作例程,只设置一个re-init应该发生的标志?那么可能只有一个定时器,每x秒检查一次标志,只有当DOM实际上改变时才运行所有这些选择器/回调。



这可能还是很糟糕的如果您以快速的速度添加/删除大量的元素(如动画或____)。如果x为低,则不得不每x秒为每个保存的选择器重新解析DOM一次,如果x为高,则界面会出现缓慢。



任何其他新颖的解决方案?



当我允许我时,我会添加一个赏金。我为最新的解决方案添加了一个赏金! p>

基本上我所得到的是一种更加强调面向方面的操作DOM。可以允许新元素在将来中创建,并且应该使用创建初始document.ready修改



JS已经能够做到这么多魔法,我希望这将是显而易见的。

解决方案

在我看来,DOM 3级事件 DOMNodeInserted help (仅针对节点触发)和 DOMSubtreeModified help (几乎任何修改都会触发,如属性更改)是您完成该任务的最佳选择。



当然,这些事件的大缺点是,这个世界的互联网探险者不支持他们

(...好吧, IE9 does)。



这个问题的另一个合理的解决方案是钩住任何可以修改DOM的方法。但是我们必须问,我们的范围在这里?



只需处理来自特定库(如jQuery)的DOM修改方法即可。如果由于某种原因,另一个库正在修改DOM甚至是本地方法?



如果只是用于jQuery,我们不需要。 sub()。我们可以用以下形式写钩子:



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

//等等

}($。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>新段落< / p>');
$('< div> new div< / div>')。appendTo($('#test'));






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



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



更新



我测试过覆盖 Element.prototype.appendChild 等。在Chrome和Safari中使用,但不在Firefox中!






可能还有其他方法可以解决这个要求。但是我不能想到一个真正令人满意的单一方法,例如计数/观察节点的所有后代(需要一个间隔超时,eeek)。



结论



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


There are a lot of questions about binding future manipulations to non-existent elements that all end up answered with live/delegate. I am wondering how to run an arbitrary callback (to add a class or trigger a plugin, for example) to all existing elements that match a selector and all future elements that match that same selector that are yet to be created.

It seems that the main functionality of the livequery plugin made it into the core but the other part, attaching arbitrary callbacks got lost along the way somehow.

Another common answer is event delegation but what if one doesn't have access to all of the vendor code that is creating the elements to have it trigger the events?


Here is some real-world code:

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


One approach would be to monitor when new nodes are added/removed and re-trigger our selectors. Thanks to @arnorhs we know about the DOMNodeInserted event, which I would ignore the cross-browser problems in the hope that those small IE patches could someday land upstream to jQuery or knowing the jQuery DOM functions could be wrapped.

Even if we could ensure that the DOMNodeInserted fired cross-browser, however, it would be ridiculous to bind to it with multiple selectors. Hundreds of elements can be created at any time, and making potentially dozens of selector calls on each of those elements would crawl.

My best idea so far

Would it maybe be better to monitor DOMNodeInserted/Deleted and/or hook into jQuery's DOM manipulation routines to only set a flag that a "re-init" should happen? Then there could just be a timer that checks that flag every x seconds, only running all those selectors/callbacks when the DOM has actually changed.

That could still be really bad if you were adding/removing elements in great numbers at a fast rate (like with animation or ____). Having to re-parse the DOM once for each saved selector every x seconds could be too intense if x is low, and the interface would appear sluggish if x is high.

Any other novel solutions?

I will add a bounty when it lets me. I have added a bounty for the most novel solution!

Basically what I am getting at is a more aspect-oriented approach to manipulating the DOM. One that can allow that new elements are going to be created in the future, and they should be created with the initial document.ready modifications applied to them as well.

JS has been able to do so much magic lately that I'm hoping it will be obvious.

解决方案

In my opinion, the DOM Level 3 events DOMNodeInsertedhelp (which fires only for nodes) and DOMSubtreeModifiedhelp (which fires for virtually any modification, like attribute changes) are your best shot to accomplish that task.

Of course, the big downside of those events is, that the Internet Explorers of this world don't support them
(...well, IE9 does).

The other reasonable solution for this problem, is to hook into any method Which can modify the DOM. But then we have to ask, what is our scope here?

Is it just enough to deal with DOM modification methods from a specific library like jQuery? What if for some reason another library is modifying the DOM or even a native method ?

If it's just for jQuery, we don't need .sub() at all. We could write hooks in the form of:

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


A live example of the above code can be found here: http://www.jsfiddle.net/RRfTZ/1/

This of course requires a complete list of DOMmanip methods. I'm not sure if you can overwrite native methods like .appendChild() with this approach. .appendChild is located in Element.prototype.appendChild for instance, might be worth a try.

update

I tested overwriting Element.prototype.appendChild etc. in Chrome, Safari and Firefox (official latest release). Works in Chrome and Safari but not in Firefox!


There might be other ways to tackle the requirement. But I can't think of a single approach which is really satisfying, like counting / watching all descendents of a node (which would need an interval or timeouts, eeek).

Conclusion

A mixture of DOM Level 3 events where supported and hooked DOMmanip methods is probably the best you can do here.

这篇关于修改尚未创建的元素(除事件之外)的首选方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆