Vue <script setup>下子组件向父组件触发emit事件的正确方法
问题原因
你当前代码失效的核心原因是混淆了Vue两种父子组件通信的写法,两种逻辑不匹配:
- 父组件中使用
:refresh-records="refreshRecords"是「将父组件方法作为Props属性传递给子组件」的写法,这种写法需要子组件通过defineProps接收后手动调用,不会自动响应子组件的emit事件 - 子组件中使用
defineEmits声明事件、调用emits('refresh-records')是「触发自定义事件通知父组件」的写法,这种写法需要父组件用@事件名的格式绑定监听函数,不会读取Props里的同名属性
两种写法各走各的逻辑,所以子组件能正常打印触发日志,但父组件因为没有绑定对应的事件监听,根本不会执行refreshRecords方法。
正确实现方案
两种方案选其一即可,禁止混合使用。
方案1:自定义事件通信(官方推荐,符合单向数据流规范)
这种方式是Vue官方推荐的父子通信模式,子组件只负责抛出事件,具体执行逻辑由父组件控制,耦合度更低。
你只需要修改父组件的模板绑定方式,子组件原有逻辑不需要改动:
<!-- 父组件代码 --> <script setup> async function refreshRecords() { console.log("Refreshing"); } </script> <template> <!-- 注意:用@开头绑定自定义事件监听,不要用:开头传Props --> <Child @refresh-records="refreshRecords"></Child> </template>
子组件保持原有defineEmits和事件触发逻辑即可正常运行。
方案2:Props传递函数(不推荐,仅作兼容参考)
如果你确实要通过传Props的方式把方法传给子组件调用,就需要删掉子组件里的emit相关逻辑,改为接收Props后直接调用传入的函数:
父组件不需要修改原有绑定逻辑,子组件调整为如下写法:
<!-- 子组件代码 --> <script setup> // 接收父组件传入的函数类型Props const props = defineProps({ refreshRecords: { type: Function, required: true } }) async function onSubmit(){ // 其他提交逻辑 console.log("Emitting"); // 直接调用Props中拿到的父组件方法 props.refreshRecords({}); } </script> <template> <q-form @submit="onSubmit" class="q-gutter-md" > <!-- 表单内容省略 --> <q-btn label="Submit" type="submit" color="primary" /> </q-form> </template>
注意事项
- 优先选择方案1实现,符合Vue的设计约定,后续维护更清晰
- Vue模板中使用kebab-case(短横线分隔)命名的Props/事件,在JS代码中访问时需要转为camelCase(小驼峰)格式,比如模板里的
refresh-records对应JS里的refreshRecords
内容的提问来源于stack exchange,提问作者Jackie
相关产品推荐
相关产品推荐

