vue-冒泡行为
事件冒泡Event Bubbling是 DOM文档对象模型中最基本、也最容易引发“灵异事件”的机制。结合你刚学完的DOM 树知识理解冒泡就非常简单了事件会从触发它的最深层节点目标元素开始沿着 DOM 树一层层向上“漂浮”直到抵达根节点document。这就像往水里扔一颗石子点击操作涟漪事件会从中心点向水面四周扩散。在 Vue 3 中如果你不加以控制点击子组件里的按钮父组件甚至祖父组件的点击事件都会被意外触发。1. 事件的 3 个阶段浏览器内部流程为了彻底搞懂冒泡你需要知道浏览器处理事件的完整流程按顺序执行捕获阶段Capture事件从window往下走穿透document、html、body一路找到最底层的目标元素像潜水艇下潜。默认不会触发监听除非你特意开启目标阶段Target事件到达你真正点击的那个元素。冒泡阶段Bubbling事件从目标元素原路返回一层层往上冒泡回到window。这是默认事件触发阶段。2. 看个“灵异”代码你肯定会遇到在你的父组件模板中假设这样写template !-- 父容器监听点击 -- div classparent-box clickparentHandler 父级区域 !-- 子按钮监听点击 -- button clickchildHandler点击我/button /div /template script setup langts const parentHandler () { console.log( 父级 div 被点击了) } const childHandler () { console.log( 按钮被点击了) } /script你只点了按钮但控制台输出却是 按钮被点击了 父级 div 被点击了原因点击按钮时事件触发了button的监听然后气泡冒到了div上触发了父级的监听。3. Vue 3 的解决方案事件修饰符.stop和.selfVue 提供了极其优雅的指令修饰符来解决冒泡你不需要写e.stopPropagation()这种原生 JS。①.stop修饰符“急刹车”阻止向上冒泡这是最常用的方案相当于调用了event.stopPropagation()。!-- ✅ 完美解决点了按钮父级完全收不到信号 -- button click.stopchildHandler点击我只触发自己/button②.self修饰符“查户口”只认自己只有当event.target真正点击的那个元素恰好是绑定事件的这个元素时才触发回调。如果点击的是子元素冒泡上来的不触发。div click.selfparentHandler !-- 点击按钮父级不触发因为 target 是 button不是 div -- button clickchildHandler点我父级无动于衷/button !-- 点击父级空白区域没有子元素遮挡target 是 div父级触发 -- /div 核心区别面试必问.stop阻止冒泡传播子事件完全到不了父级。.self不阻止冒泡事件依然会往上冒泡到爷爷级只是判断当前级是否执行回调。4. 捕获阶段修饰符.capture如果你希望监听在“捕获阶段”触发即往下传的过程中可以使用.capture。这个场景较少主要用于需要在子元素收到事件之前就拦截的场景。!-- 父级在捕获阶段触发比子元素的冒泡监听先执行 -- div click.captureparentHandler button clickchildHandler点我/button /div输出顺序父级捕获-子级冒泡。通常不建议滥用默认用冒泡即可5. 特别注意v-for与冒泡的“代理”陷阱你现在学了v-for如果在循环列表上绑定事件冒泡机制会帮你省很多事事件代理。ul clickhandleListClick !-- 只给父级绑一次事件 -- li v-foritem in list :keyitem.id :data-iditem.id {{ item.name }} /li /ul点击li时冒泡到ul通过event.target.dataset.id就能拿到点击的是哪个li。性能极佳不用给每个li绑监听器。6. 组件边界自定义事件emit会冒泡吗这是一个非常重要的误区原生 DOM 事件如click、input会冒泡遵循 DOM 树。自定义事件如updatehandleChildEmit不会冒泡它只在当前的组件实例上触发不会穿透组件层级传递到父级组件之外。但是如果你的自定义事件绑在原生标签上或者你的组件根元素触发了原生click它依然会冒泡。7. 终极调试大法如何看冒泡路径在 Windows 11 的 Chrome 控制台F12 - Console中如果你监听事件时打印event对象展开看path属性或composedPath()就能看到事件经过的所有 DOM 节点列表。const handler (e: Event) { console.log(e.composedPath()) // 打印出完整的冒泡路径[button, div, body, html, document, ...] }8. 总结速记口诀点击按钮冒泡起一层一层往上提.stop一脚急刹车到此为止不上去.self只认自己身子点冒泡我不闻原生事件才冒泡自定义emit可不管。现在去你之前的父组件代码里给那个clickcallChildMethod按钮外面包一层div给div也绑个点击事件不加.stop点一下看看是不是触发两次然后加上.stop再点一下——亲手验证一次胜过看十遍文档

相关新闻