当前位置: 首页 > news >正文

Vue3 中 props 与 $emit 的使用及 defineProps 与 defineEmits 的区别详解

一、基本概念

1. 父子组件通信原则

        Vue 遵循 单向数据流 原则:父组件通过 props 向子组件传递数据;子组件若需反馈信息,则使用事件系统$emit通知父组

数据流向:父 → 子(via props),子 → 父(via emit

二、传统 Options API 写法(Vue3 兼容)

父组件 App.vue
<template><div><h2>父组件</h2><p>收到子组件消息:{{ messageFromChild }}</p><ChildComponent :title="parentTitle" @send-message="handleMessage"/></div>
</template><script>
import ChildComponent from './ChildComponent.vue';export default {components: { ChildComponent },data() {return {parentTitle: '来自父组件的标题',messageFromChild: ''};},methods: {handleMessage(msg) {this.messageFromChild = msg;}}
};
</script>
子组件 ChildComponent.vue
<template><div><h3>{{ title }}</h3><button @click="sendToParent">发送消息给父组件</button></div>
</template><script>
export default {props: ['title'],emits: ['send-message'], // 显式声明触发的事件名methods: {sendToParent() {this.$emit('send-message', '你好,我是子组件!');}}
};
</script>

✅ 使用 props 接收父级数据,使用 this.$emit 触发事件。

三、Composition API + <script setup> 新写法

<script setup> 是 Vue3 提供的编译时语法糖,让组合式 API 更简洁。

父组件(App.vue)
<template><div><h2>父组件(setup 版)</h2><p>收到子组件消息:{{ messageFromChild }}</p><ChildComponent :title="parentTitle" @send-message="handleMessage"/></div>
</template><script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';const parentTitle = ref('来自 setup 父组件的标题');
const messageFromChild = ref('');const handleMessage = (msg) => {messageFromChild.value = msg;
};
</script>
子组件(ChildComponent.vue)— 使用 defineProps 和 defineEmits
<template><div><h3>{{ title }}</h3><button @click="sendToParent">发送消息给父组件</button></div>
</template><script setup>
// 定义接收的 props
const props = defineProps({title: {type: String,required: true}
});// 定义可触发的事件
const emit = defineEmits(['send-message']);// 发送事件到父组件
const sendToParent = () => {emit('send-message', '这是通过 defineEmits 发送的消息!');
};
</script>

🔥 注意:definePropsdefineEmits宏函数(macro),不能被解构或动态调用。

四、高级用法:类型安全(配合 TypeScript)

<script setup lang="ts">
interface Props {title: string;count?: number;
}// 类型化 defineProps
const props = defineProps<Props>();// 类型化 defineEmits
const emit = defineEmits<{(e: 'send-message', msg: string): void;(e: 'update-count', value: number): void;
}>();const sendToParent = () => {emit('send-message', '类型安全的消息');emit('update-count', props.count || 0);
};
</script>

⚡️ TypeScript 下自动提示 + 类型检查,极大提升开发体验!

五、常见误区与注意事项

问题正确做法
❌ 尝试解构 defineProps 返回值const { title } = defineProps(...) ❌ 不支持
✅ 应始终通过 props.xxx 访问props.title ✅ 响应式保留
❌ 在条件语句中调用 defineEmits必须顶层调用
✅ defineProps 和 defineEmits 不需要导入编译时自动识别

六、通信流程图(文字描述 + 图表示意)

📊 图表示意(文本模拟)

箭头方向清晰体现 数据单向流动 + 事件反向通知

七、多个例子实战演示

示例 1:计数器增减控制(父控子操作)

父组件

<ChildCounter v-model:count="count"/>

子组件

<script setup>
defineProps(['count']);
defineEmits(['update:count']);
</script>
<template><div><span>当前值:{{ count }}</span><button @click="$emit('update:count', count + 1)">+</button><button @click="$emit('update:count', count - 1)">-</button></div>
</script>

实现了 .sync 模式的替代方案,使用 v-model:count 绑定。

示例 2:表单输入双向同步(类似 v-model)

父组件

<FormInput v-model="inputValue"/>

子组件 FormInput.vue

<script setup>
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);const updateValue = (e) => {emit('update:modelValue', e.target.value);
};
</script><template><input :value="modelValue" @input="updateValue" />
</template>

相当于实现了自定义 v-model 行为。

示例 3:异步完成通知

子组件完成异步任务后通知父组件更新状态

<script setup>
const emit = defineEmits(['done']);const asyncTask = async () => {await new Promise(resolve => setTimeout(resolve, 1000));emit('done', { success: true, time: Date.now() });
};
</script>

父组件监听

<AsyncComponent @done="onDone"/>

总结对比表

对比项Options API (props$emit)<script setup> (definePropsdefineEmits)
是否需要 export default否(自动导出)
props 定义位置props: {} 选项内defineProps({...}) 宏调用
emit 调用方式this.$emit('event')emit('event')(函数调用)
是否支持类型推导否(JS) / 有限(TS 需额外配置)✅ 支持 TS 泛型推导
是否响应式解构❌ 解构会失去响应性❌ 不允许解构 props
开发效率一般更高(少模板代码)

知识点

  • 单向数据流:父组件通过 props 传值给子组件,子组件不应直接修改 props,保持数据流向清晰。

  • 事件发射机制:子组件通过 $emitemit 触发事件,父组件通过 @event 监听并处理。

  • 宏函数特性defineProps defineEmits 是编译宏,只能在 <script setup> 顶层使用,不需引入。

http://www.dtcms.com/a/389617.html

相关文章:

  • vue的跨域配置
  • 计算机网络实验03:交换机VLAN配置
  • Vue中v-if与v-show的区别及应用场景解析
  • C++造轮子:手搓 List 容器
  • redis-list的基本介绍
  • ​​[硬件电路-247]:开关电源的工作原理、优缺点及应用场合
  • 【面试】Java中的垃圾回收算法详解
  • AI使用心得-完善中
  • rust编写web服务01-项目起步与环境准备
  • ORM框架及SQLAlchemy
  • 驱动开发---双机调试搭建支持win11(2025)
  • 驱动开发1:内核程序框架
  • 生产制造如何应对客户的订单变更
  • 深入浅出SpringMVC:从入门到实战指南
  • 深度学习入门:从感知机到多层感知机,用逻辑电路讲透神经网络的进化
  • macos m1 芯片无法安装kubeedge keadm 解决办法
  • 猎板 PCB:以全维度工艺突破,构建 PCB 制造技术壁垒
  • android12 SDK31 wifi开发(仅提供连接wifi的工具类)
  • Android播放视频适配黑边问题类型总结
  • 第十一章:AI进阶之--模块的概念与使用(二)
  • 异常检测patchcore 学习笔记 2025
  • [iOS] 网络 - AFNetWorking
  • iOS App 混淆与性能稳定性优化 混淆开销、崩溃风险、CI 集成与落地实务(
  • Freertos系统(任务挂起和恢复)
  • Git更新仓库时,忽略指定文件
  • 告别“瞎练”!数据闭环正成机器人智能进化核心引擎!
  • 基于MATLAB的无人机遥感数据预处理与农林植被性状估算
  • MATLAB基于AHP-模糊综合评价法的工程实践能力评价
  • 特征选择+优化算法+GBDT+SHAP分析!ReliefF-CPO-GBDT分类预测结合SHAP可解释分析MATLAB
  • 设计模式-外观模式详解