文章目录

  • 方案一:props/emits
    • props:父组件->子组件
    • emits:子组件->父组件
  • 方案二:v-model/ emits
  • 方案三:ref/emits
  • 应用场景

在实际业务开发的过程中,我们时常会遇到组件间的通信问题,比如:父子组件间通信、同级组件间通信等。本篇文章中主要介绍父子组件间通信。父子组件间通信主要有以下常见形式:

方案 父组件向子组件 子组件向父组件
props/emits props emits
v-model/emits v-model emits
ref/emits ref emits

不再说明!!!父组件->Parent.vue;子组件->Children.vue,并且代码主要展示template和script部分

方案一:props/emits

  props/emits是最常用的形式,也是最基础的方案。其主要过程是:
1、父组件->子组件:子组件先定义props对象并渲染到标签里,然后在父组件中调用子组件,通过属性的方式“: 变量名= ”绑定在标签上。
2、子组件->父组件:父组件先声明数据变量和更新函数然后通过“@函数名= ”绑定事件,然后子组件通过emits向父组件发送更新信号,一般伴随着数据变量。

props:父组件->子组件

首先要在子组件Children.vue定义props对象并且使用。我们先来看一下下面的代码:

// Children.vue
<script>
export default defineComponent({// props: ['title', 'index', 'userName', 'uid']props: {// 可选,并提供默认值title: {type: String,required: false,default: '默认标题',},// 默认可选,单类型index: Number,// 添加一些自定义校验userName: {type: String,// 在这里校验用户名必须至少 3 个字validator: (v) => v.length >= 3,},// 默认可选,但允许多种类型uid: [Number, String],},// 在这里需要添加一个入参setup(props) {// 该入参包含了当前组件定义的所有 propsconsole.log(props)},
})
</script><template>// 渲染父组件传递过来的值<p>标题:{{ title }}</p><p>索引:{{ index }}</p><p>用户id:{{ uid }}</p><p>用户名:{{ userName }}</p>
</template>

  虽然可以将变量一并装在一个string[]数组里,但是更推荐封装在对象里,因为vue3支持对props进行类型限制和一些配置,这样在实际开发中不会造成格式混乱。如果传入不正确的类型,会抛出警告信息。例如父组件向子组件传递一个日期,如果不做类型限制的话可能会导致页面渲染失败。
其中支持的类型有:

类型 含义
String 字符串
Array 数组
Boolen 布尔值
Object 对象
Date 日期
Function 函数;例如:钩子函数、箭头函数和普通函数等
Promise Promise类型的函数
Symbol Symbol类型的值

支持的配置选项有:

选项 类型 含义
type string 类型
required boolean 是否必传,true是必传,false为可传
default any 与type类型相对应的默认值。若required为false但不设置默认值,则默认为undefined
validator function 自定义验证函数,需要return一个布尔值,true为校验通过,false为校验不通过。校验不通过时,控制台会抛出警告信息

然后在父组件Parent.vue中调用子组件,通过属性的方式“: 变量名= ”绑定在标签上。来看以下代码:

// Parent.vue
<script>
import { defineComponent } from 'vue'
// 引入子组件Children.vue
import Children from '@./Children.vue'
interface Member {id: numbername: string
}
export default defineComponent({// 需要启用子组件作为模板components: {Children,},setup() {const userInfo: Member = {id: 1,name: 'Petter',}return {userInfo,}},
})
</script><template><Childrentitle="用户信息":index="1":uid="userInfo.id":user-name="userInfo.name"/>
</template>

emits:子组件->父组件

首先父组件Parent.vue声明数据变量和定义更新函数然后通过“@事件名称=更新函数 ”绑定事件。看下面代码:

