You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:09:26