查看: 4063|回复: 3

Vue父子组件传值六种方式:Props、emit与v-model实践

[复制链接]
发表于 5 天前 | 显示全部楼层 |阅读模式
在 Vue 的组件化开发中,父子组件通信是绕不开的基础能力。原文围绕父组件向子组件传值、子组件向父组件反馈两条链路,归纳了六种方式:Props、自定义事件 $emit、v-model、Provide/Inject、ref 调用,以及 $attrs 与 $listeners 透传。六种方式并不是互相替代关系,选择时先看数据流向和组件耦合程度:单向数据流优先 Props,子组件反馈用 $emit,需要双向同步用 v-model,需要直接控制子组件实例用 ref,跨层级共享用 Provide/Inject,封装透传组件则考虑 $attrs 与 $listeners。原文还提示,$attrs 与 $listeners 在 Vue 3 Composition API 中主要对应 attrs 和 expose 的使用。

1. Props:最基础的单向传值
Props 是父子通信的主干。父组件可以把字符串常量静态传给子组件,也可以用 v-bind 缩写 : 绑定 data 或计算属性。静态写法如下:
  1. <!-- 父组件 Parent.vue -->
  2. <template>
  3.   <ChildComponent title='静态标题' />
  4. </template>
复制代码

动态绑定写法:
  1. <!-- 父组件 Parent.vue -->
  2. <template>
  3.   <ChildComponent :title='parentTitle' />
  4. </template>
  5. <script>
  6. export default {
  7.   data() {
  8.     return {
  9.       parentTitle: '动态数据'
  10.     }
  11.   }
  12. }
  13. </script>
复制代码

这里的重点是父组件持有数据源,子组件通过 props 接收。原文将 Props 定位为单向数据流的主要方式,适合父级把配置、展示数据或初始值下发给子组件。

2. 自定义事件 $emit:子组件向父组件反馈
当子组件需要把点击结果或内部数据交给父组件时,用 $emit 触发自定义事件,父组件通过 v-on 或 @ 监听。子组件代码:
  1. <!-- 子组件 Child.vue -->
  2. <template>
  3.   <button @click='handleClick'>点击触发事件</button>
  4. </template>
  5. <script>
  6. export default {
  7.   methods: {
  8.     handleClick() {
  9.       this.$emit('custom-event', '从子组件传递的数据');
  10.     }
  11.   }
  12. }
  13. </script>
复制代码

父组件监听并接收数据:
  1. <!-- 父组件 Parent.vue -->
  2. <template>
  3.   <ChildComponent @custom-event='handleData' />
  4. </template>
  5. <script>
  6. export default {
  7.   methods: {
  8.     handleData(data) {
  9.       console.log('接收到的数据:', data);
  10.     }
  11.   }
  12. }
  13. </script>
复制代码

这段代码的关键是事件名要一致:子组件触发 custom-event,父组件就监听 custom-event。父组件的方法参数 data 就是 $emit 第二个参数传出的数据。

3. v-model:双向绑定的语法糖
v-model 常用于父子组件之间的双向数据绑定。原文指出,它的本质是子组件内部通过 props 接收 value,并通过 $emit('input') 更新父组件数据。默认用法下,父组件只写 v-model:
  1. <!-- 父组件 -->
  2. <template>
  3.   <ChildComponent v-model='inputValue' />
  4. </template>
  5. <script>
  6. export default {
  7.   data() {
  8.     return { inputValue: '' };
  9.   }
  10. }
  11. </script>
复制代码

如果需要自定义 v-model,子组件可以定义自己的 prop 和事件名称。原文示例中 prop 为 currentValue,事件为 update:currentValue:
  1. <!-- 子组件 Child.vue -->
  2. <script>
  3. export default {
  4.   props: ['currentValue'],
  5.   emits: ['update:currentValue'],
  6.   methods: {
  7.     change(val) {
  8.       this.$emit('update:currentValue', val);
  9.     }
  10.   }
  11. }
  12. </script>
复制代码

自定义 v-model 时,要重点核对 prop 名与 update: 事件名是否对应。原文给出的模式是 currentValue 配 update:currentValue,调用 change 时把新值交给父组件,从而完成同步更新。

4. Provide/Inject:父子与跨层级共享
Provide/Inject 主要面向跨层级组件通信,但父子组件之间同样可用。父组件通过 provide 提供数据或函数,子组件通过 inject 获取。原文示例:
  1. <!-- 父组件 Parent.vue -->
  2. <script>
  3. export default {
  4.   provide() {
  5.     return {
  6.       themeColor: 'blue',
  7.       getUser: () => ({ name: 'Admin' })
  8.     }
  9.   }
  10. }
  11. </script>
复制代码

子组件注入:
  1. <!-- 子组件 Child.vue -->
  2. <script>
  3. export default {
  4.   inject: ['themeColor', 'getUser']
  5. }
  6. </script>
复制代码

原文说明数据会响应式跟随变化。实际使用时,provide 返回的内容既可以是普通值,也可以是函数,示例中的 getUser 就是一个注入后可调用的函数。对于深层嵌套组件共享主题色或工具方法,这种方式比逐层传 props 更直接。

5. ref:父组件直接访问子组件实例
父组件可以通过 ref 标记子组件,然后在模板中访问子组件的属性和方法。原文示例:
  1. <!-- 父组件 Parent.vue -->
  2. <template>
  3.   <ChildComponent ref='childRef' />
  4.   <button @click='callChildMethod'>调用子组件方法</button>
  5. </template>
  6. <script>
  7. export default {
  8.   methods: {
  9.     callChildMethod() {
  10.       this.$refs.childRef.childMethod();
  11.       console.log(this.$refs.childRef.childData);
  12.     }
  13.   }
  14. }
  15. </script>
