13

ユーザーが用語を入力できるオートコンプリート フォームがあり、<li>その用語を含まないすべての要素を非表示にします。

<li>私は元々 jQuery ですべてをループし、用語を含まないものにeach適用しました。.hide()これは遅すぎました。

より高速な方法は、すべてをループして、非表示にする必要があるすべてに<li>クラスを適用し、ループの最後で do を実行することであることがわかりました。ただし、これはハックのように感じます。.hidden$('.hidden').hide()

.hiddenを使用してクラスの CSS ルールを書き直すと、潜在的に高速な方法になる可能性がありますdocument.styleSheets。誰かがもっと良い方法を考えることができますか?

編集:あまりにも多くの人が知っているかどうかわからないことを明確にさせてください. ループの各反復で DOM を変更し、その変更によってページが再描画される場合、すべての変更を「準備」してループの終了時に一度に適用するよりもはるかに遅くなります。

4

7 に答える 7

24

何千ものアイテムを扱うときはいつでも、DOM 操作遅くなります。通常、多くの DOM 要素をループして、その要素の特性に基づいて各要素を操作することはお勧めできません。これは、反復ごとに DOM メソッドを多数呼び出す必要があるためです。ご覧のとおり、本当に遅いです。

はるかに優れたアプローチは、データを DOM から分離しておくことです。JS 文字列の配列を検索すると、桁違いに速くなります。

これは、データセットを JSON オブジェクトとしてロードすることを意味する場合があります。それができない場合は、<li>(ページの読み込み時に) s を 1 回ループして、データを配列にコピーできます。

データセットは存在する DOM 要素に依存しなくなったので、ユーザーが入力するたびに<ul>使用中のコンテンツ全体を単純に置き換えることができます。.html()(これは、単純に を変更するだけでブラウザが DOM の変更を最適化できるため、JS DOM 操作よりもはるかに高速ですinnerHTML。)

var dataset = ['term 1', 'term 2', 'something else', ... ];

$('input').keyup(function() {
    var i, o = '', q = $(this).val();
    for (i = 0; i < dataset.length; i++) {
        if (dataset[i].indexOf(q) >= 0) o+='<li>' + dataset[i] + '</li>';
    }
    $('ul').html(o);
});

ご覧のとおり、これは非常に高速です。


ただし、アイテム数を 10,000 まで上げると、最初の数回のキーストロークでパフォーマンスが低下し始めることに注意してください。これは、検索されるアイテムの生の数よりも、DOM に挿入される結果の数に関連しています。(入力する回数が多くなり、表示する結果が少なくなるため、10,000 項目すべてを検索しているにもかかわらず、パフォーマンスは良好です。)

これを避けるために、表示される結果の数を妥当な数に制限することを検討します。(1,000 はどれでも良いようです。) これはオートコンプリートです。誰も実際にすべての結果を調べているわけではありません。結果セットが人間にとって扱いやすいものになるまで、彼らは入力を続けます。

于 2012-08-12T20:05:21.203 に答える
1

次のように、jQuery の contains() セレクターを使用して、リスト内の特定のテキストを含むすべてのアイテムを検索し、それらを非表示にすることができます。

HTML:

 <ul id="myList">
      <li>this</li>
      <li>that</li>
 <ul>​

jQuery

var term = 'this';    
$('li:contains("' + term + '")').hide();​
于 2012-08-12T19:55:33.797 に答える
1

すべての <li> を直接選択して、それらをフィルタリングできます: $("li").filter(function(){...}).hide()(こちらを参照)

(すみません、以前の投稿は間違っていました)

于 2012-08-12T19:44:53.193 に答える
1

データのコピーを属性に入れ、CSS 属性セレクターを使用することで、技術的に JavaScript を使用せずに実際の非表示を行う、よりユニークな手法を使用できます。

たとえば、用語がsecretで、データのコピーをdata-term属性に入れる場合、次の CSS を使用できます。

li[data-term*="secret"] {
    display: none;
}

これを動的に行うには、JavaScript でヘッドにスタイルを追加する必要があります。

function hideTerm(term) {
    css = 'li[data-term*="'+term+'"]{display:none;}'
    style = $('<style type="text/css">').text(css)
    $('head').append(style);
}

これを行う場合は、スタイル タグを使用しなくなったときに必ずクリーンアップすることをお勧めします。

最新のブラウザーでは CSS の選択が非常に高速であるため、これがおそらく最も高速です。ベンチマークするのは難しいので、確かなことは言えません。

于 2012-08-12T20:26:12.957 に答える
0

スタイルシート ルールを再定義する代わりに、「hide」クラス プロパティを「display:none;」に直接定義できます。事前に自分のページで、以下のように、javascript を使用して条件を確認した後、定義したクラスを適用するだけです。

$("li").each(function(){if(condition){$(this).addClass('hide');}});

その後、それらのliを再度表示したい場合は、以下のようにクラスを削除するだけです

$("li").each(function(){if(condition){$(this).removeClass('hide');}});
于 2012-08-12T19:53:51.923 に答える
0

どうですか:

<style>
    .hidden{ display: none; }
</style>

そうすれば、 $('.hidden').hide() を使用して余分なクエリを実行する必要がなくなります。

于 2012-08-12T19:46:30.863 に答える