news 2026/9/26 8:42:54

jQuery选择器详解:从基础语法到动态页面实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
jQuery选择器详解:从基础语法到动态页面实战

1. 开始之前:jQuery选择器的定位与学习路径

1.1 为什么现在学jQuery选择器还不过时

“新项目谁还在用jQuery”这个话题,我身边每隔一段时间就会被拿出来吵一次。尤其这两年前端框架越来越重,动不动就是脚手架、组件化,初学者很容易产生一种错觉:jQuery已经是老古董,没必要浪费时间。但只要你碰过一次老项目的维护,或者在兼容要求比较高的活动页里写过脚本,就会理解“jQuery还有必要学吗”这个问题不能一概而论。而即便抛开维护场景,jQuery 选择器本身也值得花时间吃透,因为它是理解“如何精准定位页面元素”的最直接入口。

先摆一个事实:很多仍在稳定运行的后台管理系统、电商平台活动页、旧版 CMS,内部还是大量 jQuery 代码。就算你用 Vue 或 React 重写了大部分功能,只要还保留着 Datatables、EasyUI、日期选择器这类老牌插件,就免不了跟 jQuery 对象打交道。这时候懂不懂选择器,直接决定你能不能在三分钟内改完一个需求,还是连排查都要翻半天文档。

更重要的是,jQuery 选择器的语法几乎沿用了 CSS 选择器规范,又额外扩展了:eq、:contains、:first这类方便伪类。你把这套规则学扎实,后面切换到原生querySelectorAll,或者去理解 CSS 选择器的优先级,都非常顺滑。可以说,选择器是 jQuery 里最值得背下来的一块知识,性价比极高。

1.2 一条适合新手的学习路径和优先级

有些人学 jQuery 喜欢一上来就翻 API 文档,看事件、看动画、看 Ajax,结果用到选择器的时候总是临时查,写出来的代码又长又绕。我的建议是把它当成一条完整链路的前置环节:选择器 → DOM 遍历与操作 → 事件 → 动画 → Ajax → 组件封装。

选择器这一步,又可以按下面的分类顺序去消化:

阶段学习内容典型写法解决的问题
基础选择器id、class、标签、通配、并集$("#id")$(".class")$("p")快速定位一个或一类元素
层级选择器后代、子元素、兄弟$("ul li")$("ul > li")$("h3 + p")按 DOM 结构关系定位元素
筛选选择器位置、子元素位置、内容、属性$("li:first")$("li:first-child")在集合内进一步过滤目标

这三类掌握以后,再去看.find()、.children()、.filter()这类遍历方法,就会觉得顺理成章。你甚至可以这样理解:选择器负责“找到起点”,遍历方法负责“在起点周围进一步移动”,两者经常搭配使用。

下面我按这三个分类逐个讲,并把实际项目里容易踩的坑标出来。

2. 基础选择器:写 jQuery 的本能反应

2.1 ID 选择器与类选择器

ID 选择器是 jQuery 里查询效率最高的,因为底层可以直接映射到document.getElementById。写法就是$("#id"),#后面对应元素的 id 属性值。类选择器用.class,最终拿到的是一组元素,哪怕页面里只有一个元素匹配,外层也是一个类数组结构的 jQuery 对象。

// 选中 id 为 userName 的元素 var $name = $("#userName"); // 选中所有 class 包含 menu-item 的元素 var $menuItems = $(".menu-item");

这里有个新手经常犯的错:拿到类选择器结果以后直接调.value取输入框内容。jQuery 对象不是原生 DOM,取输入框值要用.val(),取文本用.text(),取属性用.attr()。如果确实拿到的是原生 DOM,应该写$(".menu-item")[0].value,或者说用.get(0)。

还要注意,id 在页面中必须是唯一的。后端模板引擎、服务端控件渲染时偶尔会生成带冒号的 id,比如ctl00_ContentPlaceHolder1_txtName这种倒还好,但如果 id 里真的包含:,直接$("#id:name")会被解析成伪类,必须转义成$("#id\\:name")。顺带提一句,ASP.NET GridView 这类控件经常会动态生成复杂 id,所以很多同学习惯用$("input[type=text]")这种属性选择器去规避特殊字符问题。

两个小提醒:

  • 同一个选择器如果会被多次使用,先缓存成变量,比如var $box = $("#box");,避免每次重复查询。
  • ID 前面不要画蛇添足写标签名,比如$("div#box")能跑但没必要,还多一次过滤。

