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