13、Vue 3 (2024 版)基础笔记 - 组件 & 组件间数据传递
组件是对功能的拆分与复用。
关于组件,我们一直在使用,现在就来了解它吧。
1,组件的基础使用
1、创建组件
头部组件
src/components/comp/HeaderComp.vue
<template>
<header>
<h3>头部</h3>
</header>
</template>
<script setup lang="ts">
</script>
<style scoped>
* {
margin: 0;
padding: 0;
}
header {
display: flex;
justify-content: center;
align-items: center;
padding: 10px 0;
background: black;
color: white;
border-radius: 10px;
width: 100%;
height: 32px;
}
</style>
主体部分
src/components/comp/MainComp.vue
<template>
<main>
<h3>主体部分</h3>
</main>
</template>
<script setup lang="ts">
</script>
<style scoped>
main {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
margin-top: 10px;
background: lightblue;
width: 100%;
height: 100%;
border-radius: 10px;
}
</style>
2、使用组件
src/App.vue
<template>
<!-- 2、使用组件 -->
<HeaderComp/>
<MainComp/>
</template>
<script setup lang="ts">
// 1、引入组件
import HeaderComp from "@/components/comp/HeaderComp.vue";
import MainComp from "@/components/comp/MainComp.vue";
</script>
3、浏览查看效果
http://localhost:5173/
打开你的地址就可以看到效果了。
这就是组件的基础使用。
2,嵌套组件
组件的基础使用
这个案例中,其实就已经在使用组件嵌套了。在 root
节点(也就是 App.vue
) 中嵌套了 HeaderComp
和 MainComp
这两个组件。
接下来就更深层次嵌套,在 MainComp
组件中嵌套组件。
1、创建组件
src/components/comp/article/ArticleComp.vue
<template>
<article>
<h3>文章组件</h3>
</article>
</template>
<script setup lang="ts">
</script>
<style scoped>
article {
margin-bottom: 5px;
width: 100%;
text-align: center;
color: white;
background: lightsteelblue;
}
</style>
2、使用组件
src/components/comp/MainComp.vue
<template>
<main>
<h3>主体部分</h3>
<ArticleComp/>
<ArticleComp/>
<ArticleComp/>
</main>
</template>
<script setup lang="ts">
import ArticleComp from "@/components/comp/article/ArticleComp.vue";
</script>
<!-- ... 表示代码省略 -->
<style scoped>
...
</style>
3,全局组件
在上面的这些案例中,我们使用的都是局部组件。这里,我们学习一下全局组件的使用。
全局组件即一旦注册,在任何地方都可以直接
调用。
1、创建组件
src/components/comp/FooterComp.vue
<template>
<footer>
<h3>底部区域</h3>
</footer>
</template>
<script setup lang="ts">
</script>
<style scoped>
footer {
display: flex;
justify-content: center;
margin-top: 5px;
background: black;
color: white;
border-radius: 10px;
}
</style>
2、注册全局组件
src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
// 1、引入全局组件
import FooterComp from "@/components/comp/FooterComp.vue";
const app = createApp(App)
// 2、注册全局组件
app.component('FooterComp', FooterComp)
app.mount('#app')
3、使用全局组件
src/App.vue
<template>
<HeaderComp/>
<MainComp/>
<!-- 3、使用全局组件 -->
<FooterComp/>
</template>
<script setup lang="ts">
import HeaderComp from "@/components/comp/HeaderComp.vue";
import MainComp from "@/components/comp/MainComp.vue";
</script>
需要注意,我们没有在 App.vue
中引入 FooterComp
组件,而直接调用,因为它是全局组件了。
4,Props 组件间数据传递
在进行数据传递之前,我们先来梳理下目前文件之间的层级嵌套关系。
├── App.vue
├──── HeaderComp
├──── MainComp
│ ├── ArticleComp
├──── FooterComp
在 <script setup>
语法中,子组件接收父组件的数据使用 defineProps
。
4.1,传递静态数据
我们使用 App
和 FooterComp
进行静态数据传递的演示。App.vue
为父组件,FooterComp
为子组件,现在,演示 App
向 FooterComp
传递数据。
1、父组件向子组件传递数据
src/App.vue
<template>
<HeaderComp/>
<MainComp/>
<!-- 使用自定义属性向子组件传递静态数据 -->
<FooterComp title="Copyright © 2024 自如初" description="我的世界真奇妙"/>
</template>
<script setup lang="ts">
import HeaderComp from "@/components/comp/HeaderComp.vue";
import MainComp from "@/components/comp/MainComp.vue";
</script>
2、子组件使用 defineProps 接收数据
src/components/comp/FooterComp.vue
<template>
<footer>
<h3>底部区域</h3>
<div>
<!-- 使用数据 -->
<p>{{ title }}</p>
<p>{{ description }}</p>
</div>
</footer>
</template>
<script setup lang="ts">
// 接收父组件传递的数据
defineProps(['title', 'description'])
</script>
<style scoped>
/* 注意:样式有变化 */
footer {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 5px;
padding: 10px 0;
background: black;
color: white;
border-radius: 10px;
}
</style>
4.2,传递动态数据
会了静态传递数据,那么动态传递数据也就容易多了。我们基于静态传递数据的案例进行改造。
1、父组件传递动态数据给子组件
src/App.vue
<template>
<HeaderComp/>
<MainComp/>
<FooterComp
title="Copyright © 2024 自如初"
description="我的世界真奇妙"
:name="name"
:age="age"
/>
</template>
<script setup lang="ts">
import HeaderComp from "@/components/comp/HeaderComp.vue";
import MainComp from "@/components/comp/MainComp.vue";
// 定义动态数据
const name = "王美丽,"
const age = '19 岁啦'
</script>
2、子组件接收数据
src/components/comp/FooterComp.vue
<template>
<footer>
<h3>底部区域</h3>
<div>
<!-- 使用数据 -->
<p>{{ title }}</p>
<p>{{ description }}</p>
<p>{{name}} {{ age}}</p>
</div>
</footer>
</template>
<script setup lang="ts">
// 接收父组件传递的数据
defineProps(['title', 'description', 'name', 'age'])
</script>
...
4.3,组件传递多种数据类型
对于基本数据类型,我们新建一个组件来演示。对于数组和对象,我们还是回归到 MainComp
组件中。
准备工作
1、创建组件
src/components/PropComp.vue
<template></template>
<script setup lang="ts"></script>
2、使用组件
src/App.vue
<template>
...
<PropComp/>
</template>
<script setup lang="ts">
...
import PropComp from "@/components/PropComp.vue";
...
</script>
传递基本数据类型:Number,Boolean
1、父组件传递基础类型数据给子组件
src/App.vue
<template>
...
<PropComp :number="number" :bool="bool"/>
</template>
<script setup lang="ts">
...
// 传递 Number、Boolean
const number = 10
const bool = true
</script>
2、子组件接收数据
src/components/PropComp.vue
<template>
<div>
<h4>演示传递 Number & Boolean</h4>
<p>{{ number }}</p>
<p>{{ bool }}</p>
</div>
</template>
<script setup lang="ts">
const props = defineProps(['number', 'bool'])
</script>
传递数组
给子组件
注意:文件发生了变化。
1、父组件传递数组数据给子组件
src/components/comp/MainComp.vue
<template>
<main>
<h3>主体部分</h3>
<!-- 传递对象给子组件 -->
<ArticleComp
v-for="article in articles" :key="article.id"
:article="article"
/>
</main>
</template>
<script setup lang="ts">
import ArticleComp from "@/components/comp/article/ArticleComp.vue";
// 从服务端请求的数据
const articles = [
{id:1, title:"坚持的意义是什么?"},
{id:2, title:"什么是放下?"}
];
</script>
...
2、子组件接收数据
src/components/comp/article/ArticleComp.vue
<template>
<article>
<h3>文章组件</h3>
<div>
<p>{{ article.id }}:{{ article.title }}</p>
</div>
</article>
</template>
<script setup lang="ts">
const props = defineProps(['article'])
</script>
...
传递对象
给子组件
1、父组件传递对象数据
src/components/comp/MainComp.vue
<template>
<main>
<h3>主体部分</h3>
<!-- 传递对象给子组件 -->
<ArticleComp
v-for="article in articles" :key="article.id"
:article="article"
:userinfo="userinfo"
/>
</main>
</template>
<script setup lang="ts">
...
const userinfo = {
name:"王丽丽",
age:19
}
</script>
...
2、子组件接收数据
src/components/comp/article/ArticleComp.vue
<template>
<article>
<h3>文章组件</h3>
<div>
<!-- 数组数据 -->
<p>{{ article.id }}:{{ article.title }}</p>
<!-- 对象数据 -->
<p>{{ userinfo.name }} {{ userinfo.age }}</p>
</div>
</article>
</template>
<script setup lang="ts">
const props = defineProps(['article', 'userinfo'])
</script>
...
4.4,Props 数据校验
1、修改组件
src/App.vue
<template>
<PropComp :number="number" :bool="bool" :username="username" :users="users"/>
</template>
<script setup lang="ts">
import PropComp from "@/components/PropComp.vue";
// 传递 Number、Boolean
const number = 10
const bool = true
const username = "王丽丽"
const users = ["小丽", "小美"]
</script>
2、接收数据
src/components/PropComp.vue
<template>
<div>
<h4>演示传递 Number & Boolean</h4>
<p>{{ number }}</p>
<p>{{ bool }}</p>
<p>{{ username }}</p>
<ul>
<li v-for="(user, index) in users" :key="index">{{ user }}</li>
</ul>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
// number 必须是数字类型且为必填
number:{
type:Number,
required:true
},
// bool 必须是 boolean 类型
bool:{
type:Boolean
},
// 既可以是 string 也可以是 number,且有默认值
username:{
type:[String, Number],
default:"王美美"
},
users: {
type:Array,
default() {
return ["小新"]
}
}
})
</script>