前言
在Vue中,组件通讯主要通过props和events来实现。通过props,父组件可以向子组件传递数据,子组件则通过props接收并使用这些数据。而通过events,子组件可以向父组件发送消息或触发事件,父组件可以监听这些事件并做出响应。
此外,Vue还提供了provide和inject API,允许祖先组件向所有后代组件注入依赖项,而无需显式传递props。这在跨多层次嵌套的组件中特别有用。
今天我们就来聊一聊vue中的组件通讯。
1. 话题引入
我们首先来看一下最原始的一段vue
xml
<template>
<div class="input-group">
<input type="text" v-model="value">
<button @click="add">提交</button>
</div>
<div>
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue'
const list = ref(['html', 'css', 'js'])
let value = ref('')
const add = () => {
list.value.push(value.value)
value.value = ''
}
</script>
<style lang="css" scoped>
</style>
这里面的作用很简单,我们通过点击input框可以让列表增加内容。
2.父子组件通讯(父将数据给子)
父子组件通讯 --- 父组件将值v-bind绑定传给子组件,子组件使用defineProps接受
我们文件的大致格式如上,我们这一次的父组件是App1.vue,子组件就是对应的child1.vue.
App1.vue
xml
<template>
<div class="input-group">
<input type="text" v-model="value">
<button @click="add">提交</button>
</div>
<child :list="list"></child>
</template>
<script setup>
import { ref } from 'vue'
import child from '@/components/child1.vue'
const list = ref(['html', 'css', 'js'])
let value = ref('')
const add = () => {
list.value.push(value.value)
value.value = ''
}
</script>
<style lang="css" scoped>
</style>
-
<child>
组件:- 将父组件的
list
数组作为属性传递给子组件<child>
。
- 将父组件的
-
<script setup>
:- 使用
ref
函数创建了两个响应式变量:list
和value
。 list
是一个数组,初始包含三个字符串元素:'html', 'css', 'js'。value
是一个字符串,初始为空。- 定义了
add
函数,用于向list
数组添加新的项,并清空value
。
- 使用
child1.vue
xml
<template>
<div class="child">
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
defineProps({
list: {
type: Array,
default: () => []
}
})
</script>
<style lang="css" scoped>
</style>
-
模板部分 (
<template>
) :- 使用了 Vue 的指令
v-for
,遍历list
数组中的每个item
,并将每个item
显示为一个<li>
列表项。
- 使用了 Vue 的指令
-
<script setup>
部分:- 使用了
defineProps
函数,声明了一个名为list
的 prop。 list
的类型被指定为数组 (type: Array
),并设置了默认值为空数组 (default: () => []
)。- 这样做是为了确保
<child>
组件能够正常接收和处理来自父组件的list
数组数据。
- 使用了
这段代码的大致思路是,首先我们将父组件的list数组传给了子组件,然后子组件以defineProps的形式进行接收,然后进行我们的渲染工作。
App2.vue
xml
<template>
<div class="input-group">
<input type="text" v-model="value">
<button @click="add">提交</button>
</div>
<child :msg="tochild"></child>
</template>
<script setup>
import { ref } from 'vue'
import child from '@/components/child2.vue'
let value = ref('')
let tochild = ref('')
const add = () => {
tochild.value = value.value
}
</script>
<style lang="css" scoped>
</style>
这个 Vue 组件的结构设计了一个简单的输入表单和一个子组件的嵌套。
在<template>
中:
- 有一个包含输入框和提交按钮的
.input-group
容器。输入框通过v-model="value"
实现双向数据绑定,将用户输入的内容同步到value
变量。 - 点击按钮时,触发了
add
方法,这个方法将value
变量的值赋给tochild
变量。
接着,通过 <child :msg="tochild"></child>
将 tochild
变量的值作为 msg
属性传递给了名为 child
的子组件。
在 <script setup>
部分:
- 使用了 Vue 3 的 Composition API 中的
ref
函数来声明了两个响应式变量value
和tochild
,它们分别用于存储输入框的内容和传递给子组件的数据。 add
函数定义了按钮点击时的行为,将当前输入框中的值赋给tochild
变量,以便将其传递给子组件。
child2.vue
xml
<template>
<div class="child">
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { watch, ref } from 'vue'
const list = ref(['html', 'css', 'js'])
const prop = defineProps({
msg:''
})
watch(() => prop.msg, (newVal, OldVal) => {
list.value.push(newVal)
}
)
</script>
<style lang="css" scoped>
</style>
这个 Vue 组件的目的是展示一个简单的列表,列表的内容来自于 list
变量,并且可以接收一个名为 msg
的 prop 属性,将其值添加到列表中。在<template>
中: <ul>
标签用于显示一个无序列表,其中的每个 <li>
标签通过 v-for="item in list"
遍历 list
变量中的每个元素,并将其显示在列表中。
在 <script setup>
部分:
- 使用了 Vue 3 的 Composition API 中的
ref
和watch
函数。 list
是一个包含初始值为['html', 'css', 'js']
的响应式数组,用于存储列表中的项目。- 使用
defineProps
定义了一个名为msg
的 prop 属性,允许父组件向当前组件传递数据。 watch
函数监听了prop.msg
的变化,当msg
属性的值发生变化时,会执行回调函数将新值newVal
添加到list
数组中。 这里我们直接让数组归子组件所有,我们直接让父组件传入更新后的值给子组件。
3.子父组件通讯(子将数据给父)
1.子父组件通讯 --- 借助发布订阅机制,子组件负责发布事件并携带参数,父组件订阅该事件通过事件参数获取子组价提供的值
App3.vue
xml
<template>
<child @add1="handle"></child>
<div class="child">
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue'
import child from '@/components/child3.vue'
const list = ref(['html', 'css', 'js'])
const handle = (e) => {
list.value.push(e)
}
</script>
<style lang="css" scoped>
</style>
-
使用了
child
组件,并监听了子组件触发的add1
自定义事件,当事件触发时调用handle
方法。 -
显示一个包含动态生成内容的无序列表 (
<ul>
),使用v-for="item in list"
循环遍历list
变量中的每个元素,并在每个<li>
中显示该元素的内容。 -
导入了 Vue 3 的
ref
函数,用于声明响应式变量。 -
定义了
list
变量作为一个响应式数组,初始包含['html', 'css', 'js']
三个元素,用于存储列表显示的内容。 -
定义了一个
handle
函数,该函数接收一个参数e
,将其作为新的元素添加到list
数组中。
child3.vue
xml
<template>
<div class="input-group">
<input type="text" v-model="value">
<button @click="add">提交</button>
</div>
</template>
<script setup>
import {ref} from 'vue'
let value = ref('')
const emits = defineEmits(['add1'])
const add = () => {
emits('add1', value.value)
}
</script>
<style lang="css" scoped>
</style>
在模板部分 (<template>
) 中:
- 包含一个输入框 (
<input>
) 和一个按钮 (<button>
)。 - 使用了
v-model="value"
来实现双向数据绑定,将输入框中的内容与value
变量进行绑定,即用户在输入框中输入的内容会同步更新到value
变量中。 - 点击按钮时触发
add
方法。
在 <script setup>
部分:
- 导入了 Vue 3 的
ref
函数,用于声明一个响应式变量value
,其初始值为空字符串''
,用于存储输入框中的内容。 - 使用
defineEmits(['add1'])
定义了一个名为add1
的自定义事件,用于向父组件发送数据。 - 定义了
add
函数,当按钮被点击时,通过emits('add1', value.value)
发送add1
事件,并将当前value
变量的值作为参数传递给父组件。
2.子父组件通讯 --- 父组件借助v-model将数据绑定给子组件,子组件创建'update:xxx'事件,并接收到的数据修改后emits出来
App4.vue
xml
<template>
<child v-model:list="list"></child>
<div class="child">
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue'
import child from '@/components/child4.vue'
let value = ref('')
const list = ref(['html', 'css', 'js'])
</script>
<style lang="css" scoped>
</style>
-
子组件的使用:
- 在模板部分 (
<template>
) 中,使用了<child v-model:list="list"></child>
,这表示在父组件中将list
变量作为child
组件的v-model
绑定。 v-model:list="list"
会将父组件的list
变量作为一个 prop 传递给child
组件,并且监听child
组件触发的更新事件来同步数据。
- 在模板部分 (
-
列表的渲染:
- 父组件中定义了一个
<div class="child">
,其中包含一个无序列表 (<ul>
)。
- 父组件中定义了一个
child4.vue
xml
<template>
<div class="input-group">
<input type="text" v-model="value">
<button @click="add">提交</button>
</div>
</template>
<script setup>
import {ref} from 'vue'
let value = ref('')
const prop = defineProps({
list: {
type: Array,
default: () => []
}
})
const emits = defineEmits(['update:lis'])
const add = () => {
// prop.list.push(value.value)
const arr = prop.list
arr.push(value.value)
emits('update:lis',arr)
}
</script>
<style lang="css" scoped>
</style>
-
输入框和按钮:
- 在模板部分 (
<template>
) 中,有一个包含输入框和按钮的<div>
,类名为input-group
。 - 输入框 (
<input>
) 使用了v-model="value"
来实现双向数据绑定,即输入框中的内容会与value
变量同步。 - 提交按钮 (
<button @click="add">提交</button>
) 通过点击触发add
方法。
- 在模板部分 (
-
脚本部分 (
<script setup>
) 解释:- 使用
ref
函数引入value
变量,初始值为空字符串''
,用于存储输入框中的内容。 - 使用
defineProps
定义了一个名为list
的 prop,类型为数组 (Array
),默认值为空数组 (() => []
)。 - 使用
defineEmits
定义了一个名为update:lis
的自定义事件,用于向父组件传递更新后的列表数据。
- 使用
3.子父组件通讯 --- 父组件通过ref获取子组件中defineExpose() 暴露出来的数据
App5.vue
xml
<template>
<child ref="reff"></child>
<div class="child">
<ul>
<li v-for="item in reff?.list">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import child from '@/components/child5.vue'
let value = ref('')
let reff = ref(null)
</script>
<style lang="css" scoped>
</style>
-
子组件引用:
- 在
<template>
部分,通过<child ref="reff"></child>
的方式引入了名为child
的子组件,并通过ref="reff"
将子组件实例存储在reff
变量中,便于后续访问子组件的属性和方法。
- 在
-
列表展示:
- 在
<template>
中的<ul>
中,使用v-for="item in reff?.list"
遍历reff
引用的子组件中的list
属性。这里通过?.
安全访问操作符,确保在reff
尚未被初始化之前不会抛出错误。 - 每个
<li>
标签显示了item
变量的内容,即子组件中列表中的每个项。
- 在
-
脚本部分 (
<script setup>
) 解释:- 使用
ref
函数声明了value
和reff
变量。value
变量用于存储输入框的内容(在示例中未使用到),reff
变量用于引用子组件的实例。 - 使用
import child from '@/components/child5.vue'
导入了名为child
的子组件,在当前组件中可以直接使用它。
- 使用
child5.vue
xml
<template>
<div class="input-group">
<input type="text" v-model="value">
<button @click="add">提交</button>
</div>
</template>
<script setup>
import {ref} from 'vue'
let value = ref('')
const list = ref(['html', 'css', 'js'])
const add = () => {
list.value.push(value.value)
}
defineExpose({list:list})
</script>
<style lang="css" scoped>
</style>
输入框和按钮位于 <template>
部分。输入框通过 v-model="value"
双向绑定到 value
变量,允许用户输入文本并自动更新 value
的值。按钮通过 @click="add"
绑定了 add
方法,点击按钮时触发 add
方法。
在 <script setup>
部分,使用 import {ref} from 'vue'
导入 Vue Composition API 的 ref
函数。然后声明了两个响应式变量:
value
:用于存储输入框中的文本内容,初始值为空字符串。list
:用ref(['html', 'css', 'js'])
初始化为一个包含三个字符串('html', 'css', 'js')的数组。
add
方法定义了一个箭头函数,当按钮被点击时会调用这个函数。它将 value.value
的值(即当前输入框中的文本)添加到 list.value
数组末尾。