Vue2——插槽

引例

想要实现如下效果:
在这里插入图片描述
发现3个模块的样式一样,所以可以写一个组件,传递不同的数据实现。
实现代码:
单个样式:Category组件(子组件)
Category.vue:

<template>
    <div class="category">
        <h3>{{title}}</h3>
        <ul>
            <li v-for="(item,index) in listData" :key="index">{{item}}</li>
        </ul>

    </div>
</template>

<script>
export default {
    name: 'CategoryVue',
    props:['listData','title']
}
</script>

<style>
.category{
    width:200px;
    height: 300px;
    background: lightseagreen;
}
h3{
    text-align: center;
background: lightgoldenrodyellow;
}
</style>

App.vue:

<template>
  <div class="container">
    <Category title="美食" :listData="foods"/>
    <Category title="游戏" :listData="games"/>
    <Category title="电影" :listData="films"/>
  </div>
</template>

<script>
import Category from "@/components/Category";
export default {
  name: "App",
  data() {
    return {
      foods: ['烧烤', '火锅', '小龙虾', '螺蛳粉'],
      films: ['《当幸福来敲门》', '《泰坦尼克号》', '《阿甘正传》', '《海上钢琴师》'],
      games:['王者荣耀','我的世界','和平精英','穿越火线']
    }
  },
  components: {
    Category
  }
}
</script>
<style lang="css">
.container{
  display: flex;
  justify-content: space-around;
}
</style>

那如果想要实现如下效果又该怎么做呢?
(即不同的模块显示的内容格式不一样)——可以通过插槽来实现
在这里插入图片描述

普通插槽

插槽标签:<slot></slot>

使用方法

  • 插槽一般定义在子组件中,相当于一个占位。<slot></slot>
  • 父组件模板中的子组件标签要写成一对的样式,即:<Category></Category>
  • 这样<Category></Category>中的内容就会显示在子组件<slot></slot>标签的位置。
  • 如果<Category></Category>中没有内容,<slot></slot>标签中的内容就会显示在页面。

这里父组件被称为插槽的使用者

实现:
Category.vue:

<template>
    <div class="category">
        <h3>{{title}}</h3>
        <!-- 插槽就相当于定义一个坑,等组件来填充 -->
        <slot>我是一个插槽,如果组件标签中没有传递值时,我就显示,否则显示组件传递过来的内容</slot>
    </div>
</template>

<script>
export default {
    name: 'CategoryVue',
    props:['listData','title']
}
</script>

<style>

.category{
    width:200px;
    height: 300px;
    background: lightseagreen;
    overflow: hidden;
}
h3{
    text-align: center;
background: lightgoldenrodyellow;
}
</style>

App.vue

<template>
  <div class="container">
    <Category title="美食">
      <img src="./assets/1.jpg" />
    </Category>
    <Category title="游戏">
      <ul>
        <li v-for="(game,index) in games" :key="index">{{game}}</li>
      </ul>
    </Category>
    <Category title="电影">
      <video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
    </Category>
  </div>
</template>

<script>
import Category from "@/components/Category";
export default {
  name: "App",
  data() {
    return {
      foods: ['烧烤', '火锅', '小龙虾', '螺蛳粉'],
      films: ['《当幸福来敲门》', '《泰坦尼克号》', '《阿甘正传》', '《海上钢琴师》'],
      games:['王者荣耀','我的世界','和平精英','穿越火线']
    }
  },
  components: {
    Category
  }
}
</script>
<style lang="css">
.container{
  display: flex;
  justify-content: space-around;
}
img{
  width: 100%;
}
video{
  width: 100%;
}
</style>

实现效果:
在这里插入图片描述
如果App.vue的子组件标签中不放内容,就会将是如下样式:(将slot的内容进行显示)
在这里插入图片描述

插槽的编译

app.vue子组件标签中的html代码片段是编译完之后再放到子组件的插槽中去,所以该html代码片段的样式既可以卸载app.vue文件中,也可以写在子组件中。

具名插槽

具名插槽的使用

一个子组件可能有多个插槽,不同的插槽放置不同的内容,为了区分不同的插槽,每个插槽应该有自己的名字,这就是具名插槽

同时app.vue子组件标签中的html代码片段的内容也需要设置slot属性,用于指明该片段放在哪个插槽中。
如果两个片段放在一个插槽中,不会覆盖只是追加。

category.vue(子组件)

<template>
    <div class="category">
        <h3>{{title}}</h3>
        <!-- 插槽就相当于定义一个坑,等组件来填充 -->
        <slot name="center">我是一个插槽,如果组件标签中没有传递值时,我就显示,否则显示组件传递过来的内容center</slot>
        <slot name="footer">我是一个插槽,如果组件标签中没有传递值时,我就显示,否则显示组件传递过来的内容footer</slot>
    </div>
</template>

<script>
export default {
    name: 'CategoryVue',
    props:['listData','title']
}
</script>

<style>

