vue3 插槽slot

和 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 :是否拖拽。通过变量的赋值truefalse 来控制是否显示左侧布局,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>

这里有个不好的点就是命名:自定义组件命名最好不要用leftrighttopbottom。一旦布局改掉就会被局限住了,left不是leftright不是right的时候就尴尬住了,最好的方式就是以该模块的作用,功能等命名。

猜你喜欢

转载自blog.csdn.net/xixihahakkyy/article/details/124943100