jQuery 在存量后台、管理页面和快速交付项目中仍然常见,但不少问题并非语法错误,而是 jQuery 的静默行为、事件模型和上下文规则造成的。下面按“现象—原因—正确写法—适用场景”梳理 10 个项目里高频出现的坑点,代码保留原有逻辑,便于直接对照排查。
坑点一:选择器没命中时不会抛错
现象:执行 $('#submitBtn').on('click', fn) 时,如果 #submitBtn 不存在,代码不会报错,但事件也不会绑定。动态渲染、权限控制、异步加载场景下尤其隐蔽。
正确写法是先判断集合长度:- const $btn = $('#submitBtn');
- if ($btn.length) {
- $btn.on('click', submitForm);
- }
复制代码 或者使用事件委托:- $(document).on('click', '#submitBtn', submitForm);
复制代码 关键认知:jQuery 查不到元素属于静默失败,不是异常,不能依赖报错来发现问题。
坑点二:return false 与 event.preventDefault() 混用
return false 同时阻止默认行为和冒泡;event.preventDefault() 只阻止默认行为;event.stopPropagation() 只阻止冒泡。很多代码只是想去掉链接跳转,却顺手阻止了冒泡,导致外层事件收不到。
推荐语义更清晰的写法:- $('a.link').on('click', function (e) {
- e.preventDefault();
- doSomething();
- });
复制代码 除非明确需要阻止冒泡,否则不要用 return false。
坑点三:动态元素绑定事件却忘了事件委托
错误示例:- $('.item').on('click', function () {
- console.log('click');
- });
- $('.list').append('<div class="item">new</div>');
复制代码 后续通过 AJAX 或 append 添加的新元素不会触发点击事件。
正确写法是把事件绑定在父元素上,利用事件冒泡:- $('.list').on('click', '.item', function () {
- console.log('click');
- });
复制代码 适用于列表动态加载、分页渲染、弹窗内容异步插入等场景。
坑点四:$.each 和 $(selector).each 混淆
$.each(arr, fn) 常用于遍历数组或对象,this 指向当前数组元素;如果传入 jQuery 集合,this 也可能是 DOM 元素。$(selector).each(fn) 遍历 DOM 集合,this 是 DOM 元素,在内部用 $(this) 才能得到 jQuery 对象。
推荐写法:- $('.item').each(function () {
- $(this).addClass('active');
- });
复制代码 一句话记忆:$.each 遍历数据,$(selector).each 遍历 DOM。
坑点五:.html() 和 .text() 的 XSS 风险
危险写法:- $('#content').html(userInput);
复制代码 如果 userInput 包含 script 标签或可执行内容,会被直接执行。安全写法是使用 .text():- $('#content').text(userInput);
复制代码 需要保留 HTML 时,可先手动转义:- function escapeHtml(str) {
- return $('<div>').text(str).html();
- }
复制代码 原则:用户内容一律用 .text(),除非明确信任来源。
坑点六:$(window).load() 已废弃
旧代码常见:- $(window).load(function () {
- // do something
- });
复制代码 在 jQuery 1.8+ 中已废弃,3.x 会直接报错。正确写法:- $(window).on('load', function () {
- // 页面所有资源加载完成
- });
- $(function () {
- // DOM ready
- });
复制代码 区别在于:DOMContentLoaded 表示 DOM 就绪,window.load 表示图片、iframe 等全部资源加载完成。
坑点七:链式调用上下文切换导致误判
示例:- $('.item')
- .addClass('active')
- .css('color', 'red')
- .find('.sub')
- .end()
- .removeClass('active');
复制代码 find() 会切换上下文,end() 返回上一级,链式越长越容易误以为还在操作最初集合。建议超过 3 次的链式调用就拆开写:- const $item = $('.item');
- $item.addClass('active');
- $item.find('.sub').css('color', 'red');
复制代码 这样上下文清晰,排查时也更容易定位。
坑点八:.prop() 和 .attr() 用错
经典错误:- $('#checkbox').attr('checked', true);
复制代码 在 jQuery 1.6+ 中,checked、disabled、selected 等表单状态应使用 .prop():- $('#checkbox').prop('checked', true);
- $('#box').attr('data-id', 123);
复制代码 记忆口诀:状态用 prop,自定义属性或 HTML 属性用 attr。
坑点九:AJAX 缓存导致数据不更新
IE 或旧项目里,GET 请求可能被浏览器缓存:- $.get('/api/user', function (res) {
- console.log(res);
- });
复制代码 解决方式是在 $.ajax 中设置 cache: false:- $.ajax({
- url: '/api/user',
- type: 'GET',
- cache: false
- });
复制代码 也可以在 URL 后加时间戳:- $.get('/api/user?_=' + Date.now());
复制代码 原文建议所有 GET 请求接口默认考虑 cache: false,避免出现“数据不更新”的假象。
坑点十:重复绑定造成内存泄漏和灵异事件
在 SPA 或弹窗场景中,页面多次初始化可能重复绑定:- function initPage() {
- $('#btn').on('click', handler);
- }
复制代码 正确写法是先解绑再绑定:- function initPage() {
- $('#btn').off('click').on('click', handler);
- }
复制代码 更优解是事件委托:- $(document).on('click', '#btn', handler);
复制代码 原文提到,单页应用里 90% 的“灵异事件”都是重复绑定导致的,排查时应优先检查初始化函数是否被多次调用。
总结
这 10 个坑点集中在几类问题上:选择器静默失败、return false 误用、动态元素未委托、each 的 this 指向、html/text 的 XSS 风险、window.load 废弃、链式上下文混乱、prop/attr 混用、AJAX 缓存以及重复绑定。它们大多不是 jQuery 本身“坏了”,而是 API 语义和浏览器行为没有被正确理解。在动态渲染、后台管理和 SPA 场景中,优先使用事件委托、先判断集合长度、状态属性用 prop、用户内容用 text、GET 请求处理缓存,并控制链式调用长度,可以避开大部分隐蔽问题。 |