【vue3】08-vue的组件化开发-插槽(Slots)的完全指南

news2024/9/20 5:54:45

Vue插槽(Slots)的完全指南

  • 插槽的作用
  • 插槽的基本使用
  • 具名插槽
  • 作用域插槽(难点)

插槽的作用

在开发中,我们会经常封装一个个可复用的组件:

  • 前面我们会通过props传递给组件一些数据,让组件来进行展示;
  • 但是为了让这个组件具备更强的通用性,我们不能将组件中的内容限制为固定的div、span等等这些元素;
  • 比如某种情况下我们使用组件,希望组件显示的是一个按钮,某种情况下我们使用组件希望显示的是一张图片;
  • 我们应该让使用者可以决定某一块区域到底存放什么内容和元素;

假如我们定制一个通用的导航组件–NavBar:

  • 这个组件分成三块区域:左边-中间-右边,每块区域的内容是不固定;
  • 左边区域可能显示一个菜单图标,也可能显示一个返回按钮,可能什么都不显示;
  • 中间区域可能显示一个搜索框,也可能是一个列表,也可能是一个标题,等等;
  • 右边可能是一个文字,也可能是一个图标,也可能什么都不显示;

在这里插入图片描述

这个时候我们就可以来定义插槽slot:

  • 插槽的使用过程其实是抽取共性、预留不同;
  • 我们会将共同的元素、内容依然在组件内进行封装;
  • 同时会将不同的元素使用slot作为占位,让外部决定到底显示什么样的元素;

如何使用slot呢?

  • Vue中将<slot>元素作为承载分发内容的出口;
  • 在封装组件中,使用特殊的元素<slot>就可以为封装组件开启一个插槽;
  • 该插槽插入什么内容取决于父组件如何使用;

在这里插入图片描述


插槽的基本使用

基本插槽,也称为匿名插槽,是使用时不需要为插槽指定名称的插槽。使用基本插槽的方式非常简单,可以直接在组件内部使用<slot></slot>来定义一个匿名插槽:

<template>
    <h2>{{ title }}</h2>
    <div class="content">
        <slot>我是插槽默认内容</slot>
    </div>
</template>
      
      
<script>
export default {
    props: {
        title: {
            type: String,
            default: "我是标题"
        }
    }
}
</script>

在上面的例子中,我们在子组件ShowMessage中定义了一个匿名插槽。当父组件使用时,插槽将会被替换为组件的内容。

<template>
    <div id="app">
        <show-message title="我是标题"></show-message>
        <show-message title="我是标题2">
            <button>按钮</button>
        </show-message>
        <show-message title="我是标题3">
            <a href="#">我是超链接</a>
        </show-message>

        <show-message title="我是标题4">
            <img src="@/IMG/noteBorad.png" alt="">
        </show-message>

    </div>
</template>
      
      
<script>
import ShowMessage from "./components/ShowMessage.vue";

export default {
    components: {
        ShowMessage
    }
}
</script>

在这个例子中,使用子组件时按钮,超链接,图片将分别作为插槽的内容被嵌入到组件中,效果如下:

在这里插入图片描述

但如果同时有多个插槽,如左中右区域都留有插槽,我们该如何分别将内容插入到对应的插槽中呢,这时候就需要使用具名插槽。


具名插槽

释义:具名插槽是指为插槽赋予名称,以便使用者可以向指定的插槽中插入内容

使用具名插槽的方式是给<slot>元素添加一个name属性,如下所示:

<template>
  <div class="nav-bar">
    <!-- 同时预留多个插槽时,在每一个插槽行内使用name为其编写唯一值 -->
    <div class="left">
      <slot name="left">leftcontent</slot>
    </div>
    <div class="center">
      <slot name="center">centercontent</slot>
    </div>
    <div class="right">
      <slot name="right">rightcontent</slot>
    </div>
  </div>
</template>

在上面的例子中,我们定义了一个NavBar组件并在其中定义了名为“left”,"center"和"right"的三个具名插槽。并分别给了默认内容leftcontent,centercontent,rightcontent

