和 vue2 不同便是,原来的 slot 属性可以定义在任何元素上,现在 v-slot
只能是 template 元素
上。
默认插槽
// 父组件:
<template>
<children>
<template v-slot:default>
<div>父组件内容</div>
</template>
</children>
</template>
// children子组件:
<template>
<div>
<slot></slot> // 默认插槽
<div>我是子组件内容</div>
</div>
</template>
具名插槽
// 父组件:
<template>
<children>
<template v-slot:header>
<div>父组件header内容</div>
</template>
<template v-slot:default>
<div>父组件内容</div>
</template>
<template v-slot:footer>
<div>父组件footer内容</div>
</template>
</children>
</template>
// children子组件:
<template>
<div>
<slot name="header"></slot> //这种就叫具名插槽
<slot></slot> // 默认插槽
<slot name="footer"></slot>
<div>我是子组件内容</div>
</div>
</template>
作用域插槽
// 父组件:
<template>
<children>
<div v-slot:header="{ row }">{
{
row.name }}</div>
</children>
</template>
// children子组件:
<template>
<div>
<slot name="header" :row="row"></slot> // 默认插槽
<div>我是子组件内容</div>
</div>
</template>
<script setup lang="ts">
const row = reactive({
id: 1,
name: 'kk',
boss: 'pitt'
})
</script>
动态插槽
<children>
<template #[name]>
<div>
23
</div>
</template>
</children>
...
const name = ref('header')
插槽简写
默认插槽:简写成#default
具名插槽:例如v-slot:footer
可以简写成#footer
<template>
<children>
<template #header>
<div>父组件header内容</div>
</template>
<template #default>
<div>父组件内容</div>
</template>
<template #footer>
<div>父组件footer内容</div>
</template>
</children>
</template>
判断是否使用了自定义组件的插槽
下例是一个container
的页面布局,效果如下:
<template>
<div class="container">
<div :class="['leftContainer', dragSizeStatus ? '' : 'leftContainer__resize']" v-if="showLeftContainer">
<slot name="left"></slot>
</div>
<div class="rightContainer">
<div class="user_search" v-if="showSearchContainer">
<slot name="search" />
</div>
<slot name="list" />
</div>
</div>
</template>
<script setup lang="ts">
let props = defineProps({
showLeftContainer:{
type:Boolean,
default:true
},
showSearchContainer:{
type:Boolean,
default:true
},
dragSizeStatus:{
type:Boolean,
default:true
}
})
</script>
<style lang="scss" scoped>
// 样式省略.....
</style>
上例组件接收三个参数:showLeftContainer
:是否显示左侧布局(常用tree组件和导航) , showSearchContainer
:是否显示search模块, dragSizeStatus
:是否拖拽。通过变量的赋值true
或 false
来控制是否显示左侧布局,search布局。
假如我们的需求很简单:就是有插槽的时候显示这部分的布局,反正则隐藏,有没有更快捷方式呢?
vue3
提供了useSlot
。当你没有使用具名插槽为left
的插槽时,slots.left
为空。
<template>
<div class="container">
<div :class="['leftContainer', dragSizeStatus ? '' : 'leftContainer__resize']" v-if="slots.left">
<slot name="left"></slot>
</div>
<div class="rightContainer">
<div class="user_search" v-if="slots.search">
<slot name="search" />
</div>
<slot name="list" />
</div>
</div>
</template>
<script setup lang="ts">
import {
useSlots } from 'vue';
const slots = useSlots()
let props = defineProps({
dragSizeStatus: {
type:Boolean,
default:true
}
})
</script>
这里有个不好的点就是命名
:自定义组件命名最好不要用left
、right
、top
、bottom
。一旦布局改掉就会被局限住了,left
不是left
,right
不是right
的时候就尴尬住了,最好的方式就是以该模块的作用,功能等命名。