.category{
    width:200px;
    height: 300px;
    background: lightseagreen;
    overflow: hidden;
}
h3{
    text-align: center;
background: lightgoldenrodyellow;
}
</style>

app.vue(父组件)

<template>
  <div class="container">
    <Category title="美食">
      <img slot="center" href="./assets/1.jpg" />
      <a slot="footer" href="https://www.baidu.com">点我查看更多</a>
    </Category>
    <Category title="游戏">
      <ul slot="center">
        <li v-for="(game,index) in games" :key="index">{{game}}</li>
      </ul>
      <a slot="footer" href="https://www.baidu.com">单机游戏</a>
      <a slot="footer" href="https://www.baidu.com">网络游戏</a>
    </Category>
    <Category title="电影">
      <video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
      <div class="foot" slot="footer">
        <a href="https://www.baidu.com">经典</a>
        <a href="https://www.baidu.com">热门</a>
        <a href="https://www.baidu.com">推荐</a>
      </div>
    </Category>
  </div>
</template>

<script>
import Category from "@/components/Category";
export default {
  name: "App",
  data() {
    return {
      foods: ['烧烤', '火锅', '小龙虾', '螺蛳粉'],
      films: ['《当幸福来敲门》', '《泰坦尼克号》', '《阿甘正传》', '《海上钢琴师》'],
      games:['王者荣耀','我的世界','和平精英','穿越火线']
    }
  },
  components: {
    Category
  }
}
</script>
<style lang="css">
.container,.foot{
  display: flex;
  justify-content: space-around;
}
img{
  width: 100%;
    height: 50%;
}
video{
  width: 100%;
}
</style>

效果:
在这里插入图片描述

template

slot属性碰上template标签可以这样写:
<template v-slot:footer></template>

同时v-slot:可以简写成#
<template #footer></template>
eg:

<template v-slot:footer>
  <div class="foot">
    <a href="https://www.baidu.com">经典</a>
    <a href="https://www.baidu.com">热门</a>
    <a href="https://www.baidu.com">推荐</a>
  </div>
  <h4>欢迎观看电影</h4>
</template>

具名插槽的默认名称

没有提供 name<slot> 出口会隐式地命名为“default”
eg:
子组件:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

父组件传递:

<BaseLayout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <template #default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</BaseLayout>

父组件的写法等同于:

<BaseLayout>
  <template #header>
    <h1>Here might be a page title</h1>
  </template>

  <!-- 隐式的默认插槽 -->
  <p>A paragraph for the main content.</p>
  <p>And another one.</p>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</BaseLayout>

动态插槽名

动态指令参数v-slot 上也是有效的,即可以定义下面这样的动态插槽名:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

  <!-- 缩写为 -->
  <template #[dynamicSlotName]>
    ...
  </template>
</base-layout>

作用域插槽

作用域插槽的应用场景:
数据子组件中,而根据数据生成的结构插槽的使用者上。
(插槽的使用者即使用子组件的父组件)。
传递数据
因为插槽的使用者(父组件)需要使用子组件的数据, 所以需要将数据从子组件传递到插槽的使用者中。

  • 子组件的传递方法:利用插槽标签<slot></slot>结合v-bind指令进行传递:
    <slot :定义属性名="传递的data数据"></slot>
    可以传递多个数据
  • 父组件接收数据的方法有两种:默认作用域

默认作用域插槽接受方法

  • 插槽的使用者接收的方法:通过子组件标签上v-slot指令直接接受一个插槽的props对象。
    子组件传入插槽的props作为v-slot指令的值可以在插槽内的表达式中访问。
<MyComponent v-slot="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>

在这里插入图片描述

具名作用域插槽接受方法

具名作用域插槽的工作方式和普通作用域插槽的工作方式类似,插槽的props可以作为v-slot指令的值v-slot:name="slotProps"被访问到,也可以使用简写#name="slotProps"访问。

子组件传递props属性:

<slot name="header" message="hello"></slot>

父组件接受props属性:

<MyComponent>
  <template #header="headerProps">
    {{ headerProps }}
  </template>

  <template #default="defaultProps">
    {{ defaultProps }}
  </template>

  <template #footer="footerProps">
    {{ footerProps }}
  </template>
</MyComponent>

父组件headerProps接受到的数据是 { message: 'hello' }子组件slot标签的name属性是不会传递給插槽的。

默认作用域插槽和具名作用域插槽一起使用

当一起使用的时候相当于为默认插槽设置了一个default的名字,使用<template>标签和v-slot:default接受默认作用域插槽的属性值。具名作用域插槽正常使用即可。

<template>
  <MyComponent>
    <!-- 使用显式的默认插槽 -->
    <template #default="{ message }">
      <p>{{ message }}</p>
    </template>

    <template #footer>
      <p>Here's some contact info</p>
    </template>
  </MyComponent>
</template>

vue2作用域插槽接受方法

  • 插槽的使用者接收的方法:使用<template></template>标签的scope属性接收从子组件通过<slot>标签传递过来的所有数据,接收到的数据是一个对象。
    也可以使用<template></template>标签的slot-scope属性接收数据。
    scope和slot-scope接收数据支持解构赋值
