みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

大量のチェックボックス状態取得について

質問させてください。

以下のようなHTML構造で連続している場合、
ID内全体のチェックボックスの状態を取得し、未チェックの物を非表示するにはどのようにすれば一番処理速度が速いのでしょうか?

<div id="hoge1">
<ul>
<li>
<ul class="Parents">
<li class="child"><input type="checkbox" name="AAA"></li>
<li class="child"><input type="checkbox" name="BBB"></li>
<li class="child"><input type="checkbox" name="CCC"></li>
<li class="child"><input type="checkbox" name="DDD"></li>
</ul>
</li>
<li>
<ul class="Parents">
<li class="child"><input type="checkbox" name="AAA"></li>
<li class="child"><input type="checkbox" name="BBB"></li>
<li class="child"><input type="checkbox" name="CCC"></li>
<li class="child"><input type="checkbox" name="DDD"></li>
</ul>
</li>
~~~~~~~~~~~~
   ※繰り返し
~~~~~~~~~~~~
</ul>
</div>

現在はjQueryで$ (ul.Parents li.child)で全体をラップし、for文のループ内で$eq()で1件毎chekedを参照し、.hide()を行っています。

動作自体は問題ないのですが、処理速度の遅さが気になっています。
速い方法でればjQueryを使用しない方法でもかまいません。

どうかよろしくお願い致します。

投稿日時 - 2011-10-25 00:35:08

QNo.7092678

困ってます

質問者が選んだベストアンサー

No.4 の方のキャッシュを利用するのは良い考えと思います。

ただ、querySelectorAll() にしろ jQuery にしろ、その戻り値は「生きていません」。つまり、文書状態に応じてアップデートするのは自分の責任、ということになります。

キャッシュを使うなら「生きた」リストを使うと良い。getElements... の名前を持つメソッドが返す「生きた」リストは、文書状態に応じて自動的にアップデートされます。

var ChildrenCache = document.getElementsByClassName('child');

もちろん、load イベントを待つ必要もありません。文書木の構築に合わせて、勝手に追加されるからです。その分、普通の配列のように扱うと怪我をします。注意して下さい。

投稿日時 - 2011-10-26 15:36:13

補足

ご回答ありがとうございます。
度重なる質問にも丁寧に解説していただき、とても勉強になりました。

今回はChaire様に教えていただいたgetElementByIdを使用して対応し、
子孫セレクタの排除にも気を配ってみようとおもいます。

今回このようなサービスを初めて利用したのですが、
有識者の皆様に詳しく回答していただきとても助かりました。

投稿日時 - 2011-11-01 00:02:06

ANo.5

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(5)

ANo.4

リストはあらかじめ取得しておけば早くなるかと。
▼window.onloadや#hoge1 の出力後あたりで
var elems = $("#hoge1 ul.Parents li.child input:[type='checkbox']");
▼処理部分で
var n= elems.length;
for(var i=0; i < n;i++){
if(!elems[i].checked){elems[i].parentNode.style.display="none";}
}

jQuery1文なら
$("#hoge1 input:checkbox:not(:checked)").parent("li.child").hide();
とか、実際の構造に応じて
$("#hoge1 ul.Parents > li.child > input:checkbox:not(:checked)").parent("li.child").hide();
とか。

投稿日時 - 2011-10-26 11:24:46

補足

ご回答ありがとうございます。
キャッシュを使用する方式も盲点でした。
試してみます!!

投稿日時 - 2011-10-31 23:53:19

ANo.3

No.2 補足より。
> getElementById
> formに入れる事で

どちらでも構いませんよ。両方とも最速候補です。

function process (controls) {
 var c;
 var i;

 for (i = 0; c = controls[i]; i++) {
  if (c.type !== 'checkbox')
   continue;

  switch (c.name) {
  case 'AAA' :case 'BBB' :case 'CCC' :case 'DDD' :
   c.parentNode.style.display = c.checked ? '' : 'none';
  }
 }
}

process(document.getElementById('hoge1').getElementsByTagName('input'));
// process(document.forms[0].elements);

まあ、form.elements を使う方は「"#hoge1" の内部」という条件を無視していますけどね。実を言うと、querySelectorAll() はネイティブメソッドの中では遅い方です。しかし、"#hoge1 *.Parents > *.child > input'"というセレクタによって、"#hoge1" の存在と、input の親である ".child" の存在が自然に保証されます。上に書いた process() 関数は単純ですが、"#hoge1" が存在しているか、c.parentNode が ".child" であるか、については無視していることに注意して下さい。

ちなみに、document.getElementsByName() を使うべきではありません。フォームを飛び越えますし、meta、param、map などまで拾う可能性があります。今回はどの道、使わないでしょうが。

> 子孫セレクタを排除

子の ">"、隣接の "+" などを使って下さい。子孫の深さがそれほどでもなければ子孫セレクタの方が速い場合もありますが。

---
セレクタを「右から左」に評価するのは、リストから候補をふるい分けるときです。処理速度はリストに含まれるノード数に比例します。

[a, b, c, d].filter(selectors) ===> [a, c]

セレクタを「左から右」に評価するのは、リストの変化をステップごとに追いかけるときです。ステップ数と中間リストの要素数に応じて、処理速度が相乗的に増えます。

[a].map(step1) ===> [b, b, b].map(step2) ===> [c, c, c, c, c]

jQuery は「左から右」方式です。つまりセレクタが短く、中間リストの要素数が少なければ速く処理できます。しかしセレクタが長かったり、中間リストの要素数が多ければ処理速度がガクっと落ちます。

投稿日時 - 2011-10-25 22:00:08

ANo.2

jQuery を使う時点で速度は度外視だと思いますが……。

まだ草案が出たばかりですが、Selectors Level 4 なら次の CSS だけで済む話です。

/* チェックの入っていない input を持つ li.child を非表示にする */
#hoge1 *.Parents > ?*.child > input:not(:checked) {
 display: none;
}

これを現在の実装だけで行うよう「変換」すれば良い。

Array.prototype.forEach.call(
 // チェックの入っていない input を取得
 document.querySelectorAll(
  '#hoge1 *.Parents > *.child > input:not(:checked)'
 ),
 function (input) {
  // その input の親である li.child を非表示にする
  input.parentNode.style.display = 'none';
 });

jQuery を使うときも同じです。:checked は標準の疑似クラスですから、jQuery の独自拡張よりも率先して使って下さい。

※jQuery は内部的に querySelectorAll() を試し、その後で独自エンジンを走らせます。速度を考慮するなら、独自エンジンを走らせる回数を減らすべきです。もしどうしても独自エンジンを走らせざるをえないなら、jQuery の特性上、子孫セレクタを極力排除して下さい。

それと、フォーム部品を使う時は form の中に入れた方がスクリプト操作の面で有利ですよ。

投稿日時 - 2011-10-25 02:23:53

補足

ご回答ありがとうございます。

「Selectors Level 4」の存在を初めて知りました。
「Selectors API 」はかなり便利そうですね 。
書き忘れで申し訳ないのですが、IE7も視野に入れているため、
別の場面で是非手を出してみようと思います。

>※jQuery は内部的に querySelectorAll() を試し、その後で独自エンジンを走らせます。速度を考慮するなら、独自エンジンを走らせる回数を減らすべきです。

jQueryはそのような仕組みになっていたのですね。
今後、知識が着いてきたらjQueryの内部を見てみます。
勉強になりました。

>jQuery の特性上、子孫セレクタを極力排除して下さい。

子孫セレクタを排除といいますのは、
$ (ul.Parents li.child)ではなく、$ (ul.Parents)を使用する。と言う事なのでしょうか。
(ブラウザは、右から左にセレクタを解釈しながら描画する事と関係があったり?)

>フォーム部品を使う時は form の中に入れた方がスクリプト操作の面で有利ですよ。
こちらも記載忘れで申し訳ないです。
最終的にはformに入れ、submit後、PHPで処理を行う予定です。

jQueryを使用しない場合はgetElementByIdをクラス名指定で取得後、
displayをnoneするつもりだったのですが、formに入れる事でもっと効率のいい方法があるのでしょうか?


質問の連続で大変申し訳ないのですが、よろしくお願い致します。

投稿日時 - 2011-10-25 10:04:04

$(":checkbox:unchecked").hide();

この一行でいけるんじゃないかな?

投稿日時 - 2011-10-25 02:04:12

補足

ご回答ありがとうございます。
「unchecked」
このような指定は初めて知りました。
勉強になります。
是非試してみます。

投稿日時 - 2011-10-25 09:25:30

あなたにオススメの質問