2.2 标签选择器与通配选择器

标签选择器直接写元素名,例如$("div")、$("li")、$("input"),底层借助getElementsByTagName或者querySelectorAll来实现。当你想为某种标签统一加事件、统一加样式时非常省事。

// 所有 tr 加一个 class $("tr").addClass("data-row"); // 所有文本框先清空 $("input[type='text']").val("");

标签选择器的问题是匹配范围大,尤其页面里 div 和 span 到处都是,如果只是要给某个区域内的标签加样式,一定要限定上下文。比如$("#main li")远好于$("li")。

通配选择器*匹配的是所有元素,威力大但代价也大。$("*")会遍历整棵 DOM 树,性能损耗明显。实际开发中几乎不会单独用,偶尔会出现在组合选择里,比如$("#box *")选中某个容器里的全部子子孙孙,但能不用就尽量不用。

2.3 并集选择器与基础组合写法

并集选择器用逗号把多个选择器串起来,表示“匹配其中任意一个”。这个规则从 CSS 到 jQuery 都一致。

// 同时选中所有 h2 和 .title 以及 #footer $("h2, .title, #footer").css("border", "1px solid #eee");

要注意,返回结果的顺序并不是按照你写选择器的顺序,而是按照元素在文档中出现的顺序排列。这个细节在做索引过滤时很重要,如果你:eq(0)拿到的不是自己以为的那个选择器里的第一个,先想想元素顺序。

并集选择器最常见的场景是多个入口做同样的事,比如“关闭按钮”和“弹窗遮罩”都要触发关闭逻辑:

$(".btn-close, .modal-mask").on("click", function () { $("#modal").hide(); });

基础组合中还有一个容易被忽略的写法:上下文参数。$("li", "#list")等价于$("#list").find("li")。这类写法在插件源码里很常见,因为它可以让你在不额外缓存父元素的情况下,快速把范围锁到某个容器内部。

3. 层级选择器:用结构关系定位元素

3.1 后代选择器:一个空格代表“任意子孙”

后代选择器用空格表示,作用是选中某个元素内部所有满足条件的子孙节点,不只是儿子,还包括孙子、重孙子。它是实际项目里用得最多的层级选择器,因为大多数时候我们需要的是容器内部的某类元素,而不是精确到第几层。

<div id="box"> <p>直接段落</p> <section> <p>嵌套段落</p> </section> </div>
// 会选择两个 p 元素,包括嵌套在 section 里面的那个 $("#box p").css("color", "red");

这个“包含所有子孙”的特性既是优点也是坑。比如一个商品列表页,你在ul上写了$("ul a")去绑点击,但如果a又有自己的子元素图标,点击事件照样会触发;再比如你要统计某个容器内直接有几个子节点,用后代选择器就会多算嵌套层级,这时候就该换用子元素选择器。

3.2 子元素选择器:只认亲儿子

子元素选择器用>连接,只匹配直接子元素,不会再往下钻。它的语法和 CSS 完全一致,很多场景下能帮你避免误伤深层节点。

还是上面那段 HTML:

// 只选中 section 外面的那个 p $("#box > p").css("color", "red");

在这里,被选中的只有 div 的直接子元素 p,嵌套在 section 里的 p 会被忽略。这在设计下拉菜单、标签页这类层级分明的组件时特别重要。

我自己的经验是:能用>的地方就别用空格。一方面是为了减少匹配范围、提升一点性能,更重要的是语义更清楚——你写$("#box > p")时,读代码的人一眼就知道操作目标是直接子节点;写$("#box p")时,还得去猜你是不是真的想照顾到深层元素。

顺带说一个性能上的贴心理解:后代选择器需要往树的深处持续扫描,子元素选择器只需检查一层父子关系,所以同样的结构下,>通常比空格更轻快。

3.3 相邻兄弟与后续兄弟:+ 和 ~

兄弟选择器主要处理“同一父元素下的同级元素之间的关系”。相邻兄弟选择器用+,它只会选中紧跟在指定元素后面的那个兄弟元素;通用兄弟选择器用~,会选中指定元素后面的所有兄弟元素。

<h3>文章标题</h3> <p>段落A</p> <p>段落B</p>
$("h3 + p").text("只匹配段落A"); $("h3 ~ p").text("匹配段落A和段落B");

开发中比较典型的用法是 hover 某个按钮时,显示或激活紧随其后的面板。比如:

