Vue 2.6
已经发布一段时间了,主要的更新就是slot
(插槽)。可能不少人从始至终都没用过slot
,那多是你对它不够了解,当你真正的了解它的时候,你就会知道当你封装一个可复用插件的时候它是多么的 perfect~html
代码已放到Github上。能够下载跟着练习一下。vue
咱们先看一个简单的例子:git
<!--子组件-->
<template>
<button class="custom-button">
<slot></slot>
</button>
</template>
<style>
.custom-button{
color: #fff;
background-color: #409eff;
padding: 10px 20px;
font-size: 14px;
border-radius:6px;
outline: none;
border: 1px solid #dcdfe6;
}
</style>
复制代码
<!--父组件-->
<template>
<div class="button-list">
<cus-bottom>肯定</cus-bottom>
</div>
</template>
<script>
import customButton from './customButton.vue'
export default{
components:{
'cus-bottom':customButton
}
}
</script>
复制代码
最终渲染:github
<div class="button-list">
<button class="custom-button">
肯定
</button>
</div>
复制代码
当子组件渲染的时候,<slot></slot>
将会被替换为“肯定”。slot
是不会被渲染的,它是用来接收父组件传过来的内容。bash
咱们来看一张图,我以为更容易理解插槽的概念:ide
slot
标签,组合起来就是最终的渲染。
固然上述就是最简单的slot
的使用,咱们接着往下看。ui
<slot></slot>
不只能够接受字符串,还能够接收Html模板:spa
<!--父组件-->
<div class="button-list">
<cus-bottom>
<span>肯定</span>
</cus-bottom>
</div>
复制代码
最终渲染:插件
<div class="button-list">
<button class="custom-button">
<span>肯定</span>
</button>
</div>
复制代码
还能够接收其余组件:code
<!--父组件-->
<div class="button-list">
<cus-bottom>
<!-- cus-font 图标组件 -->
<cus-font></cus-font>
<span>肯定</span>
</cus-bottom>
</div>
复制代码
咱们用例子来解释一下什么叫 编译做用域
<!--父组件-->
<template>
<div class="button-list">
<cus-bottom>{{buttonText}}</cus-bottom>
</div>
</template>
<script>
import customButton from './customButton.vue'
export default{
components:{
'cus-bottom':customButton
},
data(){
return{
buttonText:'保存'
}
}
}
</script>
复制代码
{{buttonText}}
是父组件中的编译的,因此子组件获取不到buttonText
变量,反之在子组件内编译的变量父组件也获取不到。
官网叫后备内容。我以为有点怪,这里就叫默认内容。
当咱们button
默认内容就是“肯定”:
<button class="custom-button">
<!--这里的肯定就是默认内容-->
<slot>肯定</slot>
</button>
复制代码
如今当我在一个父级组件中使用<cus-button>
而且按钮也是“肯定”的时候,就能够不提供任何内容:
<div class="button-list">
<cus-bottom></cus-bottom>
</div>
复制代码
固然若是咱们父组件里的按钮是“保存”的时候,还能够这样写
<div class="button-list">
<!--这里的保存 会替换掉子组件的默认内容-->
<cus-bottom>保存</cus-bottom>
</div>
复制代码
最终渲染:
<div class="button-list">
<button class="custom-button">
保存
</button>
</div>
复制代码
具备名字的插槽。为何要有这个东西呢?咱们在上面的例子中
slot
只有一个,因此父组件传过来的内容都被子组件惟一的slot
接收了。可是不少时候咱们须要有多个slot
来分别接收父组件传过来的 '多份' 内容。
这里咱们使用官网的例子,带有以下内容的 <base-layout>
组件:
<div class="container">
<header>
<!-- 咱们但愿把头部内容放在这里 -->
</header>
<main>
<!-- 咱们但愿把主要内容放在这里 -->
</main>
<footer>
<!-- 咱们但愿把页脚放在这里 -->
</footer>
</div>
复制代码
如今我须要三个slot
(插槽),来接收父组件传过来的三分内容。对于这样的状况,slot
元素有一个特殊的特性:name。这个特性能够用来定义额外切独立的插槽:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
复制代码
中间一个不带 name 的 slot
的插槽 会带有隐含的名字“default”。至关于<slot name="default"></slot>
。也就是说如今子组件里有三个名为:header
default
footer
的插槽。
那么如今父组件使用 <base-layout>
组件的时候须要传三分内容(都不是必须的),'header','default','footer'。这个时候就须要有个标识告诉子组件三分内容跟三个插槽如何对应上。
在向具名插槽提供内容的时候,咱们能够在一个 <template>
元素上使用 v-slot
指令,并以 v-slot
的参数的形式提供其名称:
<base-layout>
<template v-slot:header>
<h1>这是header插槽的内容</h1>
</template>
<p>这里是default插槽的内容</p>
<p>这里也是default插槽的内容</p>
<template v-slot:footer>
<p>这是footer插槽的内容</p>
</template>
</base-layout>
复制代码
v-slot
:后面就是子组件对应的slot
的name
。由于子组件main标签里的slot
没有name
,默认name = default
,因此还能够这样写
<base-layout>
<template v-slot:header>
<h1>这是header插槽的内容</h1>
</template>
<template v-slot:default>
<p>这里是default插槽的内容</p>
<p>这里也是default插槽的内容</p>
</template>
<template v-slot:footer>
<p>这是footer插槽的内容</p>
</template>
</base-layout>
复制代码
最终渲染:
<div class="container">
<header>
<h1>这是header插槽的内容</h1>
</header>
<main>
<p>这里是default插槽的内容</p>
<p>这里也是default插槽的内容</p>
</main>
<footer>
<p>这是footer插槽的内容</p>
</footer>
</div>
复制代码
跟 v-on
和 v-bind
同样,v-slot
也有缩写,即把参数以前的全部内容 (v-slot:
) 替换为字符 #
。例如 v-slot:header
能够被重写为 #header
:
<base-layout>
<template #header>
<h1>这是header插槽的内容</h1>
</template>
<template #default>
<p>这里是default插槽的内容</p>
<p>这里也是default插槽的内容</p>
</template>
<template #footer>
<p>这是footer插槽的内容</p>
</template>
</base-layout>
复制代码
这里讲做用域插槽我以为叫插槽传值更贴切。
例如,设想一个带有以下模板的 <current-user>
组件:
<template>
<span>
<slot>{{ userInfo.name }}</slot>
</span>
</template>
<script>
export default{
data(){
return{
userInfo:{
name:'erdong',
sex:'boy',
age:'26'
}
}
}
}
</script>
复制代码
包括当前用户的全部信息。插槽的默认内容是name。当咱们使用 <current-user>
组件时:
父组件:
<current-user></current-user>
复制代码
最终渲染:
<span>
erdong
</span>
复制代码
可是我想让父组件里显示sex
该怎么办呢?很简单,改变子组件的插槽的默认内容:
<span>
<slot>{{ userInfo.sex }}</slot>
</span>
复制代码
可是这样达不到咱们封装组件的特性:可复用性。
若是说父组件能拿到子组件里的infoData
的值,那咱们就能够这样写:
<!--父组件-->
<current-user>
{{infoData.sex}}
</current-user>
复制代码
这样就能覆盖子组件里的默认内容。可是咱们在上面提到了 编译做用域 父组件是取不到子组件的变量的。
想让父组件取到infoData
该怎么办呢?
这个时候咱们须要更改子组件:
<!--子组件-->
<span>
<slot v-bind:userInfo="userInfo" name='user'>{{ userInfo.sex }}</slot>
</span>
复制代码
父组件:
<current-user>
<template v-slot:user="infoData">
{{infoData.userInfo.sex}}
</template>
</current-user>
复制代码
最终渲染:
<span>
boy
</span>
复制代码
子组件v-bind:userInfo="userInfo" name='user'
第一个userInfo
是传给父组件的变量名称,第二个userInfo
是传给父组件的值。name
就是该slot
的名称
父组件v-slot:user="infoData"
user
就是对应子组件的slot
的name
,infoData
就是接收该slot
传过来的值的集合的变量名称。为何叫集合呢?由于子组件一个slot能够传多个值:
<!--子组件-->
<template>
<span>
<slot v-bind:userInfo="userInfo" v-bind:address='address' name='user'>{{ userInfo.name }}</slot>
</span>
</template>
<script>
export default{
data(){
return{
userInfo:{
name:'erdong',
sex:'boy',
age:'26'
},
address:{
city:'上海市',
}
}
}
}
</script>
复制代码
<!--父组件-->
<current-user>
<template v-slot:user="infoData">
{{infoData.userInfo.sex}}{{infoData.address.city}}
</template>
</current-user>
复制代码
最终渲染:
<span>
boy上海市
</span>
复制代码
<!--父组件-->
<current-user>
<template v-slot:user="infoData">
{{infoData.userInfo.sex}}{{infoData.address.city}}
</template>
</current-user>
复制代码
上面提到了 infoData
是子组件名为user
的插槽传过来的值得集合。 即:
infoData = {
userInfo:{
name:'erdong',
sex:'boy',
age:'26'
},
address:{
city:'上海市',
}
}
复制代码
因此咱们能够用ES6的语法来解构它:
<!--父组件-->
<current-user>
<template v-slot:user="{userInfo,address}">
{{userInfo.sex}}{{address.city}}
</template>
</current-user>
复制代码
到这里咱们基本上就把Vue
的slot
(插槽)使用过了一遍,还有一些没有提到,可是若是这些你所有学会的话,能够说你已经掌握了slot
的使用。若是报错请查看你的Vue.js版本是不是2.6.x。
在上面咱们用封装button的例子来说slot的基本用法。有兴趣的同窗能够完善一下。封装一个相似于element UI
的button
组件。能够留着本身项目使用。