当在父组件使用时,可以使用<template>元素和v-slot指令来向插槽中插入内容,如下所示:

<template>
    <div id="app">
        <!-- 多个插槽使用是,采用v-slot:name确认使用哪个插槽 -->
        <nav-bar>
            <template v-slot:left>
                <button>左边按钮</button>
            </template>
            
        <!-- v-slot:name可以简写为#name -->    
             <template #center>
			    <a href="#">中间链接</a>
			 </template>
			      
            <template v-slot:right>
                <i>右边i元素</i>
            </template>
        </nav-bar>
        <hr>
        <!-- 只使用一个插槽时:其他插槽会使用默认值 -->
        <nav-bar>
            <template v-slot:right>
                <button>右边按钮</button>
            </template>
        </nav-bar>

    </div>
</template>

运行效果如下:

在这里插入图片描述


作用域插槽(难点)

认识作用域插槽:

但是有时候我们希望插槽可以访问到子组件中的内容是非常重要的:

  • 当一个组件被用来渲染一个数组元素时,我们使用插槽,并且希望插槽中没有显示每项的内容;
  • 这个Vue给我们提供了作用域插槽;

比如,在下面这个组间通信案例选项卡模拟案例中:

  • tabControl是独立的组件,在父组件中使用时传递参数来显示对于内容

  • 点击哪个标题则展示对应内容

  • 可以通过下方代码部分看到tabControl部分使用的时候里面的item始终都是被包裹在span元素里的,

  • 如果想自己决定使用的时候包裹item的是什么元素呢,比如button,比如a标签

在这里插入图片描述


代码部分:

-tabControl.vue:

<template>
    <div class="tabControl">
        <template v-for="(item, index) in titles" :key="item">
            <div class="tabControl-item" @click="itemClick(index)" :class="{ active: index === currentIndex }">
            <!-- 此处!!!!!!!!!!!!!!! -->
                    <span>{{ item }}</span>
            </div>
        </template>
    </div>
</template>

<script>


export default {
    props: {
        titles: {
            type: Array,
            default: () => []
        }
    },

    data() {
        return {
            currentIndex: 0
        }
    },

    emits: ["tabitemClick"],

    methods: {
        itemClick(index) {
            this.currentIndex = index;
            this.$emit("tabitemClick", index)
        }
    }

}
</script>

App.vue:

<template>
  <div id="app">
    <!-- tab control -->
    <TabControl :titles="['衣服', '鞋子', '裤子']" @tabitem-click="tabcardSwitch"></TabControl>
    <TabControl :titles="['流行', '最新', '优选']"></TabControl>
    <!-- 展示内容 -->
    <h1>{{ pageContents[currentIndex] }}</h1>
  </div>
</template>

<script>
import TabControl from './components/TabControl.vue';

export default {
  components: {
    TabControl
  },

  data() {
    return {
      // 写二维数组时就是选项卡的切换了,现在是便于理解
      pageContents: ["衣服列表", "鞋子列表", "裤子列表"],
      currentIndex: 0
    }
  },

  methods: {
    tabcardSwitch(index) {
      console.log("app:", index);
      this.currentIndex = index
    }
  }

}
</script>

我们可以通过预留插槽的方式来解决,但直接使用插槽的话, 会让我们数据固定, 不能动态展示;

那像下面这样使用呢 ?

在这里插入图片描述
由于vue中渲染作用域的存在,像上面这样的做法显然是不行的

而我们希望的仅是span改变,而里面的内容仍是item这样不固定的数据,所以这时候就需要用到作用域插槽

(1)子组件中在插槽中传递出要使用的数据:

<template>
    <div class="tabControl">
        <!-- template写成了temolate,导致遍历出的item多了一个父级元素,难怪flex:1不生效 -->
        <template v-for="(item, index) in titles" :key="item">
            <div class="tabControl-item" @click="itemClick(index)" :class="{ active: index === currentIndex }">
                <!-- 需求:可以由父组件决定是span或者说按钮等内容:未填充时是默认值span -->
                <!-- 在插槽上写: 用:绑定一个属性传递出去 :item=“要传递的属性” -->
                <slot :item="item">
                    <span>{{ item }}</span>
                </slot>

            </div>
        </template>
    </div>
