Vue快速上手:七、插槽

上一章讲了组件将JS中的状态值传其它组件,但是如果是需要传模板内容(HTML代码)传给子组件来达到灵活使用组件的功能, 要实现这一功能就不得不说一下插槽了。

基本使用

使用方法:

  • 父组件直接在子组件标签写模板内容,类似在HTML中嵌套HTML代码一样。
  • 在子组件使用输出。

如:

子组件:

xml 复制代码
<script setup>
    const props = defineProps({
        v: String
    })
</script>

<template>
    <div class="form-input-box">
        <div class="form-input-lable">
            <slot></slot> <!-- 在引输入父组件的插槽内容 -->
        </div>
        <div class="form-input">
            <input type="text" v-model="props.v">
        </div>
    </div>
</template>

<style scoped>
    .form-input-box {
        margin: 20px 0 0;
        width: 500px;
        background-color: aquamarine;
    }
    .form-input-lable {
        display: flex;
        justify-content: space-between;
    }
    input {
        width: 100%;
    }
</style>

父组件:

xml 复制代码
<script setup>
    import { reactive } from "vue";
    import MyInput from "@/components/MyInput.vue";

    // 声明响应式状态数据
    const data = reactive({
        name: "",
        xx: "",
        love: ""
    })
</script>

<template>

    <!--  input1  -->
    <MyInput :v="data.name"> <!-- 组件标签内部嵌套的部分就是插槽内容 -->
        <label>姓名</label>
    </MyInput>

    <!-- input2 -->
    <MyInput :v="data.xx"> <!-- 组件标签内部嵌套的部分就是插槽内容 -->
        <label>血型</label>
        <span>A、B、O、AB</span>
    </MyInput>
</template>

页面上生成的HTML结构就为:

javascript 复制代码
<div data-v-f33d1cc8="" class="form-input-box">
    <div data-v-f33d1cc8="" class="form-input-lable">
        <label>姓名</label> <!-- 插槽的内容原样输出在这里 -->
    </div>
    <div data-v-f33d1cc8="" class="form-input">
        <input data-v-f33d1cc8="" type="text">
    </div>
</div>

<div data-v-f33d1cc8="" class="form-input-box">
    <div data-v-f33d1cc8="" class="form-input-lable"><!-- 组件标签内部嵌套的部分就是插槽内容 -->
        <label>血型</label>
        <span>A、B、O、AB</span> <!-- 插槽的内容原样输出在这里 -->
    </div>
    <div data-v-f33d1cc8="" class="form-input">
        <input data-v-f33d1cc8="" type="text">
    </div>
</div>

插槽默认内容

在外部没有提供任何内容的情况下,可以为插槽指定默认内容。比如:如果我们想在父组件没有提供任何插槽内容时在 <button> 内渲染"Submit",只需要将"Submit"写在 <slot> 标签之间来作为默认内容:

xml 复制代码
<button type="submit"> 
    <slot> Submit <!-- 默认内容 --> </slot> 
</button>

具名插槽

一个组件的插槽是可以有多个的,不过需要为每个插槽命名,才知道每一次要渲染的内容。这种带命名的插槽就是具名插槽,像前面的那种没有命名的就是默认插槽,只不过默认插槽会有一个隐式的名称default;

使用方法:

  • 在父组件使用template包含插槽内容,并在template添加v-slot:插槽名指令为其命名, 同样使用可用简写#插槽名
  • 子组件的slot中使用name属性来渲染对就插槽的内容。

父组件:

xml 复制代码
<script setup>
    import Container from "@/components/Container.vue";
</script>

<template>
    <Container>
        <template v-slot:header> <!-- 使用v-slot具名为 header -->
            <div class="header">这是头部</div>
        </template>

        <template #default> <!-- 这里为默认插槽 -->
            <div class="main">这是中间部分,使用的是默认插槽</div>
        </template> 

        <template #footer> <!-- 使用简写为其具名 -->
            <div class="footer">这是底部</div>
        </template>
    </Container>
</template>

子组件:

xml 复制代码
<template>
    <section>
        <slot name="header"></slot> <!-- 渲染header插槽 -->
        <slot></slot> <!-- 渲染默认插槽 -->
        <slot name="footer"></slot> <!-- 渲染footer插槽 -->
    </section>
</template>

作用域插槽(在插槽中传值)

一般情况下插槽的内容只能使用父组件中的状态数据,因为插槽的内容都是在父组件中定义的,使用状态数据也只能使用父组件定义的,但是我们可以像对组件传递props那样,向一个插槽的出口上传递属性值:

