一柄轻剑能伤敌,靠的是认得清敌我。选中一个元素之后,还得会看它的出身、父母、兄弟—— 这些“亲戚关系”,就是遍历。这一式,我们学会在元素家族里认亲。

本式要点
  • 用 parent / children / find / siblings / next / prev / closest 在家族里认亲
  • 理解 closest 与事件委托的黄金配合
  • 会用 each() 逐个处理选中的元素
  • 会用 filter / first / last / eq 缩小包围圈
  • 会用 not / is / has 与 Until 系列做更聪明的问询

元素的家族关系

把页面看成一张家谱——每个标签都是某个标签的子嗣。按钮小友的一家,长这样:

document
└── html
    ├── head
    └── body
        ├── header
        └── main
            ├── h2(标题)
            ├── .card(第一张)── siblings:互为兄弟
            │   └── button(点我)← 你在这里
            ├── .card(第二张)── next() / prev():同级的前后邻居
            └── p(段落)

围绕这张家谱,jQuery 准备了一组“认亲”方法:

方法家族说法找谁
parent()找父亲上一级父元素,只找一层
parents()列祖列宗所有祖先;可传选择器过滤,如 parents('.page')
children()亲儿子直接子元素;可传选择器过滤
find()满门子孙所有后代;必须传选择器,如 find('a')
siblings()兄弟姐妹同级全部;可传选择器过滤
next() / prev()紧邻的弟与兄后一个 / 前一个同级元素,各只找一个
closest()一路向上寻亲从自己开始向上,找最近的匹配;必须传选择器,可能命中自己

向上找:parent / parents / closest

parent() 只找上一级;parents() 把一路向上的祖先全部找来(可传选择器过滤); closest(选择器) 从自己开始向上,返回最近的一个匹配。 最后一个正是事件委托的黄金搭档——事件绑在父级上,处理时却要操作“所在的那张卡片”,一记 closest 就位。

例 1 · closest 高亮按钮所在的卡片
内功卡

吐纳打坐,贵在坚持。

轻功卡

每日一纵,身轻如燕。

剑法卡

剑走轻灵,意在剑先。

按钮在 .card-body 里,卡片在两层之上——不管隔几层, closest('.card') 都能一步找到“最近的卡片”,三张卡各管各的。

向下找:children / find

往下走的两个方法分工明确:children() 只认亲儿子(直接子元素), find() 认满门子孙(所有后代,必须传选择器)。拿例 1 的卡片阵试刀:

三张卡都住在 .col 列里面,所以对 #jq07-deck 来说它们不是“儿子”而是“孙子”—— children 扑空,find 全中。想找哪层,先想清楚辈分。

兄弟姐妹:siblings / next / prev

同级之间也有讲究:siblings() 把兄弟姐妹一网打尽(可传选择器过滤), next() / prev() 只找紧挨着的后一个 / 前一个。

逐个点名:each()

jQuery 对选中集合的隐式遍历是“一声令下,全员行动”。可有些活儿必须逐个点名—— 比如“隔一行染一色”,得知道每个元素排第几。这时请 each() 出场:

例 2 · each 给表格隔行变色
招式境界口诀
选择器入门找到即命中
事件入门点谁谁回应
动画进阶动静皆有度
遍历进阶认亲不迷路

index % 2 === 1 挑出第 2、4 行(序号从 0 数,奇数序号正是视觉上的偶数行)。 顺带一提::even / :odd 这类位置伪类在 jQuery 4 里依然能用, 但官方更推荐用 each 或 filter 这种“看得见逻辑”的写法—— 判断条件白纸黑字写在那儿,两年后回看也知道自己当时在想什么。

例 3 · each 统计列表项,拼成一句话
  • 选择器
  • 内容与属性
  • 类与样式
  • 事件

点上面的按钮,看结果。

这就是 each 的日常:一边走一边收集,走完再统一收尾。 记一笔——each 走完后会把原来的集合原样还回来,链式调用不受影响。

缩小包围圈:filter / first / last / eq

选中一堆元素后,还可以从中再挑:first() 取第一个、last() 取最后一个、 eq(2) 取序号为 2 的那一个(即第三个,从 0 数)、filter() 按选择器或函数筛选。

心法:回顾隐式遍历

第一式就见过它:$('p').css('color', 'red') 会让所有段落变红。 隐式遍历是 jQuery 的默认性格——“对选中的每个元素都动手”;而本式的遍历方法负责“换个圈子再动手”。 位置伪类 :first / :last 在 jQuery 4 里仍然可用,但方法版 .first() / .last() 更清晰、也更快——官方推荐日常改用方法版。

再认几门亲戚:not / is / has 与 Until 系列

除了“往上找、往下找、找兄弟”,jQuery 还备了几个更聪明的问法: not() 是“排除掉某些”,is() 是“判断是不是”(返回 true / false, 不返回集合),has() 是“谁的子孙里有它”。

方法问法返回
not(选择器 / 函数)除了这些,剩下的给我集合
is(选择器)这批元素里有没有符合的?符合一个就算 truetrue / false
has(选择器)谁的内部(子孙)藏着匹配元素集合
parentsUntil() / nextUntil() / prevUntil()边走边找,走到谁为止(不含终点)集合
add() / addBack() / end()把另一批元素、上一环或起点并进来一起操作集合
contents()连文本节点、注释节点也一并取出(主要在 iframe 场景用)集合
例 4 · 问法练习:not / is / has / nextUntil
  • 门派名册(我有一份子名单)
    • 入门心法(已成)
    • 吐纳(未成)
    • 剑法(未成)
    • 轻功(未成)
点按钮,看每次问中了哪些。
练功 · 第七式
  1. 修改例 1:要求同一时刻只有一张卡高亮——点击前先把所有卡片的高亮洗掉,再点亮自己。
  2. 给例 1 的按钮再加一招:标记卡片的同时,把所在卡片的标题也染成朱砂色(text-danger)。
  3. 思考题:parents('.card') 与 closest('.card') 有什么区别?
参考答案 1

“先全局清洗、再局部点亮”是做“唯一选中”的常见套路; closest 负责把按钮的点击翻译成“所在卡片”的操作。

参考答案 2

closest 向上找到卡片、find 向下找到标题—— 上上下下的配合,正是遍历方法的日常。

参考答案 3

parents() 返回所有匹配的祖先(不含自己,可能有多个,由近及远排列); closest() 从自己开始向上,返回最近的一个匹配(结果零个或一个)。 例 1 里两者都能找到卡片;但如果按钮自己也带 .card 类, closest 会返回按钮本身,而 parents 不会。找全部用 parents,找最近用 closest。

本式小结

  • 元素是一棵树:parent / parents / children / find 上下认亲,siblings / next / prev 同级走动;
  • closest 从自己向上找最近匹配,是事件委托的黄金搭档;
  • each(function (index, element)) 逐个点名,index 从 0 起,element 就是 this;
  • filter / first / last / eq 缩小包围圈;隐式遍历是“对每个选中元素都动手”的默认行为;
  • not 排除、is 判断(返回布尔值)、has 找“子孙里有的”;nextUntil / prevUntil / parentsUntil 走到谁为止(不含终点);
  • addBack() 把起点或上一环并回来,add() 并入另一批元素。
下一式,我们搭积木——节点的增删改。