$(".btn-open + .dropdown").addClass("show");

这种写法比给每个按钮都绑定一个带索引的 id 干净得多。配合事件委托时,兄弟选择器也能减少不少临时变量。

需要注意,+和~都只向后匹配,不会往前找。所以如果你需要“前面的兄弟元素”,jQuery 里没有对应的选择器,得用.prev()方法。

4. 筛选选择器:按位置、状态和内容找元素

4.1 位置筛选:first、last、eq、gt、lt

位置筛选选择器是 jQuery 相对原生 CSS 选择器扩展得比较多的部分,它的作用是站在“匹配结果集合”的角度继续过滤。

  • :first匹配集合中的第一个元素
  • :last匹配集合中的最后一个元素
  • :eq(index)匹配集合中索引为 index 的元素,索引从 0 开始
  • :gt(index)匹配集合中索引大于 index 的元素
  • :lt(index)匹配集合中索引小于 index 的元素
  • :even匹配索引为偶数的元素,注意这里的偶数索引从 0 开始
  • :odd匹配索引为奇数的元素
$("li:first").addClass("current"); // 第一个 li $("li:eq(2)").text("第三个 li"); // 索引 2 对应第三个 $("li:gt(1)").hide(); // 索引 1 之后的 li 全部隐藏 $("li:lt(2)").hide(); // 索引 0 和 1 的 li 隐藏

这几个选择器在做表格分页、轮播、列表高亮时非常顺手。比如要给表格加斑马纹,除了用 CSS 的nth-child(even),在旧项目里也可以这样写:

$("#tableBody tr:even").addClass("even-row");

这里有个特别容易踩的坑::even和:odd是以当前匹配集合的索引来计算的,不是以子元素在父容器里的顺序计算的。假设你先把选择器范围缩小到了$(".list li:visible"),那么“第偶数个可见元素”和“DOM 里的第偶数个 li”就是完全两回事。

4.2 子元素位置筛选:first-child 与 nth-child 的区别

上一节的:first是“匹配集合中的第一个”,而:first-child强调的是“父元素的第一个子节点”。这两个名字就差一个词,含义差得很远。

看一段例子:

<ul class="list"> <li>A</li> <li>B</li> </ul> <ul class="list"> <li>C</li> </ul>
$("ul.list li:first").length; // 1,取所有 li 里的第一个 $("ul.list li:first-child").length; // 2,A 和 C 都是各自父元素的第一个子节点

热词里经常看到“jquery 第一个子元素”,大家搜的大概率是first-child而不是:first。当你希望“每个分组里的第一个”都被选中时,用:first-child;当你只想要“所有匹配结果里的第一个”时,用:first。

同理,:last-child、:nth-child(n)也都是基于父元素的子节点位置来计算的。

// 每个表格行的第一个单元格加粗 $("tr td:first-child").addClass("strong"); // 选中每个列表的第二个子节点(注意 nth-child 从 1 开始) $("ul li:nth-child(2)").css("color", "#c00");

:nth-child还支持odd、even以及公式写法,例如:nth-child(2n+1),这套语法和 CSS 规范性一致。用它的好处是天然跟元素在结构中的位置绑定,即便前面同样有多个容器也不会串位。

4.3 内容与状态筛选:contains、empty、visible、checked

除了位置,jQuery 还能按内容、显示状态和表单状态来筛选元素。

// 按文本内容过滤 $("p:contains('报错')").addClass("error-text"); // 空元素,没有子节点也没有文本 $("div:empty").hide(); // 包含某个子元素的父元素 $(".card:has(.btn-danger)").addClass("warning-card"); // 可见不可见 $("#tips:hidden").fadeIn(); $("input:visible").focus();

:contains非常实用,但有两个限制。一是参数里如果文本含有引号,匹配会容易出错,需要仔细转义;二是它执行的是子字符串匹配,不是精确匹配,所以:contains('媒体')也会匹配“新媒体运营”。想要精确匹配文本,建议还是用原生遍历或写个过滤器函数。

:visible和:hidden的判断逻辑也不算直观。jQuery 判断隐藏元素,大致依据是 display 为 none、type 为 hidden、宽高为 0,或者父元素已经隐藏。visibility: hidden在多数版本里也会被认定为隐藏,但opacity: 0的元素不算隐藏。写自动化脚本时要特别留意,不要以为透明元素就是隐藏。

表单类状态选择器也很常用:

$("input:checked").val(); $("option:selected").text(); $("input:disabled").prop("disabled", false);

4.4 属性筛选选择器:精确匹配你的钩子

属性选择器是筛选选择器里的一组重要分支,它不靠位置、不靠文本,而是看元素的属性特征。常见写法有五种:

  • [name]带有指定属性名即可
  • [name="value"]属性值精确等于 value
  • [name^="value"]属性值以 value 开头
  • [name$="value"]属性值以 value 结尾
  • [name*="value"]属性值包含 value
// 找所有以 user 开头的 input $("input[name^='user']").css("border", "1px solid red"); // 找所有 pdf 链接 $("a[href$='.pdf']").addClass("pdf-icon"); // 找所有带>$("#productTable").on("mouseenter", "td", function () { var fullText = $(this).text().trim(); // 超过 20 个字符才给 title,避免无意义提示 if (fullText.length > 20) { $(this).attr("title", fullText); } });

这里的"#productTable td"是后代选择器,配合事件委托,即使后面的数据是 Ajax 动态加载进来的,也能正常触发。这个场景典型体现了选择器的组合价值:先定位表格,再通过事件委托聚焦到单元格。

5.2 案例:Tab 切换联动内容区

写 Tab 组件时,新手常常写出大量eq(i)配合循环的代码,其实选择器加链式方法就可以做得很干净。

$(".tab > li").on("click", function () { var index = $(this).index(); $(this) .addClass("active") .siblings() .removeClass("active"); $(".tab-content") .eq(index) .addClass("active") .siblings() .removeClass("active"); });

这里的$(".tab > li")用子元素选择器,避免内部嵌套结构影响点击目标;.index()方法拿到当前 li 在兄弟节点中的索引;内容区用.eq(index)配合索引选中对应块。整个过程没有写复杂循环,读起来一目了然。

5.3 选择器的性能注意点与最佳实践

选择器性能是一个老生常谈但又容易被忽视的点。以下几点是我在实际项目里反复验证过的:

  • 优先用 ID 选择器定位容器,再用.find()往下找,比写超长后代选择器更清晰。
  • 多次使用的查询结果一定缓存成变量,不要每次用到都重新$()。
  • 少用通配选择器,也少用:hidden、:visible这类全页面范围内过滤的伪类。
  • 非要复杂过滤时,可以用.filter()方法配合函数,可读性通常比堆一长串伪类更好。
// 不推荐:长选择器写一堆 $("div#wrapper .content ul li:visible:first"); // 推荐:分步定位 var $visibleItems = $("#wrapper .content ul li").filter(":visible"); $visibleItems.eq(0).addClass("current");

jQuery 底层用的是 Sizzle 选择器引擎,原生querySelectorAll能支持的选择器它会优先交给浏览器原生解析,而那些原生不支持的扩展伪类,比如:eq、:contains,它就会退回到 JavaScript 遍历过滤。所以不是所有选择器都一样省钱,越贴近 CSS 标准的选择器性能越稳定。

6. 常见问题与排查心得

6.1 选择器找不到元素,先检查这几件事

我在帮同事排查问题时发现,选择器“没效果”的原因通常不在选择器语法本身,而在执行时机和对象类型。

第一,代码是不是在 DOM 加载前就执行了。如果脚本写在head里,直接$("#box")拿到的必然为空。解决方案是把代码包在$(function () {})里面,让页面 DOM 就绪后再执行。

第二,是不是把 jQuery 对象和原生 DOM 混用了。$("#id")返回的是 jQuery 对象,你要在控制台打印看看结构,而不是直接打印$("#id").value。判断一个元素到底存不存在,标准写法是$("#id").length > 0。

第三,选择器里的大小写和空格是否准确。class 名和 id 名是区分大小写的,HTML 标签名虽然不区分,但选择器里的属性值区分。还有空格表示后代,如果你写的选择器是$(".menu :first"),中间这个空格会让:first变成所有后代元素中的第一个,往往不是你要的菜单自身。

6.2 动态加载的内容为什么绑定不上事件

这个坑十个新手九个踩。你用一个 id 选择器找到按钮,然后.on("click")绑定事件,按钮一开始不存在,而是 Ajax 返回后才插入页面,那事件自然绑不上。

解决方案是事件委托,把事件绑定到父容器上,再通过选择器过滤触发目标:

$("#tableBody").on("click", "tr[data-id]", function () { // 即使 tr 是后来动态生成的,也能触发 });

选择器在这里承担的责任是“过滤触发源”,不是“直接绑定对象”。只要父容器在页面初始时就存在,后续动态插入的元素都能被正确识别。

6.3 我的三个经验技巧

工具再简单,也经不起天天用,用久了自然会有一些自己的习惯。这三个经验是我使用 jQuery 比较高频的技巧:

一是能用data属性钩子就别硬扣 class。比如行选中、状态切换这类需求,优先给元素加>$("ul.nav") .find("li.active") .addClass("current") .end() .addClass("has-active");

三是在调试阶段多利用console.log($("#xxx").length)来验证选择器命中了几个元素,而不是盯着页面看效果。页面效果没出现的时候,往往是选择器没匹配上,不是 jQuery 每个方法都失效了。

7. 最后分享一个我自己的使用习惯

文章写到这里,内容基本已经讲完,最后想分享的是我在实际开发中的一个判断标准:能用简单选择器解决的问题,绝对不用复杂的扩展伪类;能用一次查询加链式方法完成的,绝不写第二遍。选择器只是工具,写得清晰才能真正加快开发速度。

如果新项目里还在纠结要不要用 jQuery,我的看法是,先看你的浏览器支持目标再说。但如果你只是想快速理解 DOM 与 CSS 选择器之间的关系,jQuery 选择器依然是一本很直观的“教科书”。把基础选择器、层级选择器、筛选选择器这三块吃透,后面的路会顺很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 8:42:37

企业级RAG知识库搭建实战:从原理到代码与调优

这几周一直在处理公司内部知识库的问答需求&#xff1a;产品文档、运维手册、售后工单散落在十几个系统里&#xff0c;员工查一份资料要打开五六个页面&#xff0c;还经常找不到最新版本。试用了几种方案之后&#xff0c;发现RAG&#xff08;检索增强生成&#xff09;是最贴合这…

作者头像 李华
网站建设 2026/9/26 8:41:37

机器学习期末大作业合集:KNN、决策树等六份课程设计源码与实验报告

简介&#xff1a;这份资源是机器学习期末大作业的六次项目合集&#xff0c;面向高校学生、课程设计者及需要快速完成高分作业的自学者&#xff0c;覆盖从基础算法到综合实验的完整训练链路。包内包含基于KNN的手写数字识别、回归模型、参数估计与非参数估计、朴素贝叶斯分类器、…

作者头像 李华
网站建设 2026/9/26 8:41:12

货拉拉AI Coding落地实践:从个人提效到组织提效的四个关键

刚在货拉拉把 AI Coding 从“一群人自己玩”推到“全研发流程用起来”&#xff0c;我印象最深的一句话&#xff0c;是一个后端同学说的&#xff1a;“我自己写代码快了至少一倍&#xff0c;但需求该什么时候上还是什么时候上。”这句话几乎把问题说完了——工具给你省了敲键盘的…

作者头像 李华
网站建设 2026/9/26 8:40:27

从个人提效到组织提效:货拉拉AI Coding落地实践与多智能体协作

我自己用 AI 写代码&#xff0c;是真切体会过那种“一个人活成一支队伍”的感觉的。一个难点需求&#xff0c;把上下文喂给模型&#xff0c;几秒钟出初稿&#xff0c;再花半小时修修改改&#xff0c;过去一下午的活俩小时搞定。但当你把这件事放大到一个几十人乃至上百人的研发…

作者头像 李华
网站建设 2026/9/26 8:39:57

AI提示词工程实战:四维锚定法打造高保真小说叙事

1. 这不是“AI写作教程”&#xff0c;而是一份被小说编辑反复验证过的提示词工程实操手册你有没有试过让AI写一个“雨夜咖啡馆里&#xff0c;穿驼色风衣的女人盯着窗外第三盏路灯发呆”这样的句子&#xff1f;输入完&#xff0c;AI回你一段华丽但空洞的描写&#xff1a;“她内心…

作者头像 李华
网站建设 2026/9/26 8:38:51

agent-skills:从提示词工程到可复用技能包,让AI Agent稳定落地

如果你最近在折腾 AI Agent&#xff0c;大概没少撞上同一堵墙&#xff1a;模型本身已经很能说了&#xff0c;但真让它按你团队的流程把活儿干完&#xff0c;它要么漏步骤&#xff0c;要么把规则忘得一干二净&#xff1b;你往系统提示词里多写几句约束&#xff0c;它又开始自由发…

作者头像 李华