当前位置: 首页 > news >正文

vue组件深入介绍之插槽

了解插槽之前请先了解vue组件基础及注册

Vue2官网介绍
Vue3官网介绍

1、vue2插槽介绍

在2.6.0中,具名插槽和作用域插槽引入了一个新的统一语法(v-slot指令)。它将取代slot和slot-scope;

Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将 < slot > 元素作为承载分发内容的出口。

允许父组件更改子组件模板内容,例如:

//父组件
<navigation-link url="/profile">Your Profile
</navigation-link>
//子组件NavigationLink.vue
<a v-bind:href="url" class="nav-link"><slot></slot>
</a>
//渲染结果
<a href="/profile" class="nav-link">Your Profile
</a>

如果 < navigation-link > 的 template 中没有包含一个 < slot > 元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。

/*子组件*/
<template>
<a v-bind:href="url" class="nav-link"></a>
</template>
/*父组件*/
<navigation-link url="/profile"><span> Your Profile</span>a标签
</navigation-link>
//渲染结果,a标签中间无任何内容被渲染,span以及文本均被抛弃
<a href="/profile" class="nav-link">
</a>

2、vue3插槽介绍

//子组件
<script setup>
</script><template><button><slot></slot></button>
</template>
//父组件
<script setup>
import {ref} from 'vue';
import MyButton from '@/components/MyButton.vue'
</script><template><div class="index-main"><MyButton>点击<span style="display: inline-block; width:10px; height: 10px; border-radius: 50%; background-color: #f00; margin-left: 5px;"></span></MyButton>--></div>
</template>
/*渲染结果*/
<button>点击<sapn data-v-b4e148ca="" style="display: inline-block; width: 10px; height: 10px; border-radius: 50%; background-color: rgb(255, 0, 0); margin-left: 5px;"></sapn></button>

插槽内容可以是任意合法的模板内容,不局限于文本;可以传入多个元素,甚至是组件

3、插槽渲染作用域

vue2和vue3插槽作用域须知如下:
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

/*父组件,父组件中的msg属性在父组件和子组件中均可渲染,但在MyButton子组件中无法获取msg的值,只有使用props传值后才可获取到*/
<script setup>
import {ref} from 'vue';
import MyButton from '@/components/MyButton.vue'const msg = ref('提交');
</script><template><div class="index-main"><div>{{msg}}</div><MyButton>{{msg}}</MyButton></div>
</template>

4、插槽的默认值设置

4.1、Vue2参考插槽——后备内容

/*vue2子组件设置默认值*/
<template>
<a v-bind:href="url" class="nav-link"><slot>跳转链接</slot>
</a>
</template>

4.2、Vue3参考插槽——默认内容

/*vue3子组件设置默认值*/
<script setup>
</script><template><button><slot>提交</slot></button>
</template>
/*vue3 父组件*/
<template><div class="index-main"><!-- 按钮文本为 提交 --><MyButton></MyButton><!-- 按钮文本为 立即提交 --><MyButton>立即提交</MyButton></div>
<template>

5、具名插槽

简单来说,当子组件有多个插槽时,为每个插槽设置不同名字,父组件中引用时可根据名字修改不同的插槽内容;

5.1、vue2具名插槽介绍

自 2.6.0 起有所更新。已废弃的使用 slot attribute;已废弃slot属性的用法具体请查看官网;

子组件插槽新语法:< slot>元素,此元素用油一个特殊的属性name,用name来定义额外的插槽;

一个不带 name 的 出口会带有隐含的名字“default”。

/*base-layout子组件*/
<div class="container"><header><slot name="header"></slot></header><main><slot></slot></main><footer><slot name="footer"></slot></footer>
</div>

父组件使用时:
可以在一个 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称:

注意 v-slot 只能添加在 上;只有一种特殊情况,可暂不了解;

跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header:

/*父组件*/
<base-layout><template v-slot:header><h1>Here might be a page title</h1></template><p>A paragraph for the main content.</p><p>And another one.</p><!-- 更明确的写法<template v-slot:default><p>A paragraph for the main content.</p><p>And another one.</p></template>--><template v-slot:footer><p>Here's some contact info</p></template>
</base-layout>

新语法与vue3相同,具体示例不再冗余展示;具体示例请参照vue3;将对应的props传值修改为vue2写法即可;

5.2、Vue3具名插槽介绍

