在真正学习插槽之前,我们需要先理解一个概念:编译作用域。
官方对于编译的作用域解析比较简单,我们自己来通过一个例子来理解这个概念:
我们来考虑下面的代码是否最终是可以渲染出来的:
中,我们使用了isShow
属性。isShow
属性包含在组件中,也包含在Vue实例中。<div id="app">
<!-- 此时的isshow使用的是app实例里面的,-->
<cpn v-show="isShow"></cpn>
</div>
<template id="cpn">
<div>
<h2>我是组件哈哈</h2>
<p>hahahaaha</p>
<button v-show="isShow">按钮</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊',
isShow: true
},
components: {
cpn: {
template: '#cpn',
},
data() {
return {
isShow: true
}
}
}
})
</script>
答案:最终可以渲染出来,也就是使用的是Vue实例的属性。
为什么呢?
的时候,整个组件的使用过程是相当于在父组件中出现的。slot翻译为插槽:
组件的插槽:
栗子:移动网站中的导航栏。
但是,每个页面的导航是一样的吗?No,我以京东M站为例
如何去封装这类的组件呢?
如何封装合适呢?抽取共性,保留不同。
这就是为什么我们要学习组件中的插槽slot的原因。
了解了为什么用slot,我们再来谈谈如何使用slot?
就可以为子组件开启一个插槽。我们通过一个简单的例子,来给子组件定义一个插槽:
中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容详情看下面代码:
<div id="app">
<cpn></cpn>
<cpn><span>哈哈</span></cpn>
<cpn><i>喝喝喝</i></cpn>
<cpn>
<!-- 三个标签会被一起替换掉-->
<i>呵呵</i>
<div>我是dic元素与</div>
<p>我时p元素</p>
</cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>我是组件哈哈</h2>
<p>hahahaaha</p>
<!-- <button></button>-->
<!-- //预备一个插槽,使可以通过插槽在以后增加组件的内容-->
<!-- <slot></slot>-->
<!-- 给定默认值-->
<slot><button>按钮</button></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn',
}
}
})
</script>
当子组件的功能复杂时,子组件的插槽可能并非是一个。
如何使用具名插槽呢?
我们来给出一个案例:
<div id="app">
<!-- 具有多个插槽准确找到其中之一,需要取名字-->
<cpn><span slot="mid">修改中间</span></cpn>
<cpn><span slot="right">修改右边</span></cpn>
</div>
<template id="cpn">
<div>
<h2>我是组件哈哈</h2>
<p>hahahaaha</p>
<!-- <button></button>-->
<!-- //预备一个插槽,使可以通过插槽在以后增加组件的内容-->
<!-- <slot></slot>-->
<!-- 给定默认值-->
<slot name="left"><sapn>左边</sapn></slot>
<slot name="mid"><sapn>中间</sapn></slot>
<slot name="right"><sapn>右边</sapn></slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn',
}
}
})
</script>
作用域插槽是slot一个比较难理解的点,而且官方文档说的又有点不清晰。
这里,我们用一句话对其做一个总结,然后我们在后续的案例中来体会:
我们先提一个需求:
pLanguages: ['JavaScript', 'Python', 'Swift', 'Go', 'C++']
我们来看看子组件的定义:
components: {
cpn: {
template: '#cpn',
data() {
return {
planguages: ['javascript', 'c++', 'java','c', 'c#', 'python']
}
},
}
在父组件使用我们的子组件时,从子组件中拿到数据:
获取到slotProps
属性slotProps.data
就可以获取到刚才我们传入的data
了<!--利用作用域插槽修改子组件在父组件中的展示方式-->
<div id="app">
<cpn></cpn>
<cpn>
<!-- 目的是和获取子组件中的planguage-->
<!-- 2.5之前利用template,之后利用div也可以,去获取planguages-->
<template slot-scope="slot">
<!-- <span v-for="item in slot.data">{
{
item}}-</span>-->
<span>{
{
slot.data.join('-')}}</span>
</template>
</cpn>
<cpn>
<template slot-scope="slot">
<span v-for="item in slot.data">{
{
item}}*</span>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- data为随意取名,利用data去直接获取planguages-->
<slot :data="planguages">
<ul>
<li v-for="item in planguages">{
{
item}}</li>
</ul>
</slot>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn',
data() {
return {
planguages: ['javascript', 'c++', 'java','c', 'c#', 'python']
}
},
methods: {
created() {
// this.planguages.join('-');
}
}
}
}
})
</script>