vue-learning:29 - component - 组件三大API之三:slot
组件三大API之三: slot
<slot>标签v-slot指令- 普通插槽
- 有默认值的插槽
- 具名插槽
- 作用域插槽
v-slot是Vue 2.6.0引入的一个新语法指令,目的是统一之前slot / slot-scope的用法。统一的指令语法更简洁也更易理解。
之前讲解的prop实现了组件向下的数据传递,而event中v-on / $emit可以实现组件向上的数据传递。这一节v-slot指令实现组件内容的自定义功能。
一个简单的例子,自定义一个按钮组件:
<div id="app">
<p>this is example for slot</p>
<custom-button></custom-button>
</div
const customButton = Vue.extend({
template: `<button>提交</button>`,
})
const vm = new Vue({
el: "#app",
components: {
customButton,
},
})
此时这个自定义按钮注定是一个提交按钮,因为我们把按钮上的文字固定写死了”提交“。如果我们需要根据按钮使用的场景不同,显示不同的文字,比如可以是提交、删除、确认、返回等。此时我们就可以使用组件<slot>标签,它相当于组件里面内容的占位符。
普通插槽
上面的例子我们只需要在组件定义时,在按钮文字的地方用<slot><slot>标签代表即可
const customButton = Vue.extend({
template: `<button>
<slot></slot>
</button>`,
})
然后在使用组件时提供提供内容即可
<div id="app">
<p>this is example for slot</p>
<custom-button>提交</custom-button>
<custom-button>删除</custom-button>
<custom-button>返回</custom-button>
</div
此时自定义按钮上要显示什么文字完成由组件使用时决定,而不是组件定义时决定。
有默认值的插槽
需求升级,我们希望组件在调用时没有写入文字时,默认显示”确认“。此时可以在组件<slot>标签定义时提供一个内容文字,将作用为组件内容缺省时的显示。
const customButton = Vue.extend({
template: `<button>
<slot>确认</slot>
</button>`,
})
div id="app">
<p>this is example for slot</p>
<!-- 有输入内容显示输入的内容:提交 -->
<custom-button>提交</custom-button>
<!-- 没有输入内容时默认显示定义时文字:确认 -->
<custom-button></custom-button>
</div
具名插槽
上面自定义按钮组件只提供了一个占位插槽,但需要抽象为组件的内容各式各样,比如一个段落内容组件,包括自定义标题、段落正文、写作时间三部分。按分析这个组件至少得分三部分,而且三部分的内容也只有在组件使用时才知道输入什么。
所以我们定义组件时,提供三个占位插槽,一个是用于标题、一个用于显示时间,其它内容都作为正文
const customSection = Vue.extend({
template: `<section>
<header>
<slot name="title"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="time"></slot>
<footer>
</section>`,
})
<custom-section>
<template v-slot:title>段落标题</template>
<template>这是段落正文部分,内容很长,这里就省略了......</template>
<template v-slot:time>2019-5-26</template>
</custom-section>
语法很简单:
- 组件定义时:
<slot>标签的时候指定一个name属性值即可 - 组件使用时,
<template>标签中用v-slot指令参数指明具体的名称,表示当前模板内容用于哪个占位符的slot即可。
在拥有多个具名插槽时,组件调用时写入插槽的内容需要用
<template>标签包裹
未命名的默认插槽,有一个内部自带的名称default
<!-- 定义时 -->
<main><slot></slot></main>
<main><slot name="defalut"></slot></main>
<!-- 使用时 -->
<template>这是段落正文部分,内容很长,这里就省略了......</template>
<template v-slot:default>这是段落正文部分,内容很长,这里就省略了......</template>
动态选择插槽
子组件内可以定义多组插槽,外部引用时根据条件决定显示调用哪个具名插槽,相当于一个switch语句。
<div id="app">
<button @click="changeSlot">点击切换slot</button>
<custom-section>
<template v-slot:[variable]>改变了插槽</template>
</custom-section>
</div>
const customSection = Vue.extend({
template: `<article>
<slot name="js">this is content for js</slot>
<slot name="html">this is content for html</slot>
<slot name="css">this is content for css</slot>
</article>`,
})
const vm = new Vue({
el: "#app",
components: {
customSection
},
data: {
index: 0,
arr: ['html', 'css', 'js'],
variable: 'html'
},
methods: {
changeSlot() {
this.variable = this.arr[++this.index % 3]
}
}
})
作用域插槽
这里有一个域的概念,在官方文档中有一句话:
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
简单来说:
插槽内容虽然被子组件标签包裹,但实际上插槽跟子组件标签一样都属性于父级模板作用域。可以直接引用父组件作用域内的数据。但却不能直接引用子模板作用域内的数据。
const customSection = Vue.extend({
template: `<section>
<header>
<slot name="title"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="time"></slot>
<footer>
</section>`,
data:() => {
return {
innerTitle: '写在子级的标题'
}
}
})
const vm = new Vue({
el: "#app",
data: {
outerTitle: '写在父级的标题'
},
components: {
customSection,
},
})
上面代码,我们在根组件vm中定义了标题outerTitle: '写在父级的标题',也在子组件custom-section定义了标题innerTitle: '写在子级的标题'。
<div id="app">
<p>这里可以直接引用父级标题:{{ outerTitle }}</p>
<custom-section>
<!-- 在插槽模板内也可以使用父级作用域内的数据的 -->
<template v-slot:title>{{ outerTitle }}</template>
<!-- <template v-slot:title>段落标题</template> -->
<template>这是段落正文部分,内容很长,这里就省略了......</template>
<template v-slot:time>2019-5-26</template>
</custom-section>
</div>
<div id="app">
<p>这里是肯定不可以直接引用子级标题:{{ innerTitle }}</p>
<custom-section>
<!-- 在插槽也不能直接引用子组件内的数据,控制台会报错!!! -->
<template v-slot:title>{{ innerTitle }}</template>
<!-- <template v-slot:title>段落标题</template> -->
<template>这是段落正文部分,内容很长,这里就省略了......</template>
<template v-slot:time>2019-5-26</template>
</custom-section>
</div>
但插槽的内容最终是显示在子组件中的,所以很多时候需要用子组件内部的数据来进行操作。此时就需要在定义插槽时将子组件内的数据向上传递,让调用插槽时可以使用。
const customSection = Vue.extend({
template: `<section>
<header>
// <slot name="title"></slot>
<slot name="title" :title="innerTitle"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="time"></slot>
</footer>
</section>`,
data:() => {
return {
innerTitle: '写在子级的标题'
}
}
})
<div id="app">
<p>这里可以直接引用父级标题:{{ outerTitle }}</p>
<custom-section>
<!-- <template v-slot:title>段落标题</template> -->
<template v-slot:title="slotProp">{{ slotProp.title }}</template>
<template>这是段落正文部分,内容很长,这里就省略了......</template>
<template v-slot:time>2019-5-26</template>
</custom-section>
</div>
看到,在定义时<slot>标签内使用v-bind绑定子组件内需要传递的值
<slot name="title" :title="innerTitle"></slot>
在插槽调用时,通过v-slot的值来的接收后就可以使用了。
<template v-slot:title="slotProp">{{ slotProp.title }}</template>
并且v-slot的值接收过来是一个对象形式,定义时v-bind可以绑定多个,在v-slot的值中以键值对接收,使用时对象打点调用。
<slot name="title" :title="innerTitle" :author="author"></slot>
<template v-slot:title="slotProp">{{ slotProp.title + '-' + slotProp.author }}</template>
插槽prop的解构
当然如果不想使用对象打点调用的方式,也可以使用ES6对象解构的语法调用。
<slot name="title" :title="innerTitle" :author="author"></slot>
<template v-slot:title="{ title, author }">{{ title + '-' + author }}</template>
插槽prop的重命名
如果传递上来的prop可能跟父级作用域引用的变量重名,可以在解构时重命名
<slot name="title" :title="innerTitle" :author="author"></slot>
<template v-slot:title="{ title, author:writer }">{{ title + '-' + writer }}</template>
插槽prop的默认值
也可以写一个默认内容,避免接收的prop是undefined情况
<slot name="title" :title="innerTitle" :author="author"></slot>
<template v-slot:title="{ title, author='anonymity'}">{{ title + '-' + author }}</template>
插槽prop的就是函数参数
在官方文档中说明,插槽内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里,所以ES6函数参数的新语法都可以使用,如解构、参数默认值等
function (slotProps) {}
function ({title, author}) {}
function ({title, author=anonymity}) {
// 插槽内容
}
v-slot的简写#
跟v-bind简写成:,v-on简写成@一样,v-slot简写@
当采用简写#后面必须接一个插槽名称,当#绑定默认插槽时,需要写成#default
// 可以
<template v-slot="slotProp"></template>
// 错误
<template #="slotProp"></template>
// 改成
<template #defalut="slotProp"></template>
独占默认插槽时,v-slot可以绑定在子组件标签上,省略template
<div id="app">
<p>this is example for slot</p>
<custom-button v-slot={type}>{{ type ? '确定' : '删除'}}</custom-button>
<custom-button #default={type}>{{ !type ? '确定' : '删除'}}</custom-button>
</div
const customButton = Vue.extend({
template: `<button><slot :type="btnType"></slot></button>`,
data() => {
return {
btnType: 1, // 1 确定 0 删除
}
}
})
const vm = new Vue({
el: "#app",
components: {
customButton,
},
})
总结
v-slot:slotName="slotProp"
#:slotName="slotProp"
vue-learning:29 - component - 组件三大API之三:slot的更多相关文章
- vue-learning:26 - component - 组件三大API之一:prop
组件三大API之一: prop prop的大小写 prop接收类型 字符串数组形式 对象形式: type / required / default / validator prop传递类型: 静态传递 ...
- vue-learning:27 - component - 组件三大API之二:event
组件三大API之二: event 在上一节中讲到prop单向下行数据绑定的特征,父组件向子组件传值通过prop实现,那如果有子组件需要向父组件传值或其它通信请求,可以通过vue的事件监听系统(触发事件 ...
- Vue Login Form Component
Vue Login Form Component Account Login <template> <div> <slot></slot> <el ...
- 第六章 组件 59 组件切换-使用Vue提供的component元素实现组件切换
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- Vue.js——60分钟组件快速入门(下篇)
概述 上一篇我们重点介绍了组件的创建.注册和使用,熟练这几个步骤将有助于深入组件的开发.另外,在子组件中定义props,可以让父组件的数据传递下来,这就好比子组件告诉父组件:"嘿,老哥,我开 ...
- Vue.js——60分钟组件快速入门
一.组件简介 组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树: 那么什么是组件呢?组件可以扩展HT ...
- Vue.js——60分钟组件快速入门(下篇)
转自:https://www.cnblogs.com/keepfool/p/5637834.html 概述 上一篇我们重点介绍了组件的创建.注册和使用,熟练这几个步骤将有助于深入组件的开发.另外,在子 ...
- Vue:Vue的介绍以及组件剖析
介绍 现在,随着基于JavaScript的单页应用程序(SPA)和服务器端渲染(SSR)的兴起,可以用JavaScript编写整个前端应用程序,并整洁地管理和维护该应用程序的前端代码.诸如Angula ...
- Vue 引出声明周期 && 组件的基本使用
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8" /> 5 & ...
随机推荐
- Directx11教程(62) tessellation学习(4)
原文:Directx11教程(62) tessellation学习(4) 现在看看四边形在不同tess factor时,四边形细分的细节,下图是tess factor1-8时候的细分.te ...
- Directx11教程(19) 画一个简单的地形
原文:Directx11教程(19) 画一个简单的地形 通常我们在xz平面定义一个二维的网格,然后y的值根据一定的函数计算得到,比如正弦.余弦函数的组合等等,可以得到一个看似不错的地形或者 ...
- oracle Transactional
从shutdown transactional命令发布起, 禁止建立任何新的oracle连接. 从shutdown transactional命令发布起,禁止启动任何新的事务. 一旦数据库上所有的活动 ...
- 探索云数据库最佳实践 阿里云开发者大会数据库专场邀你一起Code up!
盛夏.魔都.科技 三者在一起有什么惊喜? 7月24日,阿里云峰会·上海——开发者大会将在上海世博中心盛大启程,与未来世界的开发者们分享数据库.云原生.开源大数据等领域的技术干货,共同探讨前沿科技趋势, ...
- JavaScript--天猫数量输入框
<!DOCTYPE html> <head> <meta charset="utf-8" /> <title>无标题文档</t ...
- JAVA高级--异常处理概念和异常处理机制
什么是异常 程序运行的过程中发生的一些不正常事件 异常分类 Throwable Error 错误 Exception IOException RuntimeException ...
- zabbix3.4.x添加短信报警
一.修改zabbix_server.conf #vi /etc/zabbix/zabbix_server.conf 去掉注释: ### Option: AlertScriptsPath # Full ...
- 亚洲唯一,阿里云SLB位列Gartner全球网络负载均衡市场前五
近日,Gartner发布了最新的全球企业级网络设备市场份额报告“Market Share: Enterprise Network Equipment by Market Segment, Worldw ...
- 阿里云oss上传图片报错,The OSS Access Key Id you provided does not exist in our records.解决方法
vue项目 1.安装OSS的Node SDK npm install ali-oss --save 2.参考官方提示https://help.aliyun.com/document_detail/11 ...
- 15-8 pymysql的使用
一 安装pymysql模块 1 pycharm安装 file-setting如图:然后点加号,搜索pymsql即可,点击安装 2 pip 安装 pip3 install pymysql 二 连接数据 ...