</template>

(2)父组件使用v-slot:插槽名=接收数据变量名来进行接收, 此时可以将span元素换成其他元素进行替换

<template>
  <div class="app">
    <TabControl :titles="['无敌', 'NB', '666']">
 <!-- 1.<slot>为单独设置name属性值时,默认名字为default;
 	 2.这里的props非固定(可以用其他命名)-->
      <template #default="props">
        <button>{{ props.item }}</button>
      </template>
    </TabControl>
  </div>
</template>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/617142.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CVPR2023】TPS详解:联合令牌剪枝与压缩以实现视觉变形器更积极的压缩

【CVPR2023】TPS详解&#xff1a;联合令牌剪枝与压缩以实现视觉变形器更积极的压缩 0. 引言1. 为什么要使用TPS&#xff1f;2. TPS介绍3. TPS 详解3.1 重要性计算3.2 令牌压缩3.2.1 匹配3.2.2 融合 4. 简化版理解5. 总结 0. 引言 虽然 Vision Transformers &#xff08;ViTs&a…

小文智能宣布接入ChatGPT,智能化客户服务,开创全新用户体验

小文智能是一家致力于用AI技术解放劳动力的公司&#xff0c;最近我们接入了ChatGPT技术&#xff0c;深度探索AI在智能对话机器人领域应用的更多可能&#xff0c;这将为我们的客户带来更为优质的人机对话服务和全新的用户体验。 ChatGPT是一种基于人工智能的自然语言处理技术&a…

案例31:基于Springboot企业员工薪酬关系系统开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

逍遥自在学C语言 | break-循环的中断与跳转

前言 在C语言中&#xff0c;break语句是一种控制流语句&#xff0c;它用于终止当前所在的循环结构&#xff08;for、while、do-while&#xff09;或者switch语句&#xff0c;从而跳出循环或者结束switch语句的执行。 一、人物简介 第一位闪亮登场&#xff0c;有请今后会一直…

ML算法——梯度下降随笔【机器学习】

文章目录 11、梯度下降 11、梯度下降 梯度下降如何帮助参数优化&#xff1f; 梯度下降是一种用于参数优化的常见方法。它的基本思想是通过迭代地更新参数&#xff0c;以减小损失函数|代价函数的值&#xff0c;从而找到一个最优解。 梯度方向&#xff1a;→|向右|正向 ←|向左|反…

PostGIS(1):PostGIS概述

作为对象关系型数据库PostGreSQL的拓展模块&#xff0c;PostGIS可用于存储GIS数据&#xff0c;并提供了对基于GiST的R树索引支持、以及面向GIS对象的分析和处理相关的函数。 以下是PostGIS官网对其特征的介绍&#xff0c; &#xff08;1&#xff09; 先看一下百度对PostGIS的介…

Langchain-ChatGLM:基于本地知识库问答

文章目录 ChatGLM与Langchain简介ChatGLM-6B简介ChatGLM-6B是什么ChatGLM-6B具备的能力ChatGLM-6B具备的应用 Langchain简介Langchain是什么Langchain的核心模块Langchain的应用场景 ChatGLM与Langchain项目介绍知识库问答实现步骤ChatGLM与Langchain项目特点 项目主体结构项目…

php7新特性详细介绍(二)

一、PHP 7 异常 PHP 7 异常用于向下兼容及增强旧的assert()函数。它能在生产环境中实现零成本的断言&#xff0c;并且提供抛出自定义异常及错误的能力。 assert() 配置 | 配置项默认值可选值zend.assertions11 - 生成和执行代码 (开发模式) 0 - 生成代码&#xff0c;但在执…

智警杯excel和sql实训盲点

目录 excel基础操作&#xff1a; excel函数&#xff1a;智警杯赛前学习1.2--excel统计函数_lulu001128的博客-CSDN博客知识点https://blog.csdn.net/lulu001128/article/details/130936259?spm1001.2014.3001.5501 excel报表实战&#xff1a; excel数据透视及绘图&#xff…

