Vue3魔法手册 作者 张天禹 015_插槽

061_插槽-默认插槽

插槽分为三种:默认插槽,具名插槽,作用域插槽

三个组件: Game.vue Food.vue Movie.vue

他们的形式结构很类似

红色的==>上面是标题,下面是内容

万一是后台返回给我们28个分类,我们该如何处理

他们都是一个组件

把下面的内容都放在一个 Category.vue 的文件中

就是分类的意思

src/pages/09_slot/Category.vue

复制代码
<template>
    <div class="category">
        <h2>xxxx</h2>
        ?????
    </div>
</template>

<script setup lang="ts" name="Category">

</script>

<style scoped>
    .category {
        background-color: skyblue;
        border-radius: 10px;
        box-shadow: 0 0 10px;
        padding: 10px;
        width: 200px;
        height: 300px;
    }
</style>

父组件-子组件

图片地址和电影地址

复制代码
https://z1.ax1x.com/2023/11/19/piNxLo4.jpg
http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4

http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4
https://z1.ax1x.com/2023/11/19/piNxLo4.jpg

https://fd.aigei.com/pvvdo_fast/vdo/mp4/08/08a69b04e308469a81fbf008685eaadc.mp4?e=1770617040&token=P7S2Xpzfz11vAkASLTkfHN7Fw-oOZBecqeJaxypL:tyQ7mmfM3EJuwIsLRT4RK1ZKqhA=

https://fd.aigei.com/pvvdo_fast/vdo/mp4/24/240b2bfa5aa3421eb924a03c6ea60464.mp4?e=1770617040&token=P7S2Xpzfz11vAkASLTkfHN7Fw-oOZBecqeJaxypL:rjB85hxhoz2IeegsT5OYyRh7bFo=

将游戏列表,图片,视频展示在???处

组件的起始标签,组件的结束标签 span标签里面的内容不会出现在页面

vue知道你是想用Category组件标签,于是就把Category.vue文件中绿色的div内容呈现在页面上。

你这个起始标签和结束标签既然夹着一个span,vue是如何认为span的

vue认为既然你把span放在起始标签和结束标签里面,那你需要把span塞到Category.vue文件中绿色结构里面

将 span 塞到哪里呢?

我不知道塞哪里?我就不塞了,直接扔掉

vue认为要将 span 标签就塞到 slot 标签所在的位置,然后就真摆在这里

将ul里面的内容放到slot里面

Categroy这个组件使用了三次

每次使用都是夹着不同的内容过去的

夹待的内容都分别放在 slot里面了

默认插槽

默认插槽slot只占位,ul,img,video的内容就都进去了

挖个垦占位,你们都到这里来玩游戏

充值结束就可以玩游戏

写三个占位符,内容跑三遍 一个萝卜一个垦 代码-效果

_插槽-默认插槽 实现代码如下

复制代码
1, src/pages/09_slot/Category.vue

<template>
    <div class="category">
        <h2>{{ title }}</h2>
        <slot>默认内容</slot>
    </div>
</template>

<script setup lang="ts" name="Category">
    defineProps(['title'])
</script>

<style scoped>
    .category {
        background-color: skyblue;
        border-radius: 10px;
        box-shadow: 0 0 10px;
        padding: 10px;
        width: 200px;
        height: 300px;
    }
    h2 {
        font-size: 20px;
        font-weight: 800;
        background-color: orange;
        text-align: center;
    }
</style>




2, src/pages/09_slot/Father.vue
<template>
    <div class="father">
        <h3>父组件</h3>
        <div class="content">
            <Category title="热门游戏列表">
                <ul>
                    <li v-for="item in games" :key="item.id">{{ item.name }}</li>
                </ul>
            </Category>
            <Category title="今日美食城市">
                <img :src="imgUrl" alt="" />
            </Category>
            <Category title="今日影视推荐">
                <video :src="videoUrl" controls></video>
            </Category>
        </div>
    </div>
</template>

<script setup lang="ts" name="Father">
    import Category from '@/pages/09_slot/Category.vue'
    import { ref,reactive } from 'vue'

    let games = reactive([
        {id:'zg01',name:'王者荣耀'},
        {id:'zg02',name:'和平精英'},
        {id:'zg03',name:'英雄联盟'},
        {id:'zg04',name:'明日方舟'},
    ])

    let imgUrl = ref('https://z1.ax1x.com/2023/11/19/piNxLo4.jpg')
    let videoUrl = ref('https://fd.aigei.com/pvvdo_fast/vdo/mp4/08/08a69b04e308469a81fbf008685eaadc.mp4?e=1770617040&token=P7S2Xpzfz11vAkASLTkfHN7Fw-oOZBecqeJaxypL:tyQ7mmfM3EJuwIsLRT4RK1ZKqhA=')
</script>