子组件中:

xml 复制代码
<script setup>
    import { ref } from "vue";
    const msg = ref("插槽学习");
</script>
<template>
    <section>
        <slot :msg="msg"></slot> <!-- 将msg传给插槽 -->
    </section>
</template>

父组件中

xml 复制代码
<script setup>
    import Container from "@/components/Container.vue";
</script>

<template>
    <Container v-slot="slotProps"> <!-- 自定义一个名称接收插槽传来的属性值 -->
        <p>{{ slotProps.msg }}</p> <!-- 使用属性msg -->
    </Container>
</template>

条件插槽

有时你需要根据插槽是否存在来渲染某些内容时,可以结合使用 $slot 属性与v-if来实现。

父组件:

xml 复制代码
<script setup>
    import Container from "@/components/Container.vue";
</script>

<template>
    <Container>
        <template #header>
            <div class="header">header</div>
        </template>
        
        <template #default>
            <div class="main">main</div>
        </template>
        
        <template #footer>
            <div class="footer">footer</div>
        </template>
    </Container>
</template>

子组件:

xml 复制代码
<template>
    <div class="conainter">
        <slot v-if="$slots.header" name="header"></slot> <!--如果存在header插槽就渲染-->
        <slot v-if="$slots.default" name="default"></slot> <!--如果存在默认插槽就渲染-->
        <slot v-if="$slots.footer" name="footer"></slot> <!--如果存在footer插槽就渲染-->
    </div>
</template>

动态插槽

动态插槽就是动态的命名具名插槽,在不同的情况下使用不同命名的插槽。

结合上的条件插槽,以下面这个例子来介绍什么是动态插槽:

父组件:

xml 复制代码
<script setup>
import { ref } from "vue";
    import Container from "@/components/Container.vue";

    const slotListNames = ['header', 'default', 'footer'];
    const curSlotName = ref(slotListNames[0]);

    //获取数组索引内的随机数
    const getRandomIndex = (arr) => parseInt(Math.random() * slotListNames.length);
    // 更新插槽名
    const handleChang = () => {
        curSlotName.value = slotListNames[getRandomIndex()];
    }
</script>

<template>
    <Container>
        <template #[curSlotName]>
            <div v-if="curSlotName === 'default' ">
                这是默认插槽的内容
            </div>

            <div v-if="curSlotName === 'header'">
                这是header插槽的内容
            </div>

            <div v-if="curSlotName === 'footer'">
                这是footer插槽的内容
            </div>
        </template>
    </Container>

    <button @click="handleChang">更新插槽名</button>
</template>

子组件:

xml 复制代码
<template>
    <div class="conainter">
        <slot v-if="$slots.header" name="header"></slot> <!--如果存在header插槽就渲染-->
        <slot v-if="$slots.default" name="default"></slot> <!--如果存在默认插槽就渲染-->
        <slot v-if="$slots.footer" name="footer"></slot> <!--如果存在footer插槽就渲染-->
    </div>
</template>

到此Vue快速入门的基础知识也讲得差不多了,下一章节将会通过完成一个简单的任务管理器来综合的运用这些知识。

相关推荐
一枚小小程序员哈1 小时前
基于Vue + Node能源采购系统的设计与实现/基于express的能源管理系统#node.js
vue.js·node.js·express
一枚小小程序员哈6 小时前
基于Vue的个人博客网站的设计与实现/基于node.js的博客系统的设计与实现#express框架、vscode
vue.js·node.js·express
定栓6 小时前
vue3入门-v-model、ref和reactive讲解
前端·javascript·vue.js
LIUENG7 小时前
Vue3 响应式原理
前端·vue.js
wycode8 小时前
Vue2实践(3)之用component做一个动态表单(二)
前端·javascript·vue.js
wycode9 小时前
Vue2实践(2)之用component做一个动态表单(一)
前端·javascript·vue.js
第七种黄昏9 小时前
Vue3 中的 ref、模板引用和 defineExpose 详解
前端·javascript·vue.js
pepedd86410 小时前
还在开发vue2老项目吗?本文带你梳理vue版本区别
前端·vue.js·trae
前端缘梦10 小时前
深入理解 Vue 中的虚拟 DOM:原理与实战价值
前端·vue.js·面试
HWL567910 小时前
pnpm(Performant npm)的安装
前端·vue.js·npm·node.js