Amino框架无锁算法实现并发线程安装组件(一)

Amino是无锁并行框架&#xff0c;线程安装&#xff0c;该框架封装了无锁算法&#xff0c;提供了可用于线程安全的一些数据结构,同时还内置了一些多线程调度模式。使用Amino进行软件开发有以下的优势: 1.对死锁的问题免疫 2.确保系统并发的整体进度 3.降低高并发下无锁竞争带…

java设计模式之:建造者模式

文章目录 建造者模式介绍建造者模式适用场景案例场景一坨坨代码实现重构代码 与工厂模式区别建造者模式优缺点总结 该说不说几乎是程序员都知道或者了解设计模式&#xff0c;但大部分小伙伴写代码总是习惯于一把梭。好的代码不只为了完成现有功能&#xff0c;也会考虑后续扩展。…

springboot自动配置源码解析

概述 使用springboog的时候引入starter就自动为我们加载&#xff0c;例如我们引入 spring-boot-starter-web 之后&#xff0c;就自动引入了 Spring MVC 相关的 jar 包&#xff0c;从而自动配置 Spring MVC 。 自动装配原理 SpringBootApplication SpringBootApplication: Spri…

Java的引用

一、概述 其实java有4种引用&#xff0c;4种可分为强、软、弱、虚。我们将从这四个方面入手进行介绍。 二、强引用 首先看到我们有一个类叫M&#xff0c;在这个类里我重写了一个方法叫finalize()&#xff0c;我们可以看到这个方法是已经被废弃的方法&#xff0c;为什么要重写…

【jupyter】Jupyter Notebook如何导入导出文件

目录 0.系统&#xff1a;windows 1.打开 Jupyter Notebook 2.Jupyter Notebook导入文件 3.Jupyter Notebook导出文件 0.系统&#xff1a;windows 1.打开 Jupyter Notebook 1&#xff09;下载【Anaconda】后&#xff0c;直接点击【Jupyter Notebook】即可在网页打开 Jupyte…

用户研究干货——这一篇就够啦

一、基本概念&#xff1a; ①工作内容&#xff1a;用户研究的首要目的是帮助企业定义产品目标用户群&#xff0c;明确、细化产品概念&#xff0c;并通过对用户的任务操作特性、知觉特征、认知心理特征的研究&#xff0c;使用户的实际需求成为产品设计的导向&#xff0c;使产品…

建面超72万㎡,南山红花岭旧改规划公示,配套近15万㎡宿舍

近日&#xff0c;深圳市南山区城市更新和土地整备局发布关于桃源街道红花岭工业南区更新单元&#xff08;暂定名&#xff09;03-01、02-02地块《建设工程规划许可证》及总平面图的公告。 此次批复的红花岭工业南区02-02、03-01块&#xff0c;总建面超72万㎡&#xff0c;用地单…

nginx+tomcat 负载均衡、动静分离集群

文章目录 一、NginxTomcat负载均衡的组合原因1.1 Nginx实现负载均衡的原理1.2 Nginx实现负载均衡的主要配置项1.3 NginxTomcat负载均衡的组合的优点1.4 NginxTomcat负载均衡的实验设计 二、动静分离部署2.1 部署TOMCAT后端服务器2.2部署nginx服务器2.3安装nginx动态服务器 一、…

java中try-with-resources自动关闭io流

在传统的输入输出流处理中&#xff0c;我们一般使用的结构如下所示&#xff0c;使用try - catch - finally结构捕获相关异常&#xff0c;最后不管是否有异常&#xff0c;我们都将流进行关闭处理&#xff1a; try {//todo } catch (IOException e) {log.error("read xxx f…

《Lua程序设计》--学习1

前言&#xff1a; --> 表示一条语句的输出或表达式求值的结果 -- 单行注释 > 标注 一些代码需要在交互模式下输入 如果需要打印表达式求值的结果&#xff0c;必须在每个表达式前加上一个等号 <--> 表示两者完全等价 语言基础 我们将Lua语言执行的每一…

html选择器

基本选择器 基本选择器 : 标签选择器 , 类选择器 , ID选择器 标签选择器 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEed…