42

将来の操作を存在しない要素にバインドすることについて多くの質問があり、最終的にlive /delegateで回答されます。セレクターに一致するすべての既存の要素と、まだ作成されていない同じセレクターに一致するすべての将来の要素に対して、任意のコールバックを実行する方法(たとえば、クラスを追加したり、プラグインをトリガーしたりする方法)を考えています。

livequery プラグインの主な機能はコアに組み込まれたようですが、任意のコールバックをアタッチする他の部分は途中で失われました。

もう 1 つの一般的な答えはイベント委任ですが、要素を作成してイベントをトリガーするすべてのベンダー コードにアクセスできない場合はどうなるでしょうか。


以下は実際のコードです。

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

1 つのアプローチは、新しいノードがいつ追加/削除されたかを監視し、セレクターを再トリガーすることです。@arnorhsのおかげで、私はDOMNodeInsertedイベントについて知っています。これらの小さな IE パッチがいつか jQuery のアップストリームに到達するか、jQuery DOM 関数がラップされる可能性があることを知っていることを期待して、クロスブラウザーの問題を無視します。

ただし、DOMNodeInserted がクロスブラウザーを起動したことを確認できたとしても、複数のセレクターでそれにバインドするのはばかげています。いつでも何百もの要素を作成することができ、これらの要素のそれぞれに対して潜在的に数十のセレクター呼び出しを行うとクロールします。

これまでの私の最高のアイデア

DOMNodeInserted/Deleted を監視するか、jQuery の DOM 操作ルーチンにフックして、「再初期化」が発生するフラグのみを設定する方がよいでしょうか? 次に、そのフラグをx秒ごとにチェックするタイマーがあり、DOMが実際に変更されたときにのみ、これらすべてのセレクター/コールバックを実行します。

大量の要素を高速で追加/削除している場合 (アニメーションや ____ のように)、これはまだ非常に悪い可能性があります。保存されたセレクターごとに x 秒ごとに 1 回 DOM を再解析する必要があるのは、x が低い場合は負荷が高すぎる可能性があり、x が高い場合はインターフェースが遅く見える可能性があります。

他の新しいソリューションはありますか?

気が向いたら賞金を追加します。最も斬新な解決策に報奨金を追加しました!

基本的に私が得ているのは、DOM を操作するためのよりアスペクト指向のアプローチです。新しい要素が将来作成されることを可能にするもので、最初の document.ready 変更も適用して作成する必要があります。

JS は最近非常に多くの魔法を行うことができたので、それが明らかになることを願っています。

4

5 に答える 5

10

私の意見では、DOMレベル3イベントのDOMNodeInsertedヘルプ(ノードに対してのみ発生する)とDOMSubtreeModifiedヘルプ(属性の変更など、事実上すべての変更に対して発生する)は、そのタスクを実行するための最良の方法です。

もちろん、これらのイベントの大きな欠点は、この世界のInternet Explorerがそれらをサポートしていないこと
です(...まあ、IE9はサポートしています)。

この問題に対する他の合理的な解決策は、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);
    };

    // 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()このアプローチのようにネイティブメソッドを上書きできるかどうかはわかりません。たとえば、にあり、試してみる価値があるかもしれません.appendChildElement.prototype.appendChild

アップデート

Element.prototype.appendChildChrome、Safari、Firefox(公式最新リリース)で上書きなどをテストしました。ChromeとSafariで動作しますが、Firefoxでは動作しません!


要件に取り組む他の方法があるかもしれません。しかし、ノードのすべての子孫をカウント/監視するなど、本当に満足のいく単一のアプローチを考えることはできません(intervalまたはtimeouts、eeekが必要になります)。

結論

サポートされフックされたDOMmanipメソッドがここで実行できる最善の方法であるDOMレベル3イベントの混合。

于 2011-02-11T23:56:43.333 に答える
6

jQuery の新しいリリース、バージョン 1.5 について読んでいて、すぐにこの質問を思いつきました。

jQuery 1.5 では、jQuery.sub() と呼ばれるものを使用して、独自のバージョンの jQuery を実際に作成できます。

そうすれば、jQuery のデフォルトの .append()、insert()、.html()、.. 関数を実際にオーバーライドして、「mydomchange」などと呼ばれる独自のカスタム イベントを作成できます。他のすべてのスクリプトに影響を与えることはありません。

したがって、次のようなことができます (.sub() ドキュメントからマイナー mod でコピー):

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

すべてのdom操作メソッドに対してこれを行う必要があります...

jQuery ドキュメントの jQuery.sub(): http://api.jquery.com/jQuery.sub/

于 2011-02-09T00:33:23.880 に答える
2

素晴らしい質問

バインドできるカスタム イベントがあるようです: http://javascript.gakaa.com/domnodeinserted-description.aspx

だから私はあなたが次のようなことができると思います:

$(document).bind('DOMNodeInserted',function(){ /* do stuff */ });

でも、試したことがないのでわかりません..

ところで: 関連する質問: JavaScript はすべての Dom 要素で "onDomChange" をリッスンできますか?

于 2011-02-04T02:43:46.093 に答える
0

それを行うための簡単で明白な方法はありません。唯一の確実なアプローチはアクティブ ポーリングです。これにより、新しい要素が作成されてからポーリングがそれに気付くまでの間にレンダリングの問題が発生します。また、ページをポーリングする頻度によっては、ページが多くのリソースを消費する可能性もあります。観察したように、これをいくつかのブラウザー固有のイベントをバインドして結合して、少なくともそれらのブラウザーでの動作を改善することもできます。

jQuery の DOM 変更関数をオーバーライドして、カスタムの変更イベントをトリガーすることができます (そして $.live を使用してこれらのイベントをキャッチして操作します)。これらのプラグインは同様のことを行います)。結局、私はパフォーマンスをあきらめたくないし、アクティブなポーリングにしゃっくりをレンダリングしたくないので、確実にそうすることをあきらめました。それを行うための他の包括的な方法はありません。代わりに、DOM の変更ごとにトリガーする初期化イベントを用意し、代わりに操作イベントをそれらにバインドします。

よく考えないと無限のイベント ループに陥りやすいので注意してください。これは微妙で追跡が難しい場合もあります。さらに悪いことに、単体テストで許可されなかったコーナー ケースが発生する可能性があります (そのため、ユーザーはあなただけでなくそれを経験します)。カスタムの手動でトリガーされた初期化イベントは、いつトリガーしたかを常に正確に把握できるため、この意味で診断が容易です。

于 2011-02-12T16:23:55.953 に答える
-1

まず第一に、パフォーマンスが心配な場合は、このようなセレクターを使用するべきではありません。

$('input[type=text], input[type=password], textarea, .basic_form .block select, .order_form .form_item select, .order_form .form_item input')

xpath (単なる IE iirc 以上) または getElementsByClassName (IE 7 以下) のネイティブ実装を持たないブラウザーは、大規模なサイトでそれを噛むのに数秒を簡単に費やすことができるため、もちろんポーリングは完全に問題外です。あなたがそれを広くしたいなら。

于 2011-02-12T00:20:37.927 に答える