子组件包含多个插槽时:
< slot> 元素可以有一个特殊的 attribute name,用来给各个插槽分配唯一的 ID;
这类带 name 的插槽被称为具名插槽 (named slots)。没有提供 name 的 出口会隐式地命名为“default”

父组件的使用介绍:
要为具名插槽传入内容,我们需要使用一个含 v-slot 指令的 < template> 元素,并将目标插槽的名字传给该指令;
v-slot 有对应的简写 #,因此 < template v-slot:left> 可以简写为 <template #left>

示例参考

/*vue3 定义一个列表组件ListChild.vue,左侧图标,右侧箭头*/
<template><div class="list-bar" title="标题"><div v-if="leftShow" class="list-left"><slot name="left"><div class="list-leftIcon"></div></slot></div><div class="list-middle"><slot>列表内容</slot></div><div v-if="rightShow" class="list-rightIcon"><slot name="right">&gt;</slot></div></div>
</template><script setup>
const props = defineProps({leftShow:{type: Boolean,default: true},rightShow:{type: Boolean,default: true}
});
</script><style scoped>.list-bar{display: flex;display: -webkit-flex;align-items: center;-webkit-align-items: center;}.list-left{margin-right: 8px;}.list-leftIcon{width: 4px;height: 4px;background: #f00;}.list-rightIcon{margin-left: 10px;}
</style>
/*父组件*/
<script setup>
import ListChild from '@/components/ListChild.vue'
</script><template><div class="index-main"><!-- 使用默认效果 --><ListChild></ListChild><!-- 修改右侧内容 --><ListChild><template v-slot:right><!-- v-sole冒号后面为插槽的name --><!--  中间为重新定义的左侧内容  --><span style="color: #999; font-size: 12px;">2023-01-01</span></template></ListChild><!-- 修改左侧及主体内容 --><ListChild><template #left><span style="color: #999; font-size: 12px;">2023-01-01</span></template><!-- 默认不带name的均为默认插槽内容,是否 --><!-- <div>主体内容修改</div> --><template #default>主体内容</template></ListChild></div>
</template>

展示效果如下:
在这里插入图片描述

5.3、具名插槽内容替换图解

在这里插入图片描述

6、Vue3条件插槽

当需要根据插槽是否存在来判断某些内容时,可以结合$slots 属性与 v-if 来实现。(vue3独有特点)

在下面的示例中,我们定义了一个卡片组件,它拥有三个条件插槽:header、footer 和 default。 当 header、footer 或 default 存在时,我们希望包装它们以提供额外的样式:

<template><div class="card"><div v-if="$slots.header" class="card-header"><slot name="header" /></div><div v-if="$slots.default" class="card-content"><slot /></div><div v-if="$slots.footer" class="card-footer"><slot name="footer" /></div></div>
</template>

7、作用域插槽

备注:自 2.6.0 起有所更新。Vue2已废弃的使用 slot-scope;vue2和vue3的语法一致;但下面的示例为VUE3的组合式写法;

在插槽的渲染作用域中我们提到,插槽的内容无法访问到子组件的状态;

但是某些场景下可能需要父组件域内和子组件域内均能访问到此数据;此时我们需要让子组件渲染时将部分数据提供给插槽,以便父组件可以获取到;

7.1、默认插槽作用域插槽的设置

实现方法:将子组件的插槽设置一个属性;
如下面ListChild.vue子组件中slot标签上的count和list属性;也可直接使用v-bind绑定对象

父组件中写法:
v-slot=“slotProps”
v-slot:default=“slotProps”
缩写:
#default=“slotProps”
解构插槽:
v-slot=“{子组件属性名}”

/*子组件ListChild.vue*/
<template><div class="list-bar"><slot :count="1" :list="listVal" v-bind="{a:1,b:2}">列表内容</slot></div>
</template>
<script setup>import { ref } from 'vue';const listVal = ref('列表主题内容');
</script>
/*父组件index.vue*/
<script setup>import { ref } from 'vue';
</script>
<template><div class="index-main"><!-- slotProps可自定义名称slotProps的值为子组件slot标签上的所有自定义属性的对象合集{ "count": 1, "list": "列表", "a": 1, "b": 2 }--><ListChild v-slot="slotProps">{{slotProps.count}}--{{slotProps.list}}--{{slotProps.a}}--{{slotProps.b}}</ListChild><!-- 使用解构赋值 --><ListChild v-slot="{count,list,a,b}">{{count}}--{{list}}--{{a}}--{{b}}</ListChild><!-- 使用解构赋值,属性名重命名 --><ListChild v-slot="{count:countCopy ,list}">{{countCopy }}--{{list}}</ListChild></div>
</template>

7.2、具名作用域插槽

具名作用域插槽的工作方式也是类似的,插槽 props 可以作为 v-slot 指令的值被访问到;

父组件中写法:
v-slot:name=“slotProps”
缩写:
#name=“slotProps”

注意插槽上的 name 是一个 Vue 特别保留的 attribute,不会作为 props 传递给插槽。因此最终 slotProps 的结果是 { “count”: 1, “list”: “列表主题内容” }

/*子组件ListChild.vue*/
<template><div class="list-bar"><slot name="label" :count="1" :list="listVal">列表内容</slot></div>
</template>
<script setup>import { ref } from 'vue';const listVal = ref('列表主题内容');
</script>
/*父组件index.vue*/
<ListChild v-slot:label="slotProps">{{slotProps}}
</ListChild>

注意要点:

  1. 当只有一个默认插槽时,可以把v-slot直接用在组件上;
  2. 默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:
  3. 只要出现多个插槽,请始终为所有的插槽使用完整的基于 的语法;

8、动态插槽名

动态指令参数在 v-slot 上也是有效的;也可简写;具体使用方法如下

/*子组件*/
<template><div class="list-bar" title="标题"><div v-if="leftShow" class="list-left"><slot name="left"><div class="list-leftIcon"></div></slot></div><div class="list-middle"><slot>列表内容</slot></div><div v-if="rightShow" class="list-rightIcon"><slot name="right">&gt;</slot></div></div>
</template>
/*父组件index.vue*/
<script setup>
import {ref} from 'vue';
const dynamicSlotName = ref('left');
setTimeout(()=>{dynamicSlotName.value = 'right';
},1000)
</script>
<template><div><ListChild :listData="listData" prop="title"><template v-slot:[dynamicSlotName]>1111</template></ListChild></div>
</template>

vue2官方文档未提及缩写写法,建议采用v-slot的写法定义动态插槽名;
Vue3可使用如下缩写写法;

/*缩写写法*/
<template #[dynamicSlotName]>1111</template>

相关文章:

  • [Go 微服务] Kratos 验证码业务
  • PHP电商系统开发指南数据库管理
  • 多线程软件不响应处理
  • JAVA 面试常见问题详解
  • 模板类内部能否含有虚函数?
  • Android动画:提升用户体验的关键技术
  • Python特征工程 — 1.4 特征归一化方法详解
  • 有什么简单方便的提取图片文字的方法?6个软件教你快速提取图片文字
  • day02-广播机制
  • 【手撕面试题】React(高频知识点一)
  • GitHub每日最火火火项目(7.2)
  • 探索迁移学习:通过实例深入理解机器学习的强大方法
  • 【MindSpore学习打卡】应用实践-计算机视觉-FCN图像语义分割-基于MindSpore实现FCN-8s进行图像语义分割的教程
  • Linux各种命令——tac命令,more 命令, less命令,head命令,tail命令,file 命令, stat 命令
  • 1.7-自然语言的分布式表示-skip-gram模型代码实现
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • CentOS 7 修改主机名
  • CSS实用技巧干货
  • DOM的那些事
  • Mysql优化
  • oschina
  • php中curl和soap方式请求服务超时问题
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 阿里云Kubernetes容器服务上体验Knative
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 关于extract.autodesk.io的一些说明
  • 爬虫模拟登陆 SegmentFault
  • 入手阿里云新服务器的部署NODE
  • 线性表及其算法(java实现)
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 关于Android全面屏虚拟导航栏的适配总结
  • 湖北分布式智能数据采集方法有哪些?
  • ​力扣解法汇总946-验证栈序列
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • #《AI中文版》V3 第 1 章 概述
  • #考研#计算机文化知识1(局域网及网络互联)
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (3) cmake编译多个cpp文件
  • (AngularJS)Angular 控制器之间通信初探
  • (delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第2节(泛型类的类构造函数)
  • (PADS学习)第二章:原理图绘制 第一部分
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (三)centos7案例实战—vmware虚拟机硬盘挂载与卸载
  • (转)scrum常见工具列表
  • (转载)虚函数剖析
  • *setTimeout实现text输入在用户停顿时才调用事件!*
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET Core中的去虚
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .net 调用php,php 调用.net com组件 --
  • .NET 中创建支持集合初始化器的类型
  • .NET(C#) Internals: as a developer, .net framework in my eyes