JS事件机制精讲

js事件机制

页面上点击一个元素,这个点击动作会按照固定顺序传递,JS 事件机制就是规定**事件从哪开始、往哪走、什么时候触发函数的一套规则。

类比:一张桌子,桌子上放一个杯子。你用手拍杯子。

✅ 默认addEventListener('click',fn),是在冒泡阶段 触发 ✅ addEventListener('click',fn,true) 第三个参数写 true,代表在捕获阶段触发

二、解决什么问题?

三、常用场景 + 代码示例

场景 1:事件冒泡(默认现象)

盒子里面有按钮,点击按钮,按钮和外层盒子的点击事件都会执行

复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<body>
  <div id="father" style="padding:30px;background:skyblue;">
    父盒子
    <button id="son">点我</button>
  </div>

  <script>
    let father = document.querySelector('#father')
    let son = document.querySelector('#son')

    father.addEventListener('click', ()=>{
      console.log('父元素被点击')
    })
    son.addEventListener('click', ()=>{
      console.log('按钮被点击')
    })
  </script>
</body>
</html>

运行结果:点按钮 → 先打印按钮被点击,然后打印父元素被点击。 原因:触发按钮事件后,事件向上冒泡到父 div。

阻止冒泡写法:e.stopPropagation()

复制代码
son.addEventListener('click', (e)=>{
  e.stopPropagation() // 阻止事件向外冒泡
  console.log('按钮被点击')
})

加上这行,点击按钮,只会执行按钮事件,父盒子不会触发。

场景 2:事件委托(事件代理,最常用!)

解决问题 :子元素很多,或者子元素是动态新增 的,不用逐个绑定事件,只给父元素绑定一次。 原理:利用事件冒泡,点击子元素,事件会冒泡到父元素,父元素统一处理。

例子:ul 里面很多 li,后续还会新增 li

复制代码
<ul id="list">
  <li>项目1</li>
  <li>项目2</li>
  <li>项目3</li>
</ul>
<button id="add">新增项目</button>

<script>
  let list = document.querySelector('#list')
  let addBtn = document.querySelector('#add')

  // 只给父ul绑定事件,利用冒泡
  list.addEventListener('click', (e)=>{
    // e.target 就是真正点击到的元素
    if(e.target.tagName === 'LI'){
      console.log('你点击了:',e.target.innerText)
    }
  })

  // 动态新增li
  addBtn.addEventListener('click', ()=>{
    let li = document.createElement('li')
    li.innerText = '新项目'
    list.appendChild(li)
  })
</script>

优点:

  1. 减少事件绑定,节省内存,性能更好
  2. 动态添加的元素自动拥有事件,不用重新绑定(这个是最大优势)

场景 3:阻止默认行为 e.preventDefault()

不是阻止冒泡!是阻止浏览器自带的默认动作 例子:a 标签点击默认跳转,表单 submit 默认提交刷新页面

复制代码
<a href="https://www.baidu.com" id="link">百度</a>
<script>
  let link = document.querySelector('#link')
  link.addEventListener('click', (e)=>{
    e.preventDefault() // 阻止a标签默认跳转
    console.log('链接点击,不会跳转')
  })
</script>

四、两个容易混淆 API 区分(考试常考)

五、总结思维导图版(方便写作业)

六、常见坑

  1. 捕获阶段:从最外层(桌子)→向内(杯子),从上往下传递事件

  2. 冒泡阶段 :从被点击的目标(杯子)→向外(桌子),从里往外冒事件 JS 默认:事件冒泡一、事件流三个阶段

  3. 捕获阶段 :事件从 window → document → html → body → 外层父元素,一层一层向内走,还没到达点击的目标元素

  4. 目标阶段:事件到达你真正点击的那个元素,触发这个元素绑定的事件

  5. 冒泡阶段:事件从目标元素,一层一层向外传递给父元素,直到 window

  6. 解决嵌套元素点击冲突:比如 div 里面套按钮,点按钮,父 div 的点击事件也跟着触发(冒泡带来的现象)

  7. 实现事件委托(事件代理):不用给每一个子元素绑定事件,只绑定父元素,利用冒泡,提升性能

  8. 可以手动控制:阻止事件继续传播(e.stopPropagation()),不让事件继续捕获 / 冒泡

  9. e.stopPropagation():停止事件传播,阻止捕获 / 冒泡继续走,不会阻止元素本身事件

  10. e.preventDefault():阻止浏览器默认行为,不影响事件冒泡

  11. return false:jQuery 里,同时阻止冒泡 + 默认行为;原生 JS 只能阻止默认行为,不能用来阻止冒泡(别搞混)

  12. JS 事件机制 = 事件流:捕获 → 目标 → 冒泡

  13. 默认 addEventListener 是冒泡阶段触发

  14. 冒泡:子触发,往上传给父;捕获反过来

  15. 核心应用:事件委托(事件代理),适合列表、动态元素

  16. 常用 API:

    • e.stopPropagation():阻止冒泡 / 捕获传播
    • e.preventDefault():阻止浏览器默认行为
    • e.target:真正点击的目标元素(事件委托必用)
  17. 事件委托要绑定在离目标元素最近的父元素,不要绑到 body/window,避免不必要事件触发

  18. e.target 和 this 的区别:

    • e.target:实际点击到的元素
    • 事件处理函数里的this:绑定事件的那个元素(父元素)
相关推荐
To_OC2 小时前
从一头雾水到跑通全流程:我用一个周末啃透了JWT登录鉴权
前端·后端·http
excel4 小时前
研究 Vue 3 源码的收获
前端·vue.js
可乐鸡翅yeah_5 小时前
业务中 M3U8 水印相关坑,硬水印和动态水印区别
前端·网络·数据库·ffmpeg·m3u8在线
lerhxx6 小时前
AI 应用如何高效优雅地恢复中断?—— "连接解耦 + 状态持久化"
前端·javascript
计算机魔术师6 小时前
METR 演示 AI 智能体如何篡改 Inspect 评估记录以掩盖不当行为
前端
前端snow6 小时前
ai agent --- 异步处理之 Rabbit MQ
前端
念何架构之路6 小时前
zap扩展生态与总结
java·前端·数据库
独孤九剑打醒他6 小时前
【原创开源】【概念设计】源 - 栅 - 漏 - 栅 - 源 横向双栅 MOS,低压交流多值逻辑芯片探索
前端·其他·架构·开源·硬件工程
mantou1327 小时前
我给 AI Agent 做了个「油猴」:让 Claude Code / Codex 直接用你已登录的浏览器
前端·javascript·后端
默_笙7 小时前
🍕 一个主编、三个工种、两本手册:搭一支 AI 调研队
前端·javascript