jQuery DOM 遍歷 (Traversing)
DOM 遍歷是指從一個元素出發,在 DOM 樹中移動尋找其他相關的元素。jQuery 提供了豐富的遍歷方法,讓你能夠輕鬆地找到父元素、子元素、兄弟元素等。
祖先遍歷(向上)
parent() - 直接父元素
取得每個匹配元素的直接父元素:
// 取得 span 的父元素
$('span').parent();
// 加上選擇器過濾
$('span').parent('.container'); // 只返回 class 為 container 的父元素
parents() - 所有祖先元素
取得每個匹配元素的所有祖先元素,一直到 <html>:
// 取得 span 的所有祖先元素
$('span').parents();
// 加上選擇器過濾
$('span').parents('div'); // 只返回 div 祖先元素
$('span').parents('.wrapper'); // 只返回 class 為 wrapper 的祖先
parentsUntil() - 到指定祖先為止
取得從當前元素到指定祖先之間的所有祖先元素(不含指定祖先):
// 取得 span 到 #container 之間的所有祖先
$('span').parentsUntil('#container');
// 可以加上第二個參數過濾
$('span').parentsUntil('#container', 'div'); // 只返回其中的 div
closest() - 最近的匹配祖先
從當前元素開始(包含自身),找到第一個匹配的祖先元素:
// 找到最近的 .panel 祖先(可能是自己)
$('button').closest('.panel');
// 在事件處理中很常用
$('button').on('click', function () {
var $panel = $(this).closest('.panel');
$panel.addClass('active');
});
closest() 與 parents() 的主要差異:
closest()包含當前元素本身,且只返回第一個匹配的祖先parents()不包含當前元素,會返回所有匹配的祖先
offsetParent() - 定位父元素
取得最近的定位祖先元素(position 不為 static):
$('.item').offsetParent();
後代遍歷(向下)
children() - 直接子元素
取得每個匹配元素的直接子元素:
// 取得 ul 的所有直接子元素
$('ul').children();
// 加上選擇器過濾
$('ul').children('li'); // 只返回 li 子元素
$('ul').children('.active'); // 只返回 class 為 active 的子元素
find() - 搜尋所有後代
在匹配元素的所有後代中搜尋:
// 在 #content 的所有後代中搜尋 span
$('#content').find('span');
// 搜尋所有後代元素
$('#content').find('*');
children() 只搜尋直接子元素,find() 會搜尋所有後代(包含孫元素、曾孫元素等)。contents() - 所有子節點
取得每個匹配元素的所有子節點,包含文字節點和註解節點:
// 取得 div 的所有子節點(包含文字節點)
$('div').contents();
// 常用於操作 iframe 內容
$('iframe').contents().find('body');
兄弟遍歷(水平)
siblings() - 所有兄弟元素
取得每個匹配元素的所有兄弟元素:
// 取得 .active 元素的所有兄弟
$('.active').siblings();
// 加上選擇器過濾
$('.active').siblings('li');
$('.active').siblings('.item');
next() - 下一個兄弟
取得每個匹配元素緊鄰的下一個兄弟元素:
// 取得 .current 的下一個兄弟
$('.current').next();
// 加上選擇器過濾
$('.current').next('.item'); // 只有當下一個兄弟符合條件時才返回
nextAll() - 之後所有兄弟
取得每個匹配元素之後的所有兄弟元素:
// 取得 .current 之後的所有兄弟
$('.current').nextAll();
// 加上選擇器過濾
$('.current').nextAll('.item');
nextUntil() - 到指定兄弟為止
取得每個匹配元素之後,到指定兄弟之前的所有兄弟元素:
// 取得 #start 到 #end 之間的所有兄弟
$('#start').nextUntil('#end');
// 可以加上第二個參數過濾
$('#start').nextUntil('#end', 'li');
prev() - 上一個兄弟
取得每個匹配元素緊鄰的上一個兄弟元素:
// 取得 .current 的上一個兄弟
$('.current').prev();
// 加上選擇器過濾
$('.current').prev('.item');
prevAll() - 之前所有兄弟
取得每個匹配元素之前的所有兄弟元素:
// 取得 .current 之前的所有兄弟
$('.current').prevAll();
// 加上選擇器過濾
$('.current').prevAll('.item');
prevUntil() - 到指定兄弟為止
取得每個匹配元素之前,到指定兄弟之後的所有兄弟元素:
// 取得 #end 到 #start 之間的所有兄弟
$('#end').prevUntil('#start');
過濾方法
filter() - 篩選符合條件
從匹配的元素中篩選出符合條件的:
// 篩選出有 .active class 的 li
$('li').filter('.active');
// 使用函式篩選
$('li').filter(function (index) {
return index % 2 === 0; // 篩選偶數索引的元素
});
// 使用函式檢查內容
$('li').filter(function () {
return $(this).text().length > 10; // 文字長度大於 10
});
not() - 排除符合條件
從匹配的元素中排除符合條件的:
// 排除有 .disabled class 的 li
$('li').not('.disabled');
// 使用函式排除
$('li').not(function (index) {
return $(this).hasClass('hidden');
});
first() - 第一個元素
取得匹配元素中的第一個:
$('li').first();
last() - 最後一個元素
取得匹配元素中的最後一個:
$('li').last();
eq() - 指定索引的元素
取得匹配元素中指定索引位置的元素(索引從 0 開始):
$('li').eq(0); // 第一個
$('li').eq(2); // 第三個
$('li').eq(-1); // 最後一個(負數從後面數)
$('li').eq(-2); // 倒數第二個
slice() - 範圍選取
取得匹配元素中指定範圍的元素:
$('li').slice(0, 3); // 前三個(索引 0, 1, 2)
$('li').slice(2); // 從第三個開始到最後
$('li').slice(-3); // 最後三個
$('li').slice(1, -1); // 去掉第一個和最後一個
其他方法
is() - 判斷是否符合
檢查匹配元素是否符合指定條件,返回布林值:
// 檢查是否有 .active class
if ($('#item').is('.active')) {
console.log('是 active 狀態');
}
// 檢查是否隱藏
if ($('#box').is(':hidden')) {
console.log('元素是隱藏的');
}
// 在事件中檢查目標
$('a').on('click', function (e) {
if ($(e.target).is('.external')) {
// 處理外部連結
}
});
has() - 是否包含子元素
篩選出包含指定子元素的元素:
// 篩選出包含 span 的 div
$('div').has('span');
// 篩選出包含 .error 的 form
$('form').has('.error');
add() - 加入更多元素
將額外的元素加入到當前匹配的元素集合中:
// 選取所有 p 和 span
$('p').add('span');
// 等同於
$('p, span');
// 加入 DOM 元素
var div = document.getElementById('extra');
$('p').add(div);
// 在特定上下文中加入
$('p').add('span', '#container');
addBack() - 加入前一個選擇狀態
將前一個選擇狀態的元素加入到當前集合:
// 選取 ul 及其所有 li 子元素
$('ul').children('li').addBack();
end() - 回到前一個選擇狀態
在鏈式呼叫中,回到上一個選擇狀態:
// 選取 ul,對 li 做操作,然後回到 ul
$('ul')
.find('li')
.addClass('item')
.end() // 回到 ul
.addClass('list');
// 多層回退
$('ul')
.find('li')
.find('a')
.addClass('link')
.end() // 回到 li
.addClass('item')
.end() // 回到 ul
.addClass('list');
each() - 迭代處理
對每個匹配元素執行函式:
$('li').each(function (index, element) {
console.log(index, $(this).text());
// 如果返回 false,會中斷迭代
if (index >= 5) {
return false;
}
});
map() - 映射轉換
將每個匹配元素通過函式轉換,返回新的 jQuery 物件:
// 取得所有 li 的文字,組成陣列
var texts = $('li')
.map(function () {
return $(this).text();
})
.get();
// 取得所有 input 的值
var values = $('input')
.map(function () {
return $(this).val();
})
.get();
遍歷方法比較表
| 方法 | 方向 | 說明 |
|---|---|---|
parent() | 向上 | 直接父元素 |
parents() | 向上 | 所有祖先元素 |
parentsUntil() | 向上 | 到指定祖先為止 |
closest() | 向上 | 最近的匹配祖先(含自身) |
children() | 向下 | 直接子元素 |
find() | 向下 | 所有後代中搜尋 |
siblings() | 水平 | 所有兄弟元素 |
next() / prev() | 水平 | 下/上一個兄弟 |
nextAll() / prevAll() | 水平 | 之後/之前所有兄弟 |
nextUntil() / prevUntil() | 水平 | 到指定兄弟為止 |
實用範例
找到表格中的特定欄位
// 點擊按鈕時,找到同一列的其他欄位
$('table').on('click', 'button', function () {
var $row = $(this).closest('tr');
var name = $row.find('.name').text();
var email = $row.find('.email').text();
console.log(name, email);
});
手風琴選單
$('.accordion-header').on('click', function () {
var $content = $(this).next('.accordion-content');
// 關閉其他
$(this).parent().siblings().find('.accordion-content').slideUp();
// 切換當前
$content.slideToggle();
});
標籤頁切換
$('.tab').on('click', function () {
var index = $(this).index();
// 切換標籤狀態
$(this).addClass('active').siblings().removeClass('active');
// 切換內容
$('.tab-content').eq(index).show().siblings().hide();
});