历史总是惊人的相似,知识总是学了忘、忘了学。
事情是这样的,我现在使用Vue开始着手做一个后台管理系统,正在我开开心心的照着视频“抄代码”的时候,项目中使用到v-slot指令使我很是懵*,明明学过的知识就是模糊不清。所以就来写一篇博客加深记忆。
一、为什么使用插槽
在生活中很多地方都有插槽,比如电脑的USB,插板的电源插座,不难理解插槽的目的就是让我们原来的设备具备扩展性。在Vue组件封装中,插槽更是必不可少的一个特性,它可以使我们的封装的组件更加的灵活。
二、插槽的基本使用
实现上面的效果时就可以使用插槽,我们发现组件最上面的内容是固定的,下面的是不一样的,所以我们可以在组件中这样定义。
<template>
<section>
<h3>固定内容</h3>
<slot></slot>
</section>
</template>
使用时只需要在组件标签中填写我们想要的信息,slot将会被自动替换掉
<template>
<div id="app">
<home>
<button>按钮</button>
</home>
<home>
<span>不固定内容</span>
</home>
<home>
<h1>biaoti</h1>
</home>
</div>
</template>
<script>
import Home from "./components/Home.vue";
export default {
components: { Home },
name: "App"
};
</script>
三、具名插槽
当我们想要向组件中替换多个内容,这时候就可以使用具名插槽。
通俗理解,具名插槽就是给插槽起个名字,我们在使用时就可以替换指定的插槽。
具体使用:
<template>
<section>
<h3>固定内容</h3>
<slot name="header"></slot>
<slot name="body"></slot>
<slot name="footer"></slot>
</section>
</template>
我们可以通过以下方式进行替换
<template>
<div id="app">
<home>
<h4 slot="header">header</h4>
<h4 slot="body">body</h4>
<h4 slot="footer">footer</h4>
</home>
</div>
</template>
<script>
import Home from "./components/Home.vue";
export default {
components: { Home },
name: "App"
};
</script>
四、作用域插槽
这个作用域比较难理解,在学懂它之前需要理解一个概念-编译作用域
1. 什么是编译作用域
首先,我们考虑下面Home组件是否可以在父组件中渲染出来
Home.vue
<template>
<section>
<h3>固定内容</h3>
<slot name="header"></slot>
<slot name="body"></slot>
<slot name="footer"></slot>
</section>
</template>
<script>
export default {
data() {
return {
isShow: false
};
}
};
</script>
App.vue
<template>
<div id="app">
<home v-show="isShow">
<h4 slot="header">header</h4>
<h4 slot="body">body</h4>
</home>
</div>
</template>
<script>
import Home from "./components/Home.vue";
export default {
data() {
return {
isShow: true
};
},
components: { Home },
name: "App"
};
</script>
结果是可以渲染出来的,官方给出的解释:“父组件所有的东西都会在父级作用域内编译,子组件所有的东西都会在子级作用域中编译”。
当我们在App.vue中使用Home.vue时,整个home组件的使用过程是相当于父组件出现的,所以home组件的作用域就是父组件,使用的属性也是父组件的属性。所以isShow使用的是App.vue实例中的属性,而不是子组件的属性。
2. 理解作用域插槽
作用域插槽就是父组件替换插槽的标签,内容有子组件来提供。
还是先来写一个案例:
子组件中包含一组数据,pLanguages:[‘javascript’,‘python’,‘Go’],在子组件中默认是列表的形式展示的,我想在父组件中以另一种方式展示这组数据
这时候可以通过在插槽上绑定一个属性拿到pLanguages的数据,为的是可以在父组件通过v-slot拿到子组件的数据,此时子组件中默认的以li的形式渲染
<template>
<section>
<ul>
<slot :data="pLanguages">
<li v-for="item in pLanguages">{{ item }}</li>
</slot>
</ul>
</section>
</template>
<script>
export default {
name: "",
data() {
return {
pLanguages: ["javascript", "python", "Go"]
};
},
methods: {}
};
</script>
<style lang="scss" scoped></style>
为了在父组件中以另外一种形式展示pLanguages中的数据,首先我们需要在父组件中定义一个template模板 ,添加v-slot属性,通过pLanguages.data拿到子组件中的数据重新展示
<template>
<div id="app">
<home>
<template v-slot="pLanguages">
<span v-for="item in pLanguages.data">{{ item }}-</span>
</template>
</home>
</div>
</template>
<script>
import Home from "./components/Home.vue";
export default {
data() {
return {};
},
components: { Home },
name: "App"
};
</script>
总结一下:作用域插槽的作用就是将子组件中的数据在父组件以另外一种方式展示出来,通过在子组件slot标签上定义的绑定属性来拿到此时子组件的数据,在父组件可以通过v-slot的指令拿到子组件的数据
五、补充说明
- 当标签内有内容时,在父组件展示不替换插槽时会以子组件标签内的默认内容作为展示
- 在使用作用域插槽时,在父组件获取子组件数据时,在vue2.5.x以下版本必须使用template模板,在vue2.5.x以上版本可以时其他标签