Pixiv - KiraraShss
675 字
3 分钟
父组件给子组件标签绑定事件
欢迎来到我的博客!
使用 Markdown 格式编写。
今天学到了什么
- 给组件标签绑事件,实际上是给组件的根节点绑定的,可是在vue3里面,不是不需要加根节点了吗?
这里容易把两件事混在一起:给“组件”绑事件 和 给“DOM 元素”绑事件。
1)<MyComp @click="fn" /> 到底绑在哪?
在 Vue 里,@xxx 有两种含义:
A. 监听“组件自定义事件”(component event)
这是最标准的理解:父组件在监听子组件 emit('xxx') 出来的事件。
- 子组件:
emit('click') - 父组件:
<MyComp @click="fn" />
这时候 不是“给子组件根节点绑定 click”,而是“监听子组件发出来的 click 事件”。
在 Vue3 里你用 defineEmits 声明了事件后,@click 会被当成组件事件来处理(不会自动下落到 DOM)。
B. 作为“原生 DOM 事件监听器下落”(fallthrough)
Vue3 有个机制叫 属性/监听器下落(fallthrough attrs/listeners):
- 如果你在组件上写了
@click,但子组件并没有把它当成自定义事件(比如没声明emits: ['click']),那么它可能会被当成一个普通的 listener,自动绑定到子组件的根 DOM 元素上(如果存在单一根节点)。
这就是你听到的那句“给组件标签绑事件,本质是给根节点绑”。
2)那 Vue3 不是可以没有根节点(Fragment)吗?怎么下落?
对,Vue3 允许组件模板有多个根节点(Fragment)。这会带来一个关键差异:
- 如果组件只有一个根元素:
@click这类监听器可以“自动下落”到这个根元素上。 - 如果组件有多个根元素(没有单一根):Vue3 不知道该把 listener 绑到哪个元素,所以不会自动绑定,并且会在开发环境给提示(类似 “extraneous non-emits event listeners…”)。
所以结论是:
- “不需要加根节点”不等于“事件还会自动绑根上”
- 自动下落只在“单根节点”场景才自然成立
3)实际开发怎么写才不迷糊?
最稳的做法是分清目的:
我想让父组件接收子组件的动作通知 → 用 emit
子组件:
const emit = defineEmits<{ (e: 'submit'): void}>()emit('submit')父组件:
<MyComp @submit="fn" />我想让父组件传进来的 @click 真的绑到子组件某个 DOM 上 → 显式转发 $attrs
尤其是多根节点组件,推荐你明确指定绑在哪个元素上(不要指望自动下落):
<script setup lang="ts">defineOptions({ inheritAttrs: false })</script>
<template> <button v-bind="$attrs">点我</button> <div>另一个根</div></template>这样父组件写 <MyComp @click="fn" /> 就会明确绑到那个 button 上。
赞助支持
如果这篇文章对你有帮助,欢迎赞助支持!
最后更新于 2026-04-20,距今已过 134 天
部分内容可能已过时