组件三大API之三: slot

  • <slot>标签
  • v-slot指令
  • 普通插槽
  • 有默认值的插槽
  • 具名插槽
  • 作用域插槽

v-slotVue 2.6.0引入的一个新语法指令,目的是统一之前slot / slot-scope的用法。统一的指令语法更简洁也更易理解。

之前讲解的prop实现了组件向下的数据传递,而eventv-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的更多相关文章

  1. vue-learning:26 - component - 组件三大API之一:prop

    组件三大API之一: prop prop的大小写 prop接收类型 字符串数组形式 对象形式: type / required / default / validator prop传递类型: 静态传递 ...

  2. vue-learning:27 - component - 组件三大API之二:event

    组件三大API之二: event 在上一节中讲到prop单向下行数据绑定的特征,父组件向子组件传值通过prop实现,那如果有子组件需要向父组件传值或其它通信请求,可以通过vue的事件监听系统(触发事件 ...

  3. Vue Login Form Component

    Vue Login Form Component Account Login <template> <div> <slot></slot> <el ...

  4. 第六章 组件 59 组件切换-使用Vue提供的component元素实现组件切换

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  5. Vue.js——60分钟组件快速入门(下篇)

    概述 上一篇我们重点介绍了组件的创建.注册和使用,熟练这几个步骤将有助于深入组件的开发.另外,在子组件中定义props,可以让父组件的数据传递下来,这就好比子组件告诉父组件:"嘿,老哥,我开 ...

  6. Vue.js——60分钟组件快速入门

    一.组件简介 组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树: 那么什么是组件呢?组件可以扩展HT ...

  7. Vue.js——60分钟组件快速入门(下篇)

    转自:https://www.cnblogs.com/keepfool/p/5637834.html 概述 上一篇我们重点介绍了组件的创建.注册和使用,熟练这几个步骤将有助于深入组件的开发.另外,在子 ...

  8. Vue:Vue的介绍以及组件剖析

    介绍 现在,随着基于JavaScript的单页应用程序(SPA)和服务器端渲染(SSR)的兴起,可以用JavaScript编写整个前端应用程序,并整洁地管理和维护该应用程序的前端代码.诸如Angula ...

  9. Vue 引出声明周期 && 组件的基本使用

    1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8" /> 5 & ...

随机推荐

  1. HTML 5适合小公司,适合在大平台上做内容

    Web App,现在有时候也称为轻应用,不仅是通过浏览器就能打开的应用.现在随着 HTML 5 在手机端的优越性,已经慢慢称为了 Web App 的主流.Web App 除了出现在 PC 的浏览器中, ...

  2. PB 级数据处理挑战,Kubernetes如何助力基因分析?

    摘要: 一家大型基因测序功能公司每日会产生 10TB 到 100TB 的下机数据,大数据生信分析平台需要达到 PB 级别的数据处理能力.这背后是生物科技和计算机科技的双向支撑:测序应用从科研逐步走向临 ...

  3. C89标准库函数手册

    http://zh.cppreference.com/w/c 前言 ANSI C(C89)标准库函数共有15个头文件.这15个头文件分别为: 1.<assert.h>            ...

  4. 【Leetcode堆和双端队列】滑动窗口最大值(239)

    题目 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 示例: 输入 ...

  5. 小爬爬1:jupyter简单使用&&爬虫相关概念

    1.jupyter的基本使用方式 两种模式:code和markdown (1)code模式可以直接编写py代码 (2)markdown可以直接进行样式的指定 (3)双击可以重新进行编辑 (4)快捷键总 ...

  6. 你在用 JWT 代替 Session?

    现在,JSON Web Tokens (JWT) 是非常流行的.尤其是 Web 开发领域. 流行 安全 稳定 易用 支持 JSON 所有这些因素,令 JWT 名声大振. 但是,今天我要来说说使用 JW ...

  7. 【NS2】WiMAX_NS2说明文档(转载)

    关于目前NS2中WiMAX模块的说明 (1)美国NIST(National Institute of Standards and Technology)版, 可以从NIST主页获得,2007.04 r ...

  8. Android学习:导入工程时报错The import android cannot be resolved

    今天在导入别人的工程时,出现了一个这个问题The import android cannot be resolved 就是找不到import android.support.v7.app.Action ...

  9. SGU 103 Traffic Lights【最短路】

    题目链接: http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=16530 题意: 给定每个点最初的颜色,最初颜色持续时间,以 ...

  10. 中断源记录 INT0 INT1

    中断源记录 INT0 INT1 用到一个单片机 使用的 P3.1 P3.3 作为唤醒口,后来发一 P3.1 和 P3.3 使用的同一个中断 INT1,这个尴尬了,只能两选 一. 查看规格书,还好 P3 ...