Vue 组件通信指的是在 Vue.js 应用程序中,不同组件之间传递数据和信息的过程。在一个项目中,通常有很多个组件,其中每个组件都是独立的实例,都拥有自己的状态和方法。因此,为了构建复杂的应用,组件之间需要能够互相传递数据和信息,也就是进行组件通信,接下来的几篇内容将对vue组件通信的方式进行一个详细介绍。以下是vue组件通信的方式:
- 父传子 Props
- 子传父 Emits
- 双向数据绑定 V-model
- 多层组件传递 Provide / Inject
- Refs传参
- Composition API (特别是
reactive
,ref
,computed
,watch
) - attrs / listeners
- Vuex
- pinia
- Event Bus
本篇内容先对父子组件通信的三种方式props、emits以及v-model进行介绍。
一.父传子
父组件通过 props
向子组件传递数据。使用 props
是父传子最常见的方式。使用的方也很简单,只需要在子组件中声明 props
,定义它期望从父组件接收的数据,父组件中通过冒号绑定。
-
声明 Props:
- 在子组件中使用
props
选项声明它期望接收的属性。 - 指定
props
的类型,默认值,以及是否必填。
- 在子组件中使用
-
动态绑定:
- 父组件可以使用
v-bind
或简写为:
来动态绑定数据到子组件的props
。
- 父组件可以使用
-
单次绑定:
- 使用
.once
修饰符 (v-bind:title.once
) 可以进行单次绑定,数据只会从父组件传到子组件一次。
- 使用
举个例子:
父组件:
<template>
<div class="container">
<div class="mytitle">
我是父组件
</div>
<div>
<childView :data="fatherdata"></childView>
</div>
</div>
</template>
<script setup>
import {ref} from 'vue'
import childView from './ChildView.vue'
const fatherdata = ref("100万");
</script>
子组件;
<template>
<div class="container">
<div class="mytitle">
我是子组件;
</div>
<div>
1.父传子: 父亲传给我{
{ data }}元
</div>
</div>
</template>
<script setup>
import {ref} from 'vue'
const props = defineProps({
data:{
type:String,
default:"0"
}
})
</script>
在props中,也可以对传入数据的类型、默认值、是否必填进行指定:
<script setup>
const props = defineProps({
// 基础类型检测 (`null` 意味着任何类型都可以)
title: String,
likes: Number,
// 多种类型
id: [String, Number],
// 必须的字符串
author: {
type: String, // 指定类型
required: true, // 指定是否为必填项
},
// 带有默认值的数字
initialEnthusiasm: {
type: Number,
default: 1,
},
// 带有默认值的对象
article: {
type: Object,
// 对象或数组默认值必须从工厂函数返回
default: () => ({
content: '',
published: false,
}),
},
// 自定义验证函数
email: {
type: String,
validator: (value) => {
const pattern = /^\S+@\S+\.\S+$/;
return pattern.test(value);
},
},
});
</script>
二.自定义事件emits
子组件通过 $emit
函数触发一个自定义事件,并将数据作为参数传递给父组件。父组件监听这个事件,并定义一个方法来处理传递的数据。

子组件:
<template>
<div class="container">
<div class="mytitle">
我是子组件;
</div>
<div class="score" @click="getData">
这是一张{
{ data }}分的试卷
</div>
</div>
</template>
<script setup>
import { ref, defineEmits } from 'vue'
const data = ref (80)
const emits = defineEmits(['giveData'])
const getData = () => {
emits('giveData',data.value)
}
</script>
父组件:
<template>
<div class="container">
<div class="mytitle">
我是父组件
</div>
<div>
<childView @giveData="handle"></childView>
<div>儿子考了{
{ childScore }} 分</div>
</div>
</div>
</template>
<script setup>
import {ref} from 'vue'
import childView from './ChildView.vue'
const childScore = ref (0)
const handle = (score) => {
console.log("传入的score",score)
childScore.value = score
}
</script>
以该代码为例,总结出子传父的通信过程:
-
初始化:
- 父组件引入并使用子组件
<childView>
。 - 父组件监听子组件的自定义事件
giveData
,并绑定了处理函数handle
。
- 父组件引入并使用子组件
-
事件触发:
- 用户在子组件中点击分数显示区域时,会触发
getData
方法。 getData
方法内部使用emits
函数触发giveData
事件,并传递当前data.value
的值。
- 用户在子组件中点击分数显示区域时,会触发
-
事件处理:
- 父组件中的
handle
方法被调用,接收从子组件传递过来的分数score
。 handle
方法将接收到的分数赋值给childScore
,从而更新父组件的状态。
- 父组件中的
-
状态更新:
- 由于
childScore
是响应式数据,其值的更新会触发父组件的重新渲染。 - 父组件模板中显示的 “儿子考了{ { childScore }} 分” 也会相应更新,显示最新的分数。
- 由于
三.v-model 双向数据绑定
该方法常用于表单输入组件,它实际上是 props
和 emits
的语法糖。
在父组件中使用 v-model
指令绑定一个变量到子组件上时,Vue 实际上做了两件事情:
一是将一个名为 modelValue
的 prop 传递给子组件。
二是监听一个名为 update:modelValue
的事件,该事件在子组件内部被触发时,会更新绑定的变量。
那么是如何实现的呢?举个例子:
子组件:
在子组件内部,首先需要定义一个 prop,通常命名为 modelValue
,用来接收父组件传递的值。
然后定义一个事件发射器(通过 defineEmits
或 this.$emit
),当子组件需要更新父组件的状态时,触发 update:modelValue
事件,并传递新的值。
<template>
<div class="container">
<div class="mytitle">
我是子组件;
</div>
<input :value="modelValue" @input="handleInput" placeholder="请输入数字">
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
const props = defineProps(['modelValue'])
const emits = defineEmits(['update:modelValue'])
const handleInput = (event) => {
const newValue = event.target.value;
emits('update:modelValue', newValue);
};
</script>
父组件:
在父组件中,parentData
是一个响应式引用,给他设定初始值为 0
。通过 v-model
指令,它被绑定到子组件的 modelValue prop
上,并且监听 update:modelValue
事件来更新 parentData
。
<template>
<div class="container">
<div class="mytitle">
我是父组件
</div>
<div>
<childView v-model="parentData">parentData的初始值为{
{ parentData }}</childView>
</div>
</div>
</template>
<script setup>
import {ref} from 'vue'
import childView from './ChildView.vue'
const parentData = ref (0)
</script>
当在输入框中输入内容时,将触发 <input>
的 input
事件,接着handleInput
方法被调用,获取新的输入值。然后handleInput
方法通过 $emit
触发 update:modelValue
事件,并将新的值作为参数。这时父组件监听到 update:modelValue
事件,并更新绑定的 parentData
变量,至此实现子父组件的双向数据绑定。
这篇文章就先介绍到这里,下篇内容介绍多层组件传递 Provide / Inject 以及 Refs 传参。