jQueryで最も近い直近の親要素と最も近い直近の子要素を取得する

jQueryで親要素や子要素を取得する方法はいくつかありますが、リストなどのように同じような階層が深く続いているものでは最も近い要素を選択したいときがあります。そのようなときにjQueryではどのように要素を取得するのか紹介します。

直近の親要素を取得


<div class="a">
  <div class="b">
    <div class="a">選択される要素
      <div class="b">
        <div class="c">スタート地点</div>
      </div>
    </div>
  </div>
</div>

var parent = $('.c').closest('.a');

.c から最も近い .a クラスを持った親要素が選択されます。最も近い親要素が選択されるので、一番上の階層の .a 要素は選択されません。

2番目に近い要素を取得


<div class="a">
  <div class="b">選択される要素
    <div class="a">
      <div class="b">
        <div class="c">スタート地点</div>
      </div>
    </div>
  </div>
</div>

var parent = $('.c').closest('.b').parent().closest('.b');

直近ではなく、2番目に近い要素を取得したいときはこのように記述します。まず、$('.c').closest('.b') で直近の .b 要素を取得し、parent() で1階層上に上がり、そこで再び直近の .b 要素を探して取得します。


var parent = $('.c').closest('.b').closest('.b');

ちなみに parent() を省いてしまうと、closest()自身も含めて探索するため結果は直近の .b 要素となってしまいます。

直近の子要素を取得


<div class="a">スタート地点
  <div class="b">
    <div class="c">
      <div class="d">選択したい要素
        <div class="c">
          <div class="d"></div>
        </div>
      </div>
    </div>
  </div>
</div>

今度は逆に直近の子要素を取得してみます。.a 要素をスタートとして直近の .d 要素を対象にします。jQueryの関数には closest() 関数の逆はないので、自作してみます。

直近の子要素を取得する関数


$.fn.closestOpposite = function(selector) {
  // 1階層下の子要素を取得
  var children = this.children();
  
  // 子要素がないときは探索終了
  if (children.length === 0) return $();
  
  // 現在の要素が探索するクラス名を持っていたとき
  if (this.filter(selector).length) {
    return this.filter(selector);
  }
  
  // それ以外のときはさらに下層を再帰的に探索
  return children.closestOpposite(selector);
};

var child = $('.a').closestOpposite('.d');

これで直近の子要素を取得することができます。jQueryには子要素を取得する関数として、children()find() がありますがどちらも直近の子要素を取得することはできません

細かい挙動


<div class="a">スタート地点
  <div class="b">
    <div class="c">
      <div class="d">
        <div class="c">
          <div class="d"></div>
        </div>
      </div>
    </div>
  </div>
  <div class="c">
    <div class="d">選択される要素
      <div class="c"></div>
    </div>
  </div>
</div>

また、このように複数の場所に .d 要素があるときは階層が浅い方(直近)を取得します。


<div class="a">スタート地点
  <div class="c">
    <div class="d">選択される要素
      <div class="c"></div>
    </div>
  </div>
  <div class="c">
    <div class="d">選択される要素
      <div class="c"></div>
    </div>
  </div>
</div>

.d 要素が同じ階層にあるときは両方取得します。