【jQuery】closest()で最も近い親要素を取得する完全ガイド|parents・parent・DOM走査の使い分けまで

jQueryの closest() は、ある要素から上に向かってDOM階層を走査し、セレクターに一致する最も近い祖先要素(または自分自身)を取得します。イベントデリゲーションや削除ボタンの実装で頻繁に使われる重要なメソッドです。この記事ではclosest・parent・parents・parentsUntilの違いと実用パターンまで解説します。

この記事でわかること

  • closest() で最も近い祖先要素を取得する基本
  • parent() / parents() / closest() の違い
  • イベントデリゲーションと組み合わせた活用パターン
  • フォームの入力欄からエラー表示要素を辿るパターン
  • parentsUntil() で範囲を指定して取得する
スポンサーリンク

parent / parents / closest の違い

メソッド 取得範囲 自分自身 マッチ数
parent() 1つ上の親要素のみ 含まない 0 or 1
parents() 全祖先要素 含まない 0以上(複数)
closest() 最初にマッチした祖先 含む 0 or 1
parentsUntil() 指定要素より手前の全祖先 含まない 0以上

実務ではほとんどの場合 closest() が最適です。HTML構造が変わっても最初にマッチした祖先を返すため、堅牢なコードになります。

closest() の基本的な使い方

<ul id="todo-list">
  <li class="todo-item">
    <span class="todo-text">タスク1</span>
    <button class="delete-btn">削除</button>
  </li>
</ul>
$(function () {
  // 削除ボタンから最も近い li 要素を取得して削除
  $(document).on('click', '.delete-btn', function () {
    var $item = $(this).closest('.todo-item');
    console.log('削除対象:', $item.find('.todo-text').text());
    $item.remove();
  });

  // closest() は自分自身も対象になる
  // → ボタン自身が .delete-btn なら $(this).closest('.delete-btn') は自分を返す
  console.log('自分自身:', $('.delete-btn').closest('.delete-btn').length); // 1
});
closest() は自分自身から始めて上に辿る
parents() と違い、closest() は自分自身も検索対象に含みます。まず自身がセレクターに一致するかチェックし、一致しなければ親・祖父…と上に辿ります。

フォームのエラー表示と組み合わせる

<div class="form-group">
  <label>メールアドレス</label>
  <input type="email" class="form-control" name="email">
  <p class="error-msg" style="display:none; color:red"></p>
</div>
$(function () {
  // 入力欄からフォームグループを辿ってエラーメッセージを表示
  function showError($input, message) {
    $input.closest('.form-group')
      .find('.error-msg')
      .text(message)
      .show();
    $input.addClass('is-invalid');
  }

  function clearError($input) {
    $input.closest('.form-group')
      .find('.error-msg')
      .hide();
    $input.removeClass('is-invalid');
  }

  $('input').on('blur', function () {
    if ($(this).val() === '') {
      showError($(this), '必須入力です');
    } else {
      clearError($(this));
    }
  });
});
closest() + find() のコンビが強力
closest(".form-group").find(".error-msg") のパターンは、入力欄から同じフォームグループ内のエラー要素を確実に取得できます。HTML構造が深く入れ子になっていても、この書き方は安定して動作します。

parents() と parentsUntil() の使い方

$(function () {
  // 全ての祖先要素を取得(遠い順)
  var $ancestors = $('#target').parents();
  console.log('祖先の数:', $ancestors.length);

  // セレクター付きで祖先をフィルタリング
  var $sections = $('#target').parents('section');
  console.log('section祖先:', $sections.length);

  // parentsUntil: 指定要素の手前まで全祖先を取得
  // #container の手前まで(#container 自身は含まない)
  var $between = $('#target').parentsUntil('#container');
  $between.addClass('highlight'); // 中間の祖先要素をハイライト
});

実用的なパターン集

$(function () {
  // テーブル行のデータ取得(ボタンが複数列ある場合)
  $(document).on('click', '.edit-btn', function () {
    var $row  = $(this).closest('tr');
    var id    = $row.data('id');
    var name  = $row.find('.name-col').text();
    console.log('編集:', id, name);
  });

  // アコーディオンの開閉(クリックされた見出しから親パネルを辿る)
  $(document).on('click', '.accordion-header', function () {
    var $panel = $(this).closest('.accordion-item');
    $panel.toggleClass('is-open');
    $panel.find('.accordion-body').slideToggle();
  });

  // ドロップダウンの外側クリックで閉じる
  $(document).on('click', function (e) {
    // クリックが .dropdown の内側でなければ閉じる
    if ($(e.target).closest('.dropdown').length === 0) {
      $('.dropdown').removeClass('is-open');
    }
  });
});

まとめ

jQueryで祖先要素を取得する際のポイントをまとめます。

  • closest(sel): 最も近い祖先(自分自身も含む)→ 実務でほぼこれ
  • parent(): 1つ上の親のみ
  • parents(sel): 全祖先(セレクターでフィルタ可能)
  • 定番パターン: closest(".group").find(".target")

関連記事: 要素を削除する完全ガイド / 要素を別の要素に置き換える方法

よくある質問(FAQ)

Qclosest()が undefined になります。
Aclosest() はマッチしなかった場合、空のjQueryオブジェクトを返します(undefinedではありません)。.length === 0 で確認できます。セレクター文字列("li")ではなくDOM要素(document.querySelector("li"))を渡してしまっていないか確認してください。
Qclosest()とparents().first()の違いは何ですか?
Aclosest() は自分自身もチェックしますが、parents().first() は親要素から始まります。また parents() は全マッチを返すため parents("li").first() は最も近い li 祖先を返しますが、closest("li") の方が簡潔で自分自身もチェックするため正確です。
Qイベントが起きた要素からフォームを取得したいです。
A$(this).closest("form") でフォーム要素を取得できます。さらに .serialize() でフォーム内の値をまとめて取得できます:var data = $(this).closest("form").serialize();
Q孫要素から祖父要素を取得したいです。
Aclosest() は何層でも上に辿れます。$(this).closest(".grandparent-class") のようにセレクターを指定すれば、何層上にあっても最初にマッチした要素が返されます。
Q祖先要素を複数取得して全てにクラスを付けたいです。
Aparents() でセレクターに一致する全祖先を取得できます:$(this).parents(".section").addClass("is-active")または全祖先に対して $(this).parents().addClass("has-active-child") も使えます。