// Parent.vue
<script>
import { defineComponent, reactive } from 'vue'
import Children from '@./Children.vue'
interface Member {id: numbername: stringage: number
}
export default defineComponent({components: {Children,},setup() {const userInfo: Member = reactive({id: 1,name: 'Petter',age: 0,})/*** 声明一个更新年龄的方法* @param name, age - 新的名字和新的年龄,由子组件触发 emits 时向父组件发送信号*/function updateInfo({ name, age }: Member) {// 当 `name` 变化时更新 `name` 的值if (name && name !== userInfo.name) {userInfo.name = name}// 当 `age` 变化并且新值在正确的范围内时,更新 `age` 的值if (age > 0 && age !== userInfo.age) {userInfo.age = age}// 显示新的名字和新的年龄alert({ name, age })},return {userInfo,updateInfo,}},
})
</script><template><Child @update-info="updateInfo" />
</template>

然后子组件Children.vue通过emits向父组件发送更新信号,一般伴随着数据变量。来看下面代码:

// Children.vue
<script>
export default defineComponent({// emits: ['update-info']// 先定义emits对象emits: {// 需要校验'update-info': (name: string, age: number) => {// 写一些条件拦截,返回 `false` 表示验证不通过if (age < 18) {console.log('未成年人不允许参与')return false}// 通过则返回 `true`return true},// 若无需校验的,设置为 `null` 即可。例如:'update-name': null},// 使用 setup 第二个参数 context 里的 emit 方法触发setup(props, { emit }) {// 通知父组件将年龄设置为 `18`和将姓名设置为`Tom`emit('update-info', {name: 'Tom',age: 18,})},
})
</scirpt><template><div @click="undate-info">发送给父组件</div>
</template>

  和 props 一样,可以指定是一个数组,把要接收的 emit 事件名称写进去;但是相同的使用对象可以更好管理数据。emits最少要传递一个参数:事件名称。事件名称是在子组件书写。
  上述代码的事件名称是指父组件 Parent.vue 绑定事件时 @update-info=“updateInfo” 里的 update-info ,如果改成 @hello=“updateInfo” ,那么事件名称就需要使用 hello ,一般情况下事件名称和更新函数的名称会保持一致,方便维护。
  同时,emits也支持传递多个参数,第二个参数可以使用对象修饰数据。
  emits可以进行一些校验操作,方法如下emits:{ 事件名称(key): 函数(val) => { return 布尔值 }},详情看上述代码。

TIPS:
1、官方文档推荐对 camelCase 风格(小驼峰)命名的 props 和emits,但在绑定时使用和 HTML attribute 一样的 kebab-case 风格(短横线),例如使用 user-name 代替 userName 传递,详见官网的传递 props和emits的细节 一节。

方案二:v-model/ emits

  事实上,v-model与props的配置差不多,那为什么要用v-model呢?主要体现在父组件->子组件上。
  在上述的讲解中可以看出,方案props/emits中,子组件向父组件传递数据,父组件必须声明一个更新函数并绑定事件给子组件,才能更新数据。而使用方案v-model/emits则无需父组件声明函数就能更新数据。具体改动如下:

// Parent.vue
<template><Childrenv-model:uid="userInfo.id"v-model:username="userInfo.name"v-model:age="userInfo.age"/>
</template>
<script>
import { defineComponent, reactive } from 'vue'
import Children from '@./Children.vue'
interface Member {id: numbername: stringage: number
}
export default defineComponent({setup() {// 通知父组件将年龄设置为 `18`和将姓名设置为`Tom`const userInfo: Member = reactive({id: 1,name: 'Petter',age: 0,}),onMounted( () => {console.log(userInfo.id, userInfo.name,userInfo.age)}),return userInfo},
})
</script>

想要绑定多个数据,可以使用多个v-model;
格式:<组件 v-model: 子组件中定义的变量名称=父组件定义的变量名称></组件>

// Children.vue
<script>
export default defineComponent({props: {uid: Number,username: String,age: Number,},// 注意这里的 `update:` 前缀emits: ['update:uid', 'update:username', 'update:age'],
})
</script>
<template>// 渲染父组件传递过来的值<p>用户id:{{ uid }}</p><p>用户名:{{ username }}</p><p>年龄:{{ age }}</p>
</template>

子组件中emits属性格式需要转变成:emits: [update: 父组件v-model属性名/子组件定义的变量名称。]

方案三:ref/emits

  props和v-model主要是值的传递,而使用ref还可以操作子组件的方法

  除了方案一、二之外,我们还可以使用方案三ref/emits。主要改动也是体现在父组件->子组件上,且进一步简化了操作。我们只需要在父组件上声明一个响应式对象,而无需再像上面两个方案上一样,需要父组件调用子组件时在子组件上绑定一个ref属性,然后就能对子组件的属性和方法进行操作,这样会简化代码。具体操作如下:
  首先,子组件上声明响应式变量,然后在setup函数内return变量。只有return了父组件才能调用,否则父组件无法获取。

// Children.vue
<template>// 渲染从父组件Parent.vue接受到的值<div> Children: {{ valueRef }}</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({name: 'Children',setup() {const valueRef = ref('')// 该函数可以接受父级传递一个参数,并修改valueRef的值const acceptValue = (value: string) => (valueRef.value = value)return {acceptValue,valueRef}}
})
</script>

  然后父组件Parent.vue使用空的响应式对象来操作子组件的响应式对象,并且调用子组件时在其标签上绑定ref属性。

// Parent.vue
<template><div>childrenRef</div><button @click="sendValue">send</button>// 这里ref接受的字符串,要setup返回的ref类型的变量同名<Children ref="childrenRef" />
</template><script lang="ts">
import { defineComponent, ref } from 'vue'
import Children from './Children.vue'
export default defineComponent({name: 'Parent',components: {Children},setup() {// 如果ref初始值是一个空,可以用于接受一个实例// vue3中获取实例的方式和vue2略有不同const childrenRef = ref<typeof Children>()// 请保证视图渲染完毕后再执行操作onMounted( () => {// 可以拿到Children组件实例,并调用其setup返回的所有信息console.log(childrenRef.value)// 通过调用子组件实例的方法,向其传递数据childrenRef.value.acceptValue('123456')// 也可以去操作子组件的数据childrenRef.value.valueRef = '8888';});// 必须return出去才可以给到template使用return {childrenRef, }}
})
</script>

  ref()其实是将变量变成一个对象,以键值对存储{ 变量名key:值value}。子组件实例本身就以键值对形式存储,而子组件中的响应式对象的存储形式又是键值对,故父组件调用子组件的响应式对象的格式是:响应式对象.value.子组件响应式对象。
  emits的改动请参考方案二。

应用场景

知道原理后,我们要回到实际开发应用中去:一般情况下
1、父组件->子组件:父组件发起 AJAX 请求,拿到数据后,再根据子组件的渲染需要传递不同的 props 给不同的子组件使用。
2、子组件->父组件:更新表单等数据量较多时非常好用。

vue3-父子组件间通信相关推荐

  1. Vue3父子组件间传参通信

    Vue3 父子组件间通信 前言 一.父传子 defineProps 二.子传父 defineEmits 三.子组件暴露属性给父组件 defineExpose 四.依赖注入Provide / Injec ...

  2. 【Vue父子组件间通信】

    Vue父子组件间通信 父子组件通信 父传子 (props) 子传父 (自定义事件) 完整代码 效果 父子组件通信 父传子 (props) (1)在父组件中使用子组件时,给子组件一个自定义属性,这个属性 ...

  3. vue -- watch侦听器与父子组件间通信

    watch侦听器 方式一 1.默认有两个参数 newValue与oldValue 2.如果是对象类型那么拿到的是代理对象 如果要进行深度监听 需要加上 deep : true 如果想要第一次渲染直接执 ...

  4. vue 父子组件间通信

    前言 在vue项目中,封装组件,涉及到父子组件的传值,本文主要讲解父子组件之间传值的方法. 一.props / $emit 适用于父子组件通信,单向数据流,这种方法是 vue 组件的基础. 二.ref ...

  5. Vue2.0入门系列——父子组件间通信

    1.子组件更新,父组件不变 点击"按钮"按钮,子组件数据被修改,父组件数据不变  =========>>>>>>  项目源代码, <hea ...

  6. Vue父子组件间通信

    组件是vue.js最强大的功能之一,但组件之间的作用域是相互独立的,这就意味着不同组件之间的数据是无法相互引用的.为实现组件之间的通信,vue为我们提供了三种方式:prop.ref.emit. 首先创 ...

  7. 深入浅出,带你看懂Vue组件间通信的8种方案

    前言 Vue种组件通信的情况有多种,总结有以下4种情况: 父子组件间通信 兄弟组件间通信 祖孙后代间通信 无关系组件间通信 8种解决方案 通过 props 传递 通过 $emit 触发自定义事件 使用 ...

  8. Vue实现组件间通信的七种方式

    1. props / $emit 父组件通过props的方式向子组件传递数据,而通过$emit 子组件可以向父组件通信: 父传子:父组件通过import引入子组件,并注册,在子组件标签上添加要传递的属 ...

  9. vue中组件间通信的6种方式

    前言 组件是 vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互进行直接的引用,所以组件间的相互通信是非常重要的. 除了使用vuex外还有下面6种组件间 ...

最新文章

  1. matlab抓取股票数据,Matlab经过sina web接口获取个数即时股票数据函数实现代码
  2. HDU 2818 Building Block
  3. .NET架构小技巧(8)——优待异常
  4. 【STC15库函数上手笔记】6、ADC
  5. mysql数据库事务有几种特性_面试官:你能说说事务的几个特性是啥?有哪几种隔离级别?...
  6. Netscaler 10.5 VPX与XenApp XenDesktop 集成配置系列之三enable StoreFront Remote Access
  7. elementUI 日期选择控件少一天的问题解决方法
  8. Spark ML机器学习
  9. Flutter之Dialog 简单使用
  10. SpringBoot中Async异步方法和定时任务介绍
  11. linux u盘无损分区,Unix/Linux无损分区解决方案[原创]
  12. 使用burp对Tomcat 弱密码爆破
  13. QT之隐藏任务栏图标
  14. JustinMind原型制作工具
  15. SharedPreferences in credential encrypted storage are not available until after user is unlocked
  16. C语言学习笔记——(三)静态开辟内存和动态开辟内存
  17. 微信小程序--游戏demo
  18. AI作画的人机战争走向何方?
  19. Springboot - 处理LocalDateTime的入参和出参格式
  20. 计算一幅图像的平均亮度

热门文章

  1. 每天一道算法--经典兔子繁殖迭代问题(斐波那契数列)
  2. 人工智能就业发展前景分析
  3. USB供电类型简单介绍
  4. 上了java课程的一些收获
  5. csdn上的blog 编辑器-xhEditor编辑器
  6. 在小红书投放后,如何复盘才更有效?品牌方速看
  7. 常见数学符号的英文表达
  8. 解一元二次方程ax2+bx+c=0的解。
  9. java中级开发面试总结
  10. 基于JAVA毕业设计的超市管理系统