<style scoped>
    .father {
        padding: 20px;
        background-color: rgb(165,164,164);
        border-radius: 10px;
    }
    .content {
        display: flex;
        justify-content: space-evenly;
    }

    ul {
        list-style: none;
    }
    li {
        font-size: 18px;
        font-weight: 600;
        margin: 20px 0;

    }
    img,video {
        width: 100%;
    }
</style>

062_插槽-具名插槽 ==> 具有名字的插槽

代码-效果 说明ul,img,video没有放到name="s2"的坑位里面,所以页面呈现是默认内容.

ul去找 默认的slot没有找到,因为那个是带名字的slot

我要将 ul 放在一个名为 s2 的插槽里面

表示 ul 要放在 名为s2的插槽里面

红的找s1,绿色的找s2

v-slot:s1 简写 #s1 插槽名

_插槽-具名插槽 实现代码如下:

复制代码
1, src/pages/09_slot/Father.vue
<template>
    <div class="father">
        <h3>父组件</h3>
        <div class="content">
            <Category>
                <template v-slot:s2>
                    <ul>
                        <li v-for="item in games" :key="item.id">{{ item.name }}</li>
                    </ul>
                </template>
                <template v-slot:s1>
                    <h2>热门游戏列表</h2>
                </template>
            </Category>
            <Category>
                <template v-slot:s2>
                    <img :src="imgUrl" alt="" />
                </template>
                <template v-slot:s1>
                    <h2>今日美食城市</h2>
                </template>
            </Category>
            <Category>
                <template #s2>
                    <video :src="videoUrl" controls></video>
                </template>
                <template #s1>
                    <h2>今日影视推荐</h2>
                </template>
            </Category>
        </div>
    </div>
</template>


<script setup lang="ts" name="Father">
    import Category from '@/pages/09_slot/Category.vue'
    import { ref,reactive } from 'vue'

    let games = reactive([
        {id:'zg01',name:'王者荣耀'},
        {id:'zg02',name:'和平精英'},
        {id:'zg03',name:'英雄联盟'},
        {id:'zg04',name:'明日方舟'},
    ])

    let imgUrl = ref('https://z1.ax1x.com/2023/11/19/piNxLo4.jpg')
    let videoUrl = ref('')
</script>

<style scoped>
    .father {
        padding: 20px;
        background-color: rgb(165,164,164);
        border-radius: 10px;
    }
    .content {
        display: flex;
        justify-content: space-evenly;
    }

    ul {
        list-style: none;
    }
    li {
        font-size: 18px;
        font-weight: 600;
        margin: 20px 0;

    }
    img,video {
        width: 100%;
    }
    h2 {
        font-size: 20px;
        font-weight: 800;
        background-color: orange;
        text-align: center;
    }
</style>





2, src/pages/09_slot/Category.vue
<template>
    <div class="category">
        <!-- <slot name="default"></slot> -->
        <slot name="s1">默认插槽内容1</slot>
        <slot name="s2">默认插槽内容2</slot>
    </div>
</template>

<script setup lang="ts" name="Category">
    defineProps(['title'])
</script>

<style scoped>
    .category {
        background-color: skyblue;
        border-radius: 10px;
        box-shadow: 0 0 10px;
        padding: 10px;
        width: 200px;
        height: 300px;
    }    
</style>
飘红表示v-slot:s2这个只能放在组件标签上或者是放在<template>标签上

你目前将 v-slot:s2放在ul标签上,这是不允许的

063_插槽-作用域插槽

准备数据

src/pages/09_slot/Game.vue

复制代码
<template>

</template>

<script setup lang="ts" name="Game">

</script>

<style scoped>

</style>

src/pages/09_slot/Father.vue

复制代码
<template>
    <div class="father">
        <h3>父组件</h3>
        <div class="content">
            ??????????
        </div>
    </div>
</template>

<script setup lang="ts" name="Father">
    
</script>

<style scoped>
    .father {
        padding: 20px;
        background-color: rgb(165,164,164);
        border-radius: 10px;
    }
    .content {
        display: flex;
        justify-content: space-evenly;
    }

    ul {
        list-style: none;
    }
    li {
        font-size: 18px;
        font-weight: 600;
        margin: 20px 0;
    }
    img,video {
        width: 100%;
    }
    h2 {
        font-size: 20px;
        font-weight: 800;
        background-color: orange;
        text-align: center;
    }
</style>

分类: 订单分类,美食分类,电影分类

Game.vue 该文件里面维护的结构,数据,样式都是与游戏有关

游戏相关的结构,数据,样式

第一个是无序列表,第二个是有序列表,第三个是不列列表

绿色里面的数据不确定

可以放插槽里面去实现

但是 games 飘红了,因为games在子组件

父组件要使用子组件里面的数据 父组件摸不到子组件的数据games

games访问不到,类似作用域的问题,数据games是在子组件,父组件是摸不到games数据的

这就是作用域的问题,该如何处理

根据绿色数据生成的红色结构是由父组件决定的

给slot组件传递props数据

slot组件是vue里面内置的组件

可以接收games数据

子组件是slot插槽的位置

黄色部分就是在使用插槽, 父组件是slot插槽的使用者

原理:

games数据在子组件,子组件通过props把games传递给内置组件slot,slot拿到games数据以后他没有扔掉,也没有吃掉,slot把games数据传递给插槽的使用者.

粉色小圈圈的位置是可以使用slot传递过来的games数据

你所传递的数据打包成一个对象,直接传递给a

代码-效果

有三组 key-value 数据

代码-效果

数据在子组件里面,由数据生成的结构是由父组件决定的,正是因为数据在子组件,而父组件需要拿到数据能决定结构,所以就出现了一个数据访问作用域的问题,为了解决这个问题,所以才引出了作用域插槽,这个就是作用域插槽。当然父组件里面我们要使用v-slot="params"

为作用域插槽取名后,需要修改的代码如下: 作用域插槽也是可以有名字的

UI组件可以的对话框,table表格等都在大量使用作用域插槽

红色的是UI组件库的作者写的,程序员写的是绿色的,写的弹窗,表格等

总结:

我们理解的作用域插槽,首先从作用域出发,我们实际开发中就会遇到,由子组件去维护自己的所有数据,结构,交互,都是由他自己决定的,但是有一个例外,他的结构由他的父组件决定,这个就是作用域的问题,为了解决这个问题,所以官方出了一个作用域插槽。

UI组件可以里面的对话框,表格等都大量使用作用域插槽。

_插槽-作用域插槽 实现代码如下

复制代码
1, src/pages/09_slot/Father.vue
<template>
    <div class="father">
        <h3>父组件</h3>
        <div class="content">
            <Game>
                <template v-slot:qwe="params">
                    <ul>
                        <li v-for="y in params.youxi" :key="y.id">{{ y.name }}</li>
                    </ul>
                </template>
            </Game>
            <Game>
                <template v-slot:qwe="params">
                    <ol>
                        <li v-for="item in params.youxi" :key="item.id">{{ item.name }}</li>
                    </ol>
                </template>
            </Game>
            <Game>
                <!-- 将所传数据解构出来后展示数据: -->
                <template v-slot:qwe="{youxi}">
                    <h3 v-for="i in youxi" :key="i.id">{{ i.name }}</h3>
                </template>
            </Game>
        </div>
    </div>
</template>

<script setup lang="ts" name="Father">
    import Game from '@/pages/09_slot_作用域插槽/Game.vue';
</script>

<style scoped>
    .father {
        padding: 20px;
        background-color: rgb(165,164,164);
        border-radius: 10px;
    }
    .content {
        display: flex;
        justify-content: space-evenly;
    }
    img,video {
        width: 100%;
    }
</style>





2, src/pages/09_slot/Game.vue
<template>
    <div class="game">
        <h2>游戏列表</h2>
        <slot name="qwe" :youxi="games" x="哈哈" y="您好"></slot>
    </div>
</template>

<script setup lang="ts" name="Game">
    import {reactive} from "vue";

    let games = reactive([
        {id:'zg01',name:'王者荣耀'},
        {id:'zg02',name:'和平精英'},
        {id:'zg03',name:'英雄联盟'},
        {id:'zg04',name:'明日方舟'},
    ])
</script>

<style scoped>
    .game {
        width: 200px;
        height: 300px;
        background-color: aqua;
        border-radius: 10px;
        box-shadow: 0 0 10px;
    }
    h2 {
        font-size: 20px;
        font-weight: 800;
        background-color: orange;
        text-align: center;
        margin-top: 20px;
    }
    ul {
        list-style: none;
    }
    li {
        font-size: 18px;
        font-weight: 600;
        margin: 20px 0;
    }
</style>
相关推荐
lisypro12 小时前
gin-vue-admin项目使用命令行进行启动
前端·vue.js·golang·gin
Ziky学习记录2 小时前
深入理解 JavaScript 事件循环机制
前端·javascript
码云数智-园园2 小时前
React Server Components 深度解析与实战应用:从原理到生产级落地指南
开发语言·前端·javascript
lyyl啊辉2 小时前
5. pinia集中状态存储
vue.js
锅包一切2 小时前
【蓝桥杯JavaScript基础入门】二、JavaScript关键特性
开发语言·前端·javascript·学习·蓝桥杯
明月_清风2 小时前
源码回溯的艺术:SourceMap 底层 VLQ 编码与离线解析架构实战
前端·监控
明月_清风2 小时前
WebMCP 实战指南:让你的网站瞬间变成 AI 的“大脑外挂”
前端·mcp
我不吃饼干10 小时前
TypeScript 类型体操练习笔记(二)
前端·typescript
光影少年11 小时前
浏览器渲染原理?
前端·javascript·前端框架