返回 导航

Vue.js

hangge.com

Vue.js - 插槽slot的使用详解(默认内容、具名插槽、动态插槽名、作用域)

作者:hangge | 2026-04-02 08:37
    在 Vue.js 中,插槽(Slot)是一种非常灵活、强大的组件内容分发机制。它允许父组件向子组件传递模板结构,而不是普通的数据,从而大大增强了组件的可扩展性与复用性。本文将从基础插槽开始,通过样例逐步讲解具名插槽、作用域插槽、动态插槽,帮助大家掌握插槽的使用。

1,插槽的基本使用

(1)首先我们创建一个 MySlotCompnent.vue 组件,负责定义插槽,代码如下。可以看到,我们在该组件中添加了一个 <slot>,可在该 <slot> 中放入需要显示的内容,即让使用者决定显示的内容。 
提示<slot></slot> <slot name="default></slot> 的简写。 
<template>
    <div class="my-component">
        <div>我是头部</div>
        <!--中间显示的内容用slot占位,因为内容是不确定的-->
        <slot></slot>
        <div>我是尾部</div>
    </div>
</template>

<script>
export default {
    name: 'MyComponent',
}
</script>

<style scoped>
.my-component {
    border: solid 1px gray;
    padding: 5px;
}
</style>

(2)然后我们可以使用 MySlotCompnent.vue 组件及其插槽,这里为 MySlotCpn.vue 组件的插槽插入了不同的内容。
<template>
    <div class="my-component">
        <!-- 1.默认没有插入内容 -->
        <my-slot-compnent></my-slot-compnent>
        <!-- 2.插入一个文本 -->
        <my-slot-compnent>
            欢迎访问hangge.com
        </my-slot-compnent>
        <!-- 3.插入一个元素 -->
        <my-slot-compnent>
            <button>我是按钮</button>
        </my-slot-compnent>
        <!-- 4.插入多个内容 -->
        <my-slot-compnent>
            <div>我是div</div>
            <button>按钮1</button>
            <button>按钮2</button>
        </my-slot-compnent>
    </div>
</template>

<script>
import MySlotCompnent from './MySlotCompnent.vue';
export default {
    name: 'MyComponent',
    components: {
        MySlotCompnent
    }
}
</script>

(3)运行效果如下,可以看到 MySlotCompnent.vue 组件中间的内容都是由使用者决定的。

2,插槽的默认内容

(1)在使用插槽的情况下,当没有提供插入的内容时,如果希望显示默认内容,那么这个默认内容只在没有提供插入内容的情况下才会显示。修改 MySlotCompnent.vue 组件,在插槽中添加默认内容,代码如下所示:
<template>
    <div class="my-component">
        <div>我是头部</div>
        <!--中间显示的内容用slot占位,因为内容是不确定的-->
        <slot>
            这个是插槽的默认内容,只在没有提供插入的内容时,才会显示
        </slot>
        <div>我是尾部</div>
    </div>
</template>

<script>
export default {
    name: 'MyComponent',
}
</script>

<style scoped>
.my-component {
    border: solid 1px gray;
    padding: 5px;
    margin: 10px;
}
</style>

(2)当我们使用 MySlotCompnent.vue 组件时,如果没有插入对应的内容,那么会显示插槽中的默认内容。

3,具名插槽的使用

(1)一个组件中可以存在多个插槽,如果我们希望这些插槽分别显示不同的内容,那么可以使用具名插槽,即为插槽起一个名字。
提示<slot> 元素有一个特殊的 name 属性, 而不带有 name 属性的插槽也会带有隐含的 name="default"。 

(2)我们创建一个 MySlotCompnent.vue 组件,里面有三个插槽,并且分别为插槽添加 name 属性。
<template>
    <div class="nav-bar">
        <div class="left">
            <slot name="left"></slot><!--1.为插槽起一个left名字-->
        </div>
        <div class="center">
            <slot name="center"></slot><!--2.为插槽起一个center名字-->
        </div>
        <div class="right">
            <slot name="right"></slot><!--3.为插槽起一个right名字-->
        </div>
    </div>
</template>
<script>
export default {
    name: 'MyComponent',
}
</script>

<style scoped>
.nav-bar {
    border: solid 1px gray;
    padding: 5px;
    display: flex;
}

.center {
    flex: 1;
    text-align: center;
    align-items: center;
}
</style>

(3)在为 MySlotCompnent.vue 组件具名插槽提供内容时,需要将提供的内容编写到对应的 <template> 元素中。接着,在 <template> 元素上使用 v-slot 指令,并通过冒号语法将目标插槽的名字传递给该指令。 
<template>
    <div class="my-component">
        <my-slot-compnent>
            <template v-slot:left>
                <button class="btn">左边的按钮</button>
            </template>
            <template v-slot:center>
                <h1>中间的标题</h1>
            </template>
            <template v-slot:right>
                <button class="btn">右边的按钮</button>
            </template>
        </my-slot-compnent>
    </div>
</template>

<script>
import MySlotCompnent from './MySlotCompnent.vue';
export default {
    name: 'MyComponent',
    components: {
        MySlotCompnent
    }
}
</script>

<style scoped>
.my-component {
    padding: 10px;
}
</style>
<template>
    <div class="my-component">
        <my-slot-compnent>
            <template #left>
                <button class="btn">左边的按钮</button>
            </template>
            <template #center>
                <h1>中间的标题</h1>
            </template>
            <template #right>
                <button class="btn">右边的按钮</button>
            </template>
        </my-slot-compnent>
    </div>
</template>

