「这是我参与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
选项可以对应一个字符串数组: