目录
配置全局组件
例如组件使用频率非常高(table,Input,button,等)这些组件 几乎每个页面都在使用便可以封装成全局组件
mian.ts中
import { createApp } from 'vue'
import App from './App.vue'
import Card from "./components/Card.vue";
createApp(App).component("Card",Card).mount('#app')
要放到mount的前面
使用时
<Card></Card>即可
配置局部组件
就是在一个组件内(A) 通过import 去引入别的组件(B) 称之为局部组件
应为B组件只能在A组件内使用 所以是局部组件
如果C组件想用B组件 就需要C组件也手动import 引入 B 组件
案例,在递归组件内有提到
配置递归组件
也就是在template里面有引用了一便自己,和js的递归差不多
案例
子组件
<script setup lang="ts">
type TreeData = {
name: string;
active: boolean;
children?: TreeData[];
}
defineProps<{
data: TreeData[]
}>()
const handleClick = (item: TreeData) => {
console.log(item)
}
</script>
<template>
<div
@click.stop="handleClick"
v-for="item in data" :key="item.name"
style="margin-left: 10px;">
<input type="checkbox" v-model="item.active" />
<span>{{ item.name }}</span>
<BaseRefAndReactive v-if="item?.children?.length" :data="item.children" />
</div>
</template>
<style scoped>
</style>
如果想换一个名字,可以再写一个script标签
<script lang="ts"> export default { name: 'Base' } </script>
这样就可以使用Base这个组件名来进行递归了
父组件
<script setup lang="ts">
import BaseRefAndReactive from "./components/BaseRefAndReactive.vue";
import {ref} from "vue";
type TreeData = {
name: string;
active: boolean;
children?: TreeData[];
}
const treeData = ref<TreeData[]>([
{
name: "Node 1",
active: false,
children: [
{
name: "Node 1-1",
active: false,
children: [
{
name: "Node 1-1-1",
active: false,
},
{
name: "Node 1-1-2",
active: false,
},
],
},
{
name: "Node 1-2",
active: false,
},
],
},
{
name: "Node 2",
active: false,
children:[]
}
])
</script>
<template>
<Card></Card>
<BaseRefAndReactive :data="treeData"></BaseRefAndReactive>
</template>
<style scoped>
</style>
动态组件
让多个组件使用同一个挂载点,并动态切换,这就是动态组件。
在挂载点使用component标签,然后使用v-bind:is=”组件”
案例:写一个tab,有三个按钮点击不同的按钮,切换不同的组件
<script setup lang="ts">
import A from "./components/A.vue";
import B from "./components/B.vue";
import Card from "./components/Card.vue";
import {ref,reactive} from "vue";
const comData = reactive([
{
name:"A",
com: A
},
{
name:"B",
com: B
},
{
name:"C",
com: Card
}
])
const com = ref(comData[0].com)
const active = ref(0)
function changeView(index:number){
active.value = index
com.value = comData[index].com
}
</script>
<template>
<div class="container">
<div
v-for="(item,index) in comData" :key="index"
:class="{'active':active === index}"
@click="changeView(index)">
{{item.name}}
</div>
</div>
<component :is="com"></component>
</template>
<style scoped>
.container {
width: 500px;
display: flex;
justify-content: center;
margin: 0 auto;
}
.container div {
margin: 10px;
cursor: pointer;
width: 100px;
height: 30px;
line-height: 30px;
border: 1px solid grey;
text-align: center;
}
.active {
background-color: skyblue;
color: white;
}
</style>
这样的话我们就完成了动态组件,但是这样写的会有一些警告
原因是:我们将组件放到了reactive和ref中对他进行了响应式包装,造成了一些性能浪费我们可以进行修改推荐我们使用shallowRef 或者 markRaw 跳过proxy 代理
如下:
<script setup lang="ts">
import A from "./components/A.vue";
import B from "./components/B.vue";
import Card from "./components/Card.vue";
import {shallowRef,ref,reactive,markRaw} from "vue";
const comData = reactive([
{
name:"A",
com: markRaw(A)
},
{
name:"B",
com: markRaw(B)
},
{
name:"C",
com: markRaw(Card)
}
])
const com = shallowRef(comData[0].com)
const active = ref(0)
function changeView(index:number){
active.value = index
com.value = comData[index].com
}
</script>
<template>
<div class="container">
<div
v-for="(item,index) in comData" :key="index"
:class="{'active':active === index}"
@click="changeView(index)">
{{item.name}}
</div>
</div>
<component :is="com"></component>
</template>
<style scoped>
.container {
width: 500px;
display: flex;
justify-content: center;
margin: 0 auto;
}
.container div {
margin: 10px;
cursor: pointer;
width: 100px;
height: 30px;
line-height: 30px;
border: 1px solid grey;
text-align: center;
}
.active {
background-color: skyblue;
color: white;
}
</style>
这样就没有警告了
插槽Sort
插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。
匿名插槽
父组件内 <A> <template v-slot:default> <p>default slot</p> </template> </A>
子组件内
<div class="body"> <slot></slot> </div>
不需要名字的插槽
具名插槽
具名插槽其实就是给插槽取个名字。一个子组件可以放多个插槽,而且可以放在不同的地方,而父组件填充内容时,可以根据这个名字把内容填充到对应插槽中
<div class="header"> <slot name="header"></slot> </div>
有名字,父组件就可以通过名字精准插入
<template v-slot:header> <p>header slot</p> </template>
也可以对插槽进行简写,将v-solt: 用#替换即可
作用域插槽
在子组件动态绑定参数 派发给父组件的slot去使用
案例:
A组件
<script setup lang="ts">
import {ref} from "vue";
const dataRef = ref([1,23,4,4,1])
</script>
<template>
<div class="container">
<div class="header">
<slot name="header"></slot>
</div>
<div class="body">
<slot></slot>
</div>
<div>
<slot name="footer" :data="dataRef"></slot>
</div>
</div>
</template>
<style scoped>
.container {
width: 500px;
height: 500px;
background-color: #ccc;
border: 1px solid grey;
margin: 0 auto;
}
.header {
height: 50px;
background-color: #eee;
border: 1px solid grey;
}
.body {
height: 400px;
background-color: #ddd;
border: 1px solid grey;
}
.footer {
height: 50px;
background-color: #eee;
border: 1px solid grey;
}
</style>
父组件
<script setup lang="ts">
import A from "./components/A.vue";
</script>
<template>
<A>
<template v-slot:header>
<p>header slot</p>
</template>
<template v-slot:default>
<p>default slot</p>
</template>
<template #footer="{data}">
{{data}}
</template>
</A>
</template>
<style scoped>
</style>
动态插槽
可以动态的去指定插槽的名字
案例:
<script setup lang="ts">
import A from "./components/A.vue";
import {ref} from "vue";
const slotSelect = ref("header");
const change = () => {
slotSelect.value = "default";
}
</script>
<template>
<A>
<template #[slotSelect]>
<p>header slot</p>
</template>
<template #footer="{data}">
{{data}}
</template>
</A>
<button @click="change">点我切换</button>
</template>
<style scoped>
</style>