[TOC]
为什么使用slot?
- slot翻译为插槽
- 生活中很多地方都有插槽:电脑的USB插槽,插板中的电源插槽
- 插槽的目的是让我们原来的设备具备更多的扩展性
- 比如电脑的USB让我们可以插入U盘,硬盘,手机,音响,键盘,鼠标等
- 组件的插槽
- 组件的插槽也是为了让我们封装的组件更加具有扩展性
- 让使用者可以决定组件内部的一些内容到底展示什么
基本使用
- 我们可以添加一个slot标签,相当于是一个预留位置,我们可以在这个位置添加我们个性化的东西
- 比如:比如我们移动开发中,几乎每一个页面都有导航栏,导航栏我们必然会封装成一个组件,比如nav-bar组件,这个组件多个页面都要使用,它们结构相同,但是内容却不同,我们就需要用插槽的思想去封装这个组件
- 如何封装呢?抽取共性,保留不同
- 最好的封装方式就是将共性抽取到组件中,将不同暴露为插槽
- 一旦我们预留了插槽,就可以人让使用者根据自己的需求,决定插槽中插入什么内容(是搜索框,还是文字,还是菜单,由调用者自己来决定) ```html
我是组件
哈哈哈哈哈哈哈
- slot插槽的使用方式:首先在组件模板中写一个slot标签`<slot></slot>`,然后我们在使用该组件时,在组件标签内容区域写的内容`<cpn><button>按钮</button></cpn>`就会被当作slot中的内容传入到组件模板中的slot标签中去,这时就可以自定义我们插槽中要显示的内容了
- 如果每次使用组件时,多个地方都需要使用某个标签,只有个别地方使用别的标签,这时我们还可以给slot标签一个默认值,注意,这个默认值是写在slot插槽中的`<slot><button>按钮</button></slot>`,这时,使用该组件时,如果`<cpn></cpn>`中没有传入新东西,就默认显示slot标签中存在的button按钮,如果传入了新内容,那么就显示指定的内容
- 如果`<cpn>这里有很多标签</cpn>`,而且只有一个插槽的情况下,会将所有内容都放进插槽中的
<a name="JF7Cr"></a>
## 具名插槽
- 如果我们组件模板中有三个slot,而我们使用组件时,传入了一个标签,我们希望替换掉中的插槽,如果我们直接使用`<cpn><button>按钮</button></cpn>`这种方式,其实会替换掉三个插槽中的内容的
- 如果想要准确替换某一个插槽中的内容,就需要给插槽起名字,如果想要替换掉有名字的slot,就需要在使用时,给要替换的标签写上slot属性`<cpn><button slot="center">按钮</button></cpn>`
```html
<div id="app">
<cpn><button slot="center">按钮</button><button slot="left">返回</button></cpn>
</div>
<template id="cpn">
<div>
<slot name="left"><span style="border:1px solid #000;">left</span></slot>
<slot name="center"><span style="border:1px solid #000;">center</span></slot>
<slot name="right"><span style="border:1px solid #000;">right</span></slot>
</div>
</template>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello'
},
components: {
cpn: {
template: '#cpn'
}
}
})
</script>
编译作用域
- 在学习作用域插槽之前,我们需要先理解一个概念:编译作用域
- 如果我们在app实例中定义一个变量,isShow:true,在cpn组件中定义一个变量isShow:false,我们在id为app的div中使用时,他显示的是true。
- 这就说明:在使用变量时,只会在当前的编译作用域中寻找,每个组件和Vue实例都是要给封闭的环境,都有自己的作用域,不能跨作用域去使用变量
- 官方说明: 父组件模板的所有东西都会在父级作用域内编译,子组件模板的所有东西都会在子级作用域内编译
- 我们在使用
<cpn v-show="isShow"></cpn>时,整个组件的使用过程相当于在父组件中出现的,那么它的作用域就是父组件,使用的属性也是属于父组件的属性,因此,isShow使用的是Vue实例中的属性,而不是子组件中的属性 ```html
我是子组件
我是内容
<a name="1B3kt"></a>
## 作用域插槽
- 作用域插槽slot是一个比较难理解的一个点,用一句话做一个总结:
- 父组件替换插槽的标签,但是内容由子组件来提供
- 需求:子组件中包括一组数据:['JavaScript','Python','Swift','Go','C++']
- 需要在多个界面进行展示:某些界面是水平方向展示,某些界面是列表形式展示的,某些界面直接展示一个数组
- 内容在子组件,但是希望父组件告诉我们如何展示,要如何做呢?使用slot作用域插槽
```html
<div id="app">
<cpn></cpn>
<cpn>
<!-- 注意,这种使用是到不到效果的,此时我们是想要在父组件中使用子组件中的数据,这时是拿不到的!想办法传过去 -->
<span v-for="item in languages">{{item}}</span>
</cpn>
<cpn>
<!-- 这时就可以使用slot中的绑定到data上的数据了,2.5版本以下必须使用template,以上就可以使用其他标签了 -->
<template slot-scope="slot">
<!-- 这里的slot.data其实就是我们子组件中的data上绑定的值,也就是子组件languages中的值 -->
<span>{{slot.data.join('---')}}</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- 注意这里:data是随便写的,相当于当languages的数据绑定到了data上 -->
<slot :data="languages">
<ul>
<li v-for="item in languages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script>
const app = new Vue({
el: '#app',
data: {
},
components: {
cpn: {
template: '#cpn',
data () {
return {
languages:['JavaScript', 'C++', 'Java', 'C#', 'Python', 'go', 'Swift']
}
}
}
}
})
</script>
