白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

closestメソッドは自身を含むよ

こんばんは。

ずいぶん久しぶりになってしまいました。
台風が近づく三連休初日、いかがお過ごしでしょうか。

さて、もうタイトルがすべてっていえばそれまでなのですが、
久しぶりにまじめにJavaScript(jQuery)を書いたら罠にはまったのでメモ。

.closest()ってどんなメソッド

.closest() | jQuery API Documentation

リンク先に

For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.

とあるように、DOMツリー内の祖先をトラバース、
つまり自身の要素をもとに外側に辿って行き、一番最初に見つかった要素を返すメソッドです。

<ul>
    <li id="item1">その1</li>
    <li id="item2">その2</li>
</ul>

というDOMに対して、

$("#item1").closest("ul");

と書くと直上のul要素を取得できます。
これは「.parent()」メソッドを使っても変わりません。

<ul>
    <li class="item"><a href="#">その1</a></li>
    <li class="item"><a href="#">その1</a>その2</li>
</ul>

というDOMに対して、

$("#item1 a").closest("ul");

としても、セレクタに一致するまで遡ってくれるのでul要素を取得できます。
parentを使っている場合よりも柔軟な構造変更が可能なわけです。

で、罠

DOMをもうちょっと複雑にしてみます。いわゆる入れ子構造。

<ul id="list1">
    <li id="item1">
        <ul id="item1-list1">
            <li id="item1-1">その1の1</li>
            <li id="item1-2">その1の1</li>
        </ul>
    </li>
    <li id="item2">その2</li>
</ul>

ディレクトリとか表現するときにはよくあるパターンですね。

$("#item1-1").closest("ul");

とすると当然直上のul、つまり#item1-list1を取得することができます。
されにその外側のulまで遡ろうとして、こう書くと、

$("#item1-1").closest("ul").closest("ul");

#list1が取れません
取れている要素を確認してみると#item1-list1になっています。

要するに先祖と言っている中には自分自身を含んでいるってことですね。

$("#item1-1").parents("ul").eq(1);

とかがいいのかな。もっといい方法あるのかな。

そんな罠に掛ったよっていうお話でしたとさ。