<script>
import MySlotCompnent from './MySlotCompnent.vue';
export default {
    name: 'MyComponent',
    components: {
        MySlotCompnent
    }
}
</script>

<style scoped>
.my-component {
    padding: 10px;
}
</style>

(4)运行结果如下:

4,动态插槽名的使用

(1)上述我们使用的插槽名称都是固定的,例如 v-slot:leftv-slot:center 等。其实,我们还可以通过 v-slot:[dynamicSlotName] 方式动态绑定一个插槽的名称。 

(2)下面修改 MySlotCompnent 组件,使左边布局插槽的名称来自 props 中的 name 属性。
<template>
    <div class="nav-bar">
        <div class="left">
            <slot :name="name"></slot><!--动态添加插槽的名称,由外部使用者决定-->
        </div>
        <div class="center">
            <slot name="center"></slot><!--2.为插槽起一个center名字-->
        </div>
        <div class="right">
            <slot name="right"></slot><!--3.为插槽起一个right名字-->
        </div>
    </div>
</template>
<script>
export default {
    name: 'MyComponent',
    props: {
        name: String // 接收插槽的名称
    }
}
</script>

<style scoped>
.nav-bar {
    border: solid 1px gray;
    padding: 5px;
    display: flex;
}

.center {
    flex: 1;
    text-align: center;
    align-items: center;
}
</style>

(3)在使用 MySlotCompnent.vue 组件时,首先为该组件传递了 data 中定义 name 变量(作为插槽的名称),接着在为 MySlotCompnent.vue 组件左边插槽提供内容时,传给 v-slot 指令的目标插槽名称也是动态绑定的 name 变量。
<template>
    <div class="my-component">
        <my-slot-compnent :name="name"> <!-- 传递插槽名称给MySlotCompnent.vue组件-->
            <template v-slot:[name]>
                <button class="btn">左边的按钮</button>
            </template>
            <template #center>
                <h1>中间的标题</h1>
            </template>
            <template #right>
                <button class="btn">右边的按钮</button>
            </template>
        </my-slot-compnent>
    </div>
</template>

<script>
import MySlotCompnent from './MySlotCompnent.vue';
export default {
    name: 'MyComponent',
    components: {
        MySlotCompnent
    },
    data() {
        return {
            name: 'hangge' // 传递插槽名称
        }
    },
}
</script>
<template>
    <div class="my-component">
        <my-slot-compnent :name="name"> <!-- 传递插槽名称给MySlotCompnent.vue组件-->
            <template #[name]>
                <button class="btn">左边的按钮</button>
            </template>
            <template #center>
                <h1>中间的标题</h1>
            </template>
            <template #right>
                <button class="btn">右边的按钮</button>
            </template>
        </my-slot-compnent>
    </div>
</template>

<script>
import MySlotCompnent from './MySlotCompnent.vue';
export default {
    name: 'MyComponent',
    components: {
        MySlotCompnent
    },
    data() {
        return {
            name: 'hangge' // 传递插槽名称
        }
    },
}
</script>

<style scoped>
.my-component {
    padding: 10px;
}
</style>

(4)保存代码后,页面依然可以正常显示。

5,作用域插槽

(1)由于组件存在渲染作用域,每个组件只能访问自己作用域中的内容,但有时我们希望插槽可以访问子组件中的内容。这种情况在实际开发中使用得非常多,也非常重要。这时,可以使用 Vue.js 提供的作用域插槽。
  • 例如,当一个组件被用于渲染一个数组元素时,我们在使用插槽的同时,希望能够在插槽中自定义每项内容。

(2)我们这里创建一个名为 ShowNames.vue 的组件,代码如下。首先该组件接收 names 属性,接着在 template 中使用 v-for 指令遍历 names 数组,数组中每项显示的内容使用插槽占位,让使用者决定显示的内容。然后将遍历数组的 itemindex 绑定到插槽的属性上,目的是让使用该插槽的人可以通过带值的 v-slot 指令获取插槽提供的属性,如 itemindex。 
提示:我们可以为插槽添加任意数量的属性。另外,在插槽中定义的属性称为插槽的属性(slot prop)
<template>
    <div class="show-names">
        <template v-for="(item, index) in names">
            <!-- 为插槽添加item和index属性,并绑定item和index数据。item和index称为slot prop -->
            <slot :item="item" :index="index"></slot>
        </template>
    </div>
</template>
<script>
export default {
    props: {
        names: {
            type: Array,
            default: () => []
        }
    }
}  
</script>

(3)接着我们使用该组件。首先向 ShowNames.vue 组件传递 names 属性,接着在 ShowNames.vue 组件中的 <template> 元素上使用 v-slot:default 指令,即使用默认插槽。然后在 v-slot:default 指令等号(=)后,直接接收一个 slot props 对象(如 slotProps,该名称支持自定义)。最后,通过 slotProps 获取 ShowNames.vue 组件为插槽绑定的 itemindex 数据。 
<template>
    <div class="app">
        <show-names :names="names">
            <!-- v-slot:default后面的值slotProps是插槽属性的集合。其中,slotProps可任意命名 -->
            <template v-slot:default="slotProps">
                <span class="name">{{ slotProps.item }} - {{ slotProps.index }}</span>
            </template>
        </show-names>
    </div>
</template>
<script>
import ShowNames from './ShowNames.vue';
export default {
    name: 'BlankView',
    components: {
        ShowNames
    },
    data() {
        return {
            names: ["hangge", "baidu", "google"]
        }
    }
}
</script>
<style scoped>
.name {
    border: solid 1px gray;
    padding: 5px;
    margin: 5px;
}
</style>

(4)最终运行效果如下:
评论

全部评论(0)

回到顶部