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.targetthis 的区别:

    • e.target:实际点击到的元素
    • 事件处理函数里的this:绑定事件的那个元素(父元素)
相关推荐
装备研究社1 小时前
Promise 的五个状态,90% 的人只说对了三个
前端
小聪7081 小时前
elpis-core 抽离 npm 包过程的难点和卡点
前端·架构
钱栈up2 小时前
坯料管理导入功能bug修复:只改前端一个文件就解决问题
前端·bug
沉迷...2 小时前
Git skip-worktree 使用笔记(本地忽略配置文件)
javascript·git
石小石Orz2 小时前
民间AI排行榜单新鲜出炉,Fable 5.1仅排第三
前端·后端·ai编程
FYKJ_20102 小时前
【毕设分享】基于Web的校园兼职信息发布与申请系统07059
前端·vue.js·spring boot·mysql·typescript·spark·课程设计
志尊宝4 小时前
Vue3 零基础每日笔记(032):Suspense 与异步组件——懒加载与顶层 await 终极方案
前端·javascript·vue.js·笔记·html5
Alice-YUE4 小时前
前端速通 Agent:5 个项目,一条学习路径
前端·大模型·ai agent·学习路径·deerflow
是立不是利4 小时前
前端分页逻辑与边界场景实战解析
前端·javascript