<template scope="自己起的变量名">
</template>

使用:

  • 子组件category.vue —— 数据在子组件中
<template>
    <div class="category">
        <h3>{{title}}</h3>
        <!-- 插槽就相当于定义一个坑,等组件来填充 -->
        <!--slot将games传递给插槽的使用者  -->
        <slot :games="games">我是一个插槽</slot>
    </div>
</template>

<script>
export default {
    name: 'CategoryVue',
    props: ['title'],
    data() {
        return{
            games: ['王者荣耀', '我的世界', '和平精英', '穿越火线']
        }
    }
}
</script>

<style>

.category{
    width:200px;
    height: 300px;
    background: lightseagreen;
    overflow: hidden;
}
h3{
    text-align: center;
background: lightgoldenrodyellow;
}
</style>
  • 父组件App.vue(插槽的使用者) —— 结构在父组件中
<template>
  <div class="container">
    <Category title="游戏">
      <!-- template利用scope属性接受插槽传过来的数据 -->
      <!-- scope接收的数据是一个对象 -->
      <template scope="youxi">
        <ul>
          <li v-for="(game,index) in youxi.games" :key="index">{{game}}</li>
        </ul>
      </template>
    </Category>
    <Category title="游戏">
      <!-- 支持解构赋值 -->
      <template scope="{games}">
        <ol>
          <li v-for="(game,index) in games" :key="index">{{game}}</li>
        </ol>
      </template>
    </Category>
    <Category title="游戏">
      <!-- 也可以使用slot-scope属性接受值 -->
      <template slot-scope="{games}">
        <h4 v-for="(game,index) in games" :key="index">{{game}}</h4>
      </template>
    </Category>
  </div>
</template>

<script>
import Category from "@/components/Category";
export default {
  name: "App",
  components: {
    Category
  }
}
</script>
<style lang="css">
.container{
  display: flex;
  justify-content: space-around;
}
</style>

实现的效果:
在这里插入图片描述

好几使用示例

子组件可以循环使用<slot>:
FancyList.vue:

<ul>
  <li v-for="item in items">
    <slot name="item" v-bind="item"></slot>
  </li>
</ul>

父组件使用:

<FancyList :api-url="url" :per-page="10">
  <template #item="{ body, username, likes }">
    <div class="item">
      <p>{{ body }}</p>
      <p>by {{ username }} | {{ likes }} likes</p>
    </div>
  </template>
</FancyList>

无渲染组件

简单来说就是:只有逻辑内容没有渲染内容的子组件叫做无渲染组件,子组件的渲染通过具名插槽全权交给父组件渲染。

上面的 <FancyList> 案例同时封装了可重用的逻辑 (数据获取、分页等) 和视图输出,但也将部分视图输出通过作用域插槽交给了消费者组件来管理。

如果我们将这个概念拓展一下,可以想象的是,一些组件可能只包括了逻辑而不需要自己渲染内容,视图输出通过作用域插槽全权交给了消费者组件。我们将这种类型的组件称为无渲染组件

插槽总结

  • 插槽的作用:
    让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件===>子组件
    使用插槽的时候父组件向子组件传递的html内容,在组件实例对象的$slots属性上存储着父组件向子组件传递的html内容
  • 8
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Vue 3中,具名插槽的使用方式与Vue 2类似。具名插槽允许我们在组件中定义多个插槽,并通过插槽名称将内容分发到相应的插槽中。 以下是一个Vue 3的具名插槽示例: ```html <template> <div> <h1>Vue 3 具名插槽示例</h1> <slot name="header">默认头部</slot> <slot name="content">默认内容</slot> <slot name="footer">默认底部</slot> </div> </template> <template> <div> <h2>使用组件:</h2> <MyComponent> <template #header> <h3>自定义头部</h3> </template> <template #content> <p>自定义内容</p> </template> <template #footer> <button>自定义底部</button> </template> </MyComponent> </div> </template> ``` 在上述示例中,我们定义了一个名为`MyComponent`的组件,并在其模板中使用了具名插槽。组件中的默认插槽分别是`header`、`content`和`footer`,它们分别显示了默认的头部、内容和底部。 在使用此组件时,我们可以在`MyComponent`标签内部使用`template`标签,并通过`#`符号和插槽名称来定义具名插槽的内容。例如,`#header`表示定义了一个名为`header`的具名插槽,其中包含了自定义的头部内容。 这样,当`MyComponent`组件在父组件中使用时,具名插槽的内容将会被分发到相应的插槽位置。 希望以上示例能够帮助您理解Vue 3的具名插槽使用方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [vue slot插槽——vue2、vue3默认插槽、具名插槽使用](https://blog.csdn.net/dongzi_yu/article/details/129751748)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [vue 使用插槽分发内容操作示例【单个插槽、具名插槽、作用域插槽】](https://download.csdn.net/download/weixin_38675777/12927451)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值