【Vue3】组件通信之props
背景
随着年龄的增长,很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来,技术出身的人总是很难放下一些执念,遂将这些知识整理成文,以纪念曾经努力学习奋斗的日子。本文内容并非完全原创,大多是参考其他文章资料整理所得,感谢每位技术人的开源精神。
简介
本文介绍 Vue3 中如何使用 props
实现组件间通信,即组件间相互传数据。
Vue3 中组件间通信包括:
- 父组件向子组件传数据,实现方案有:
props
v-model
$ref
- 默认插槽 / 具名插槽
- 子组件向父组件传数据
props
v-model
$parent
- 自定义事件
- 作用域插槽
- 父组件向子组件的子组件传数据,即向孙子组件传数据
$attrs
provider
&inject
- 任意组件间传数据
mitt
Pinia
开发环境
分类 | 名称 | 版本 |
---|---|---|
操作系统 | Windows | Windows 11 |
IDE | Visual Studio Code | 1.91.1 |
开发步骤及源码
1> 创建 Vue3 工程,参考:【Vue3】工程创建及目录说明。
2> 删除 src
目录下 assets
和 components
目录。
3> 修改 src
目录下 main.ts
。
import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')
4> 定义子组件,接收来自父组件的数据。
<template> <div class="content"> <h1>子组件</h1> <div class="blog" v-for="blog in blogs" :key="blog.id"> <div class="blog-title">标题:{{ blog.title }}</div> <div class="blog-author">作者:{{ author }}</div> <div class="blog-content">{{ blog.content }}</div> </div> </div> </template> <script setup lang="ts"> const data = defineProps(['author', 'blogs']) </script> <style scoped lang="scss"> .content { background-color: aquamarine; padding: 20px; .blog { border: 1px solid gray; border-radius: 5px; padding: 0 10px; margin-top: 5px; div { padding: 10px 5px; } .blog-title { font-weight: bold; } .blog-author { font-size: small; font-style: italic; } .blog-content { font-size: small; } } } </style>
注意:需要使用 defineProps
定义接收父组件的哪些 props
,如果这里没有定义,则即使父组件有传值,子组件也不能使用。defineProps
的参数是一个数组。
因为用到了 CSS 预处理器,所以需要执行 npm install -D sass
命令安装。
5> 修改 Vue 根组件 src/App.vue
,引用以上子组件并向其传值。
<template> <div class="parent"> <h1>父组件</h1> <h2>Blog数量:{{ blogs.length }}</h2> <Blog :blogs="blogs" :author="author" /> </div> </template> <script setup lang="ts"> import Blog from './components/Blog.vue' import { reactive, ref } from 'vue' const author = ref('Nick') const blogs = reactive([ { id: '001', title: '美国大选', content: '美国大选将于...' }, { id: '002', title: '奥运奖牌', content: '截止今日奥运奖牌榜...' }, { id: '003', title: '俄乌战争', content: '乌克兰单方面提出希望和谈...' }, { id: '004', title: '巴以冲突', content: '巴以冲突最新战况...' }, ]) </script> <style scoped lang="scss"> .parent { background-color: orange; padding: 20px; } </style>
可见,父组件向子组件传值只需在子组件标签上添加自定义属性(:blogs="blogs" :author="author"
)。
6> 执行命令 npm run dev
启动应用,浏览器访问:http://localhost:5173/
。
通过颜色可以辨别组件范围,可以看到子组件正确呈现出了来自父组件的数据。
7> 修改 Vue 根组件 src/App.vue
,实现父组件接收来自子组件的数据。
<template> <div class="parent"> <h1>父组件</h1> <h2>Blog数量:{{ blogs.length }}</h2> <h2>浏览数量:{{ readTimes }}</h2> <Blog :blogs="blogs" :author="author" :syncReadTimes="syncReadTimes" /> </div> </template> <script setup lang="ts"> import Blog from './components/Blog.vue' import { reactive, ref } from 'vue' const author = ref('Nick') const blogs = reactive([ { id: '001', title: '美国大选', content: '美国大选将于...' }, { id: '002', title: '奥运奖牌', content: '截止今日奥运奖牌榜...' }, { id: '003', title: '俄乌战争', content: '乌克兰单方面提出希望和谈...' }, { id: '004', title: '巴以冲突', content: '巴以冲突最新战况...' }, ]) const readTimes = ref(0) function syncReadTimes(value) { readTimes.value += value } </script> <style scoped lang="scss"> .parent { background-color: orange; padding: 20px; } </style>
可见,父组件定义了一个方法 syncReadTimes
,并将此方法作为子组件的自定义属性(:syncReadTimes="syncReadTimes"
)传入。
7> 修改子组件,实现向父组件传数据。
<template> <div class="content"> <h1>子组件</h1> <div class="blog" v-for="blog in blogs" :key="blog.id"> <div class="blog-title">标题:{{ blog.title }}</div> <div class="blog-author">作者:{{ author }}</div> <div class="blog-content">{{ blog.content }}</div> <button @click="syncReadTimes(1)">浏览量+1</button> </div> </div> </template> <script setup lang="ts"> const data = defineProps(['author', 'blogs', 'syncReadTimes']) </script> <style scoped lang="scss"> .content { background-color: aquamarine; padding: 20px; .blog { border: 1px solid gray; border-radius: 5px; padding: 0 10px; margin-top: 5px; div { padding: 10px 5px; } .blog-title { font-weight: bold; } .blog-author { font-size: small; font-style: italic; } .blog-content { font-size: small; } button { margin: 10px 0; } } } </style>
首先要在 defineProps
中定义接收来自父组件的 syncReadTimes
,然后增加一个按钮 <button>
,每点击一次便调用父组件的 syncReadTimes
并传入数据 1
。
8> 浏览器页面(http://localhost:5173/
)刷新后点击按钮,会发现父组件中的 浏览数量
显示随点击次数增加。
总结
Vue3 中 props
可以实现父组件与子组件间的双向数据通信:
- 子组件通过
defineProps
定义接收父组件的哪些数据; - 父组件将传给子组件的数据通过自定义属性添加到组件标签上;
- 父组件如果要接收来自子组件的数据,则定义一个方法,并将此方法作为自定义属性添加到组件标签上,子组件通过
defineProps
定义接收此方法引用,通过调用此方法向父组件传数据。