一、全局组件
在整个应用程序中都可以使用的组件,在main.ts文件中全局挂载
import { createApp } from 'vue'
// import './style.css'
import App from './App.vue'
import Card from './components/expame/Card.vue'
export const app = createApp(App)
// 全局组件
app.component('Card', Card)
app.mount('#app')
二、局部组件
局部组件是指在一个父组件中定义的组件。这些组件只在父组件内部使用,无法在其他组件中直接引用。局部组件通常用于封装和组织父组件内部的一部分功能和界面。
<template>
<div class="wml-box">
<div>
<Menu></Menu>
</div>
<div class="wml-box__right">
<Header></Header>
<Content></Content>
</div>
</div>
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
import Menu from './Menu/index.vue'
import Header from './Header/index.vue'
import Content from './Content/index.vue'
</script>
<style scoped lang="scss">
@include b(box) {
@include bfc;
display: flex;
@include e(right) {
display: flex;
flex-direction: column;
flex: 1;
}
}
</style>
三、异步组件
异步组件是一种用于延迟加载的组件。它们允许将组件的加载和渲染过程分为多个阶段,使得页面加载更快且更高效。异步组件通常会将组件的加载过程推迟到组件被实际渲染到页面上时才开始。
<template>
<div class="sync">
<div class="sync-content">
<div class="sync-img">
<img :src="data.url" alt="">
</div>
<div class="sync-pop">
<div>{{ data.name }}</div>
<div> {{ data.age }}</div>
</div>
</div>
<hr>
<div>{{ data.desc }}</div>
</div>
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
import { axios } from '@/server/axios'
interface Data {
data: {
url: string,
desc: string,
name: string,
age: number,
}
}
const { data } = await axios.get<Data>('./data.json')
</script>
<style scoped lang="less">
.sync {
width: 100%;
background-color: #f1f1f1;
padding: 20px;
}
.sync-content {
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 5px;
}
.sync-pop {
display: flex;
margin-left: 15px
}
.sync-img img {
width: 50px;
height: 50px;
border-radius: 50%;
}
</style>
<!-- APP.vue -->
<template>
<!-- 展示异步组件必须使用suspense -->
<Suspense>
<template #default>
<SyncVue></SyncVue>
</template>
<!-- 延迟时加载
<suspense> 组件有两个插槽。它们都只接收一个直接子节点。default 插槽里的节点会尽可能展示出来。如果不能,则展示 fallback 插槽里的节点。
-->
<template #fallback>
<skeletonVue></skeletonVue>
</template>
</Suspense>
<!-- <SyncVue></SyncVue> -->
</template>
<script setup lang='ts'>
import { ref, reactive, defineAsyncComponent } from 'vue'
import skeletonVue from './components/skeleton/Skeleton.vue'
// const SyncVue = defineAsyncComponent(() => import('@/components/skeleton/Sync.vue')); //函数模式
const SyncVue = defineAsyncComponent({
loader: () => import('@/components/skeleton/Sync.vue'),
// loadingComponent: skeletonVue,
// delay: 200
}); //对象模式
</script>
<style scoped></style>
<!-- 代码分包:使用异步组件的时候会打包成两个js -->
四、动态组件
动态组件是指可以动态添加、删除或修改的组件。它们具有以下特点:
1、可以根据特定条件或用户输入来创建、显示或隐藏组件。
2、可以在运行时修改组件的属性、样式或行为。
3、可以动态地添加、删除或移动组件。
4、可以根据数据或事件来更新组件的内容。
<!-- 动态组件 (tab切换)-->
<template>
<div style="display: flex;">
<div :class="[active == index ? 'active' : '']" v-for="(item, index) in data" @click="switchCom(item, index)"
class="tabs">
<div>{{ item.name }}</div>
</div>
</div>
<component :is="comId"></component>
</template>
<style scoped lang="less">
.tabs {
border: 1px solid #ccc;
padding: 5px 10px;
margin: 5px
}
.active {
background-color: aquamarine;
}
</style>
<!-- 第一种方式 compostions API-->
<script lang="ts" setup>
import { shallowRef, ref, markRaw, reactive } from "vue";
import A from '../tab/A.vue'
import B from '../tab/B.vue'
const comId = shallowRef(A)
const active = ref(0)
const data = reactive([
{
name: 'A组件',
com: markRaw(A)
},
{
name: 'B组件',
com: markRaw(B)
},
])
const switchCom = (item, index) => {
comId.value = item.com
active.value = index
}
</script>
<!-- 第二种方式 options API-->
<!-- <script lang="ts" setup>
import { shallowRef, ref, markRaw, reactive } from "vue";
const comId = shallowRef('A')
const active = ref(0)
const data = reactive([
{
name: 'A组件',
com: 'A'
},
{
name: 'B组件',
com: 'B'
},
])
const switchCom = (item, index) => {
comId.value = item.com
active.value = index
}
</script>
<script lang="ts">
import A from './components/tab/A.vue'
import B from './components/tab/B.vue'
export default {
components: {
A,
B
},
}
</script> -->
五、递归组件
递归组件是指在组件内部使用相同类型的组件来构建自身的一种组件设计方式。通常来说,递归组件会定义一个基本的组件,然后在组件内部使用相同的组件来构建更复杂的结构。
更改组件名方法:
1、vue3新语法默认Tree可为递归组件组件名
2、再写一个script
<script lang="ts">
export default {
name: 'h'
}
</script>
3、插件 unplugin-vue-define-options
defineOptions({
name: 'h'
})
<template>
<div v-for="item in dataList" class="tree" @click.stop="clickTap(item, $event)">
<input type="checkbox" v-model="item.checked"><span>{{ item.name }}</span>
//递归组件
<Tree v-if="item?.children?.length" :dataList="item?.children"></Tree>
</div>
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
interface Tree {
name: string,
checked?: boolean,
children?: Tree[]
};
defineProps<{
dataList?: Tree[]
}>()
const clickTap = (item: Tree, e: any) => {
console.log(item, e.target);
}
</script>
<style scoped>
.tree {
margin-left: 10px;
}
</style>
<!-- 父组件 -->
<!-- <template>
<div>
<TreeVue :dataList="data"></TreeVue>
</div>
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
import TreeVue from './components/expame/Tree.vue'
interface Tree {
name: string;
checked?: boolean;
children?: Tree[];
};
const data = reactive<Tree[]>([
{
name: "no.1",
checked: false,
children: [
{
name: "no.1-1",
children: [
{
name: "no.1-1-1",
},
],
},
],
},
{
name: "no.2",
checked: false,
children: [
{
name: "no.2-1",
},
],
},
{
name: "no.3",
checked: false
},
]);
</script>
<style></style> -->