コンパイラかく語りき

import { Fun } from 'programming'

ちょっと離れたところにあるDOMにどうやってアクセスするか

どうも!chuckです。

昨日仕事で以下の機能を実装しました。

checkboxが10個並んだ選択画面がある。従来はcheckboxの横にテキストがついているだけだった。

そこに画像を追加することとなったので改修。

ただし、checkboxの選択状態によって画像は変化する。

 

カンタンなようでいくつかのアプローチがあり、アルゴリズム的な面白さがあったのでメモ。

 

 

 まずこちらが完成イメージ。

f:id:chuck0523:20150702225525p:plain

http://chuck0523.github.io/front-end-coding/checkboxOnOff/checkboxOnOff.html

 

画像(顔文字がついてるやつ)が変わるきっかけは3つ。

  1. チェックボックスをクリックする
  2. 画像そのものをクリックする
  3. ALLボタンをクリックする

 

HTMLの構造はこう。

gist.github.com

 

ここで、画像とチェックボックスとテキストのワンセットを「ボタンラベル」と呼ぶことにする。

1つのボタンラベルの構造は以下のとおり。

 

gist.github.com

 

 

順番に見ていきましょう。

1,チェックボックスをクリックする

これは操作的にはわかりやすいと思います。単純にチェックが入ったら隣接する画像を切り替える。

ただしDOM同士は距離があり、複数のアクセス方法が考えられます。

 

jQueryセレクタでたどっていく

input[type=checkbox]を起点にして、

$(this).closest('div.check').prev().toggle();

とたどって行けます。

  •  closest('hoge')  :hoge要素を上位要素の中から探し続けます。
  • prev();直近の兄要素を参照します。
  • toggle() ;show()とhide()を同時に行います。

というわけで、セレクタによって対象を探してtoggleによって切り替えています。直感的でわかりやすいですね。

ただしデメリットがあり、途中に要素が追加になった時に動かなくなってしまいます。

 

例えば以下のように、<div class="check">と<div class="imgs">の間に新規要素が追加になったとします。

gist.github.com

 

すると、チェックボックスの親要素である<div class="check">までは辿ることができます。しかし、prev()が参照するものは直近の兄要素であり、新規要素が割り込んだことによってprev()が<div>NEW!!</div>を参照するようになってしまいます。

 

②.index()を使って序列で管理する

序列を使って間接的に参照するのがindex()を使う方法です。

var index = $('.soleCheck').index($(this));

$('.imgs').eq(index).toggle();

 

  • index() ;全ての要素の中からその要素が何番目の要素であるかを取得する
  • .eq(index);cssのnth-childに相当。全ての要素の中からindex番目の要素を参照

クリックされたチェックボックスが何番目のチェックボックスであるかを取得して、同じくその順番の画像を切替えています。

これならばDOM構造が変わっても、チェックボックスと画像のセットが変わらない限り問題ありません。

ただし、これはチェックボックスと画像がセットになっていることが不可欠であり、1つでも抜けがあると(チェックボックスの無いラベルボタンなど)、切り替えの対象がズレこんでしまいますヽ(´Д`;)ノ

 

 

2,画像そのものをクリック

次に画像そのものがクリックされた場合を考えます。とは言え考え方は先ほどと同じです。今度は画像の方からチェックボックスにアクセスすればいいのです

 

3,ALLボタンがクリックされたとき

これもロジックとしては面白いのですが、DOM要素の話とは離れてしまうのでここでは割愛します。実装の仕方について質問がありましたがお気軽にお問い合わせください。

 

 

 

というわけで、DOM要素のアクセスの仕方について書きました。

おそらく上記で挙げた2つ以外にも方法はあると思います。その時々の最適なDOMアクセスを考えることが大切ですね!ではヽ(=´▽`=)ノ