复制代码

这段代码中,this.$refs.childRef 指向子组件实例,因此可以调用 childMethod 并读取 childData。使用 ref 的前提是子组件已经渲染并建立了引用;排查时先确认 ref 名称与模板中的 ref 标记一致,再看调用发生在哪个生命周期或事件回调中。

6. $attrs 与 $listeners:属性和事件透传
原文将 $attrs 与 $listeners 列为第六种方式,主要用于组件属性透传和事件透传。它们适合封装中间层组件:父组件传下来的属性或监听事件,中间组件不逐项声明,而是继续传给内部组件。原文同时提示,在 Vue 3 Composition API 中主要是 attrs 和 expose 的使用。由于原文没有展开代码,这里不补写虚构示例,实际落地时应结合项目使用的 Vue 版本确认 API 形态。

选择与排查建议
从数据流看,Props 适合父到子的单向传递;$emit 适合子到父的事件反馈;v-model 适合需要双向同步的表单或值绑定;ref 适合父组件需要直接调用子组件方法、读取子组件数据的场景;Provide/Inject 适合跨层级共享;$attrs 与 $listeners 适合做透传封装。排查传值问题时,可以按顺序检查:数据方向是否选错;props 名称和绑定值是否正确;自定义事件名是否与监听名一致;自定义 v-model 的 prop 与 update: 事件是否配对;ref 是否指向已渲染的子组件实例;Provide/Inject 的注入键名是否与提供方一致。把这些通信方式按场景拆开使用,比在单个组件里堆叠多种传值手段更容易维护。
回复

使用道具 举报

发表于 5 天前 | 显示全部楼层

Re: Vue父子组件传值六种方式:Props、emit与v-model实践

感谢整理,这篇梳理得挺清楚,尤其是开头那句"先看数据流向和组件耦合程度"的选型原则,比单纯罗列六种写法实用多了。Props 管单向下发、$emit 管回传、v-model 管双向、ref 管实例操作,这条主线一说就很好理解。 不过有个小问题:正文到"5. ref:父组件直接访问子组件实例"那句"然后在"就断了,后面的示例和第六种 $attrs/$listeners 的内容都没贴出来,应该是发帖时被截断了,方便的话可以补一下,正好也想看看透传组件那块具体怎么写的。 另外有两处想请教下:一是 v-model 那节默认用法讲的是 value 配 input,这个在 Vue 3 里默认已经变成 modelValue 配 update:modelValue 了,如果帖子面向 Vue 2 倒没问题,但建议在开头注明下版本范围,免得新手照着写踩坑;二是 Provide/Inject 那里说数据会响应式跟随变化,如果 provide 直接返回的是一个普通字符串或普通对象(比如示例里的 themeColor: 'blue'),父组件后续改了值子组件应该收不到更新吧?是不是得配合响应式对象或函数返回值才行。整体内容质量很高,等补全后再来学习一遍。
回复 支持 反对

使用道具 举报

发表于 5 天前 | 显示全部楼层

Re: Vue父子组件传值六种方式:Props、emit与v-model实践

整理得挺清晰的,按数据流向和组件耦合程度来选这六种方式,这个思路很实用。Props 和 $emit 是最常用的两条主线,v-model 那部分把“本质是 props 接收加 $emit 更新”讲明白了,自定义 v-model 时 prop 名和 update: 事件名要成对这点也提醒得很关键,实际写的时候这里最容易出错。Provide/Inject 用来共享主题色或工具函数确实比逐层传 props 省事,不过也要注意注入的数据来源要清楚,不然调试时不太好追。另外看到 ref 那部分好像没写完,$attrs 和 $listeners 在 Vue 3 里的对应关系也值得再展开讲讲,尤其是 $listeners 合并进 $attrs 之后,透传组件的写法跟 2.x 有些差别。整体作为入门梳理已经够用了。
回复 支持 反对

使用道具 举报

发表于 5 天前 | 显示全部楼层

Re: Vue父子组件传值六种方式:Props、emit与v-model实践

楼主这篇梳理得挺清楚的,尤其开头那句“先看数据流向和组件耦合程度”,比单纯罗列六种方式有用得多。很多新手就是会背 API 但不知道什么时候该用哪个,把 Props 定位成主干、$emit 定位成反馈、Provide/Inject 定位成跨层级,这个分法很好记。 几个小疑问想请教一下: 一是文中的写法看起来偏 Vue 2。比如 v-model 默认那部分写的是子组件接收 value、emit input,自定义 v-model 用 currentValue 配 update:currentValue。如果是 Vue 3,默认约定已经变成 modelValue 和 update:modelValue 了,帖子后面是不是可以补一句两个版本的差异,不然照着抄容易踩坑。 二是结尾提到 $attrs 与 $listeners 在 Vue 3 里主要对应 attrs 和 expose,这里我有点疑惑。Vue 3 里 $listeners 是直接移除并合并进 $attrs 的,expose 更像是控制父组件通过 ref 能访问到子组件哪些内容,跟透传监听器好像不是一回事,不知道是不是原文表述被压缩了。 三是帖子的第 5 点 ref 讲了一半就断了,后面“然后在”就没内容了,应该是复制时被截掉了,方便的话补全一下,正好想看 ref 那部分和 $attrs 透传的对比。 整体框架没问题,补全加版本标注
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-27 17:23 , Processed in 0.028474 second(s), 29 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部