「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战」。
假设 App 组件可拆分为如下结构:
那么各组件的嵌套逻辑(存在的关系)如下:
App组件是Header、Main和Footer组件的父组件,Header、Main和Footer组件是App组件的子组件;Main组件是Banner、ProductList组件的父组件,Banner、ProductList组件是Main组件的子组件;Header和Main是非父子组件,Header和Footer是非父子组件,Header和Banner也是非父子组件,等等;
在开发过程中,我们会经常遇到需要组件之间(最常见的是父子组件之间)相互进行通信的情形:
- 比如
App可能使用了多个Header,每个地方的Header展示的内容不同,那么我们就需要使用者传递给Header一些数据,让其进行展示; - 又比如我们在
Main中一次性请求了Banner数据和ProductList数据,而这些数据不是在Main中展示的,而是由Banner和ProductList进行展示,那么就需要把数据传递给Banner和ProductList组件来进行展示; - 也可能是子组件中发生了事件,需要由父组件来完成某些操作,那就需要子组件向父组件传递事件;
总之,在一个 Vue 项目中,组件之间的通信是非常重要的环节,所以下面我们就具体学习一下组件之间是如何相互传递数据的。
1. 父子组件之间通信的方式
父子组件之间如何进行通信呢?
- 父组件传递数据给子组件:通过
props属性; - 子组件传递给父组件:通过
$emit触发事件;
2. 父组件传递给子组件
在开发中,最常见的可能就是父子组件之间的通信了,比如父组件有一些数据,需要子组件来进行展示时,我们就可以通过 props 来完成父组件向子组件的通信。
什么是 props 呢?
-
props是你可以在组件上注册的一些自定义的attribute(属性);原生的
HTML元素上会有一些属性(attribute),如:class、id和style等等;而对于Vue组件来说,也可以有一些自己的属性(attribute),我们可以在组件中通过props选项来注册一些属于组件自己属性(attribute)。 -
先在子组件中使用
props选项注册好自己的prop属性(attribute)列表,之后父组件就可以传递数据给子组件的某个prop属性(attribute),子组件就能通过这个prop属性(attribute)的名称获取到父组件传递过来的对应数据;
props 的注册有两种方式:
- 字符串数组
- 数组中的字符串就是
attribute的名称;
- 数组中的字符串就是
- 对象
- 通过使用对象类型,我们可以在指定
attribute名称的同时,指定该attribute接受的数据类型、是否是必须的、默认值等等;
- 通过使用对象类型,我们可以在指定
假如有这样一个需求:父组件传递一些数据给子组件,到时候在子组件中展示这些数据。
我们在项目目录(learn_component)下的 src 目录下新建 03_父组件传递子组件 文件夹,在该文件夹中新建 App.vue(作为父组件)和 ShowMessage.vue(作为子组件)文件。然后,按以下步骤实现上面的需求:
-
在子组件(这里即
ShowMessage.vue)中的props选项中按需求注册prop(这里以字符串数组的方式举例):<template> <div> </div> </template> <script> export default { props: ['title', 'content'] } </script> <style scoped> </style> -
在父组件(这里即
App.vue)中导入并使用子组件(ShowMessage.vue),并通过上一步在子组件中注册的两个属性(title和content)传递数据:<template> <div> <show-message title="哈哈哈" content="我是哈哈哈"></show-message> </div> </template> <script> import ShowMessage from './ShowMessage.vue' export default { components: { ShowMessage } } </script> <style scoped> </style> -
子组件接收到
title和content这两个attribute传递过来的数据后,就可以在自己的模板中访问title和content这两个property的值了:<template> <div> <h2>{{ title }}</h2> <p>{{ content }}</p> </div> </template> <script> export default { props: ['title', 'content'] } </script> <style scoped> </style>
为了看到对应的效果,我们需要修改一下 src/main.js 中引入 App.vue 组件的路径:
import { createApp } from 'vue'
import App from './03_父组件传递子组件/App.vue'
createApp(App).mount('#app')
页面效果如下:
可见,成功实现了前面的需求(父组件传递一些数据给子组件,到时候在子组件中展示这些数据)。
也就是说,我们已经实现了父组件传递给子组件什么数据,子组件就能展示什么数据的功能。
并且父组件中也可以使用多个子组件,传递多份数据:
<template>
<div>
<show-message title="哈哈哈" content="我是哈哈哈"></show-message>
<show-message title="呵呵呵" content="我是呵呵呵"></show-message>
<show-message title="嘻嘻嘻" content="我是嘻嘻嘻"></show-message>
</div>
</template>
<script>
import ShowMessage from './ShowMessage.vue'
export default {
components: {
ShowMessage
}
}
</script>
<style scoped>
</style>
效果如下:
当然,上面我们是直接把数据传给了属性,我们也可以先把数据保存到变量中,再通过变量把数据传给属性,那么,我们就可以在 data 选项中定义变量之后通过 v-bind 将变量绑定到对应属性上:
<template>
<div>
<show-message title="哈哈哈" content="我是哈哈哈"></show-message>
<!-- 绑定 data 选项中的数据 -->
<show-message :title="title" :content="content"></show-message>
<show-message :title="message.title" :content="message.content"></show-message>
<!-- 绑定 data 选项中的一个对象数据 -->
<show-message v-bind="message"></show-message>
</div>
</template>
<script>
import ShowMessage from './ShowMessage.vue'
export default {
components: {
ShowMessage
},
data() {
return {
title: '呵呵呵',
content: '我是呵呵呵',
message: {
title: '嘻嘻嘻',
content: '我是嘻嘻嘻'
}
}
}
}
</script>
<style scoped>
</style>
如果想要传递整个对象中的属性和值,还可以直接 v-bind 这个对象:
<template>
<div>
<show-message title="哈哈哈" content="我是哈哈哈"></show-message>
<show-message :title="title" :content="content"></show-message>
<show-message :title="message.title" :content="message.content"></show-message>
<show-message v-bind="message"></show-message>
</div>
</template>
<script>
import ShowMessage from './ShowMessage.vue'
export default {
components: {
ShowMessage
},
data() {
return {
title: '呵呵呵',
content: '我是呵呵呵',
message: {
title: '嘻嘻嘻',
content: '我是嘻嘻嘻'
}
}
}
}
</script>
<style scoped>
</style>
2.1 父传子 - props 数组用法
子组件中的 props 选项可以对应一个字符串数组: