查看: 308|回复: 0

jQuery高频坑点排查:事件委托、prop与AJAX缓存

[复制链接]
发表于 3 小时前 | 显示全部楼层 |阅读模式
jQuery 在存量后台、管理页面和快速交付项目中仍然常见,但不少问题并非语法错误,而是 jQuery 的静默行为、事件模型和上下文规则造成的。下面按“现象—原因—正确写法—适用场景”梳理 10 个项目里高频出现的坑点,代码保留原有逻辑,便于直接对照排查。

坑点一:选择器没命中时不会抛错

现象:执行 $('#submitBtn').on('click', fn) 时,如果 #submitBtn 不存在,代码不会报错,但事件也不会绑定。动态渲染、权限控制、异步加载场景下尤其隐蔽。

正确写法是先判断集合长度:
  1. const $btn = $('#submitBtn');
  2. if ($btn.length) {
  3.   $btn.on('click', submitForm);
  4. }
复制代码
或者使用事件委托:
  1. $(document).on('click', '#submitBtn', submitForm);
复制代码
关键认知:jQuery 查不到元素属于静默失败,不是异常,不能依赖报错来发现问题。

坑点二:return false 与 event.preventDefault() 混用

return false 同时阻止默认行为和冒泡;event.preventDefault() 只阻止默认行为;event.stopPropagation() 只阻止冒泡。很多代码只是想去掉链接跳转,却顺手阻止了冒泡,导致外层事件收不到。

推荐语义更清晰的写法:
  1. $('a.link').on('click', function (e) {
  2.   e.preventDefault();
  3.   doSomething();
  4. });
复制代码
除非明确需要阻止冒泡,否则不要用 return false。

坑点三:动态元素绑定事件却忘了事件委托

错误示例:
  1. $('.item').on('click', function () {
  2.   console.log('click');
  3. });
  4. $('.list').append('<div class="item">new</div>');
复制代码
后续通过 AJAX 或 append 添加的新元素不会触发点击事件。

正确写法是把事件绑定在父元素上,利用事件冒泡:
  1. $('.list').on('click', '.item', function () {
  2.   console.log('click');
  3. });
复制代码
适用于列表动态加载、分页渲染、弹窗内容异步插入等场景。

坑点四:$.each 和 $(selector).each 混淆

$.each(arr, fn) 常用于遍历数组或对象,this 指向当前数组元素;如果传入 jQuery 集合,this 也可能是 DOM 元素。$(selector).each(fn) 遍历 DOM 集合,this 是 DOM 元素,在内部用 $(this) 才能得到 jQuery 对象。

推荐写法:
  1. $('.item').each(function () {
  2.   $(this).addClass('active');
  3. });
复制代码
一句话记忆:$.each 遍历数据,$(selector).each 遍历 DOM。

坑点五:.html() 和 .text() 的 XSS 风险

危险写法:
  1. $('#content').html(userInput);
复制代码
如果 userInput 包含 script 标签或可执行内容,会被直接执行。安全写法是使用 .text():
  1. $('#content').text(userInput);
复制代码
需要保留 HTML 时,可先手动转义:
  1. function escapeHtml(str) {
  2.   return $('<div>').text(str).html();
  3. }
复制代码
原则:用户内容一律用 .text(),除非明确信任来源。

坑点六:$(window).load() 已废弃

旧代码常见:
  1. $(window).load(function () {
  2.   // do something
  3. });
复制代码
在 jQuery 1.8+ 中已废弃,3.x 会直接报错。正确写法:
  1. $(window).on('load', function () {
  2.   // 页面所有资源加载完成
  3. });
  4. $(function () {
  5.   // DOM ready
  6. });
复制代码
区别在于:DOMContentLoaded 表示 DOM 就绪,window.load 表示图片、iframe 等全部资源加载完成。

坑点七:链式调用上下文切换导致误判

示例:
  1. $('.item')
  2.   .addClass('active')
  3.   .css('color', 'red')
  4.   .find('.sub')
  5.   .end()
  6.   .removeClass('active');
复制代码
find() 会切换上下文,end() 返回上一级,链式越长越容易误以为还在操作最初集合。建议超过 3 次的链式调用就拆开写:
  1. const $item = $('.item');
  2. $item.addClass('active');
  3. $item.find('.sub').css('color', 'red');
复制代码
这样上下文清晰,排查时也更容易定位。

坑点八:.prop() 和 .attr() 用错

经典错误:
  1. $('#checkbox').attr('checked', true);
复制代码
在 jQuery 1.6+ 中,checked、disabled、selected 等表单状态应使用 .prop():
  1. $('#checkbox').prop('checked', true);
  2. $('#box').attr('data-id', 123);
复制代码
记忆口诀:状态用 prop,自定义属性或 HTML 属性用 attr。

坑点九:AJAX 缓存导致数据不更新

IE 或旧项目里,GET 请求可能被浏览器缓存:
  1. $.get('/api/user', function (res) {
  2.   console.log(res);
  3. });
复制代码
解决方式是在 $.ajax 中设置 cache: false:
  1. $.ajax({
  2.   url: '/api/user',
  3.   type: 'GET',
  4.   cache: false
  5. });
复制代码
也可以在 URL 后加时间戳:
  1. $.get('/api/user?_=' + Date.now());
复制代码
原文建议所有 GET 请求接口默认考虑 cache: false,避免出现“数据不更新”的假象。

坑点十:重复绑定造成内存泄漏和灵异事件

在 SPA 或弹窗场景中,页面多次初始化可能重复绑定:
  1. function initPage() {
  2.   $('#btn').on('click', handler);
  3. }
复制代码
正确写法是先解绑再绑定:
  1. function initPage() {
  2.   $('#btn').off('click').on('click', handler);
  3. }
复制代码
更优解是事件委托:
  1. $(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 请求处理缓存,并控制链式调用长度,可以避开大部分隐蔽问题。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-23 17:01 , Processed in 0.031565 second(s), 29 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部