vue2.x之插槽
1. 什么是插槽
插槽通俗地讲就是在封装组件的时候,对不确定部分的内容的一种占位。这个展位用slot标签表示,然后在具体使用过程中根据实际内容将其放在这个slot标签的位置。
<template> <div class="slot-wrapper"> <div class="titler-wrapper">{{title}}</div> <slot></slot> //❗️这部分就是用于不确定部分的占位,由外界决定显示内容 </div> </template>
⚠️ 注意: 只有在组件中使用了slot标签占位之后,组件标签之间的内容才能被渲染,否则是会被抛弃的
2. 插槽的编译作用域
插槽里面的内容是父组件根据自身的实际情况来定义的,是属于父组件作用域的,而子组件是属于子组件作用域的。它们之间是不能直接访问的。
⏰ 子组件
<template> <div class="slot-wrapper"> <div class="titler-wrapper">{{title}}</div> <slot></slot> //插槽 </div> </template>
⏰ 父组件
<template> <div class="hello"> <testSlot title="电影分类"> <span>{{title}}</span> //这部分就是父组件根据自身的实际情况来定义的,子组件插槽位置的内容 </testSlot> </div> </template>
此时这样是获取不到title的, 页面会报错。
3. 组件的分类
我们在使用插槽的时候,主要可以分为三类:默认插槽,具名插槽,作用域插槽
默认插槽
默认插槽很简单,就是子组件中写了一个slot标签,那么在父组件中子组件中间的所有内容都是默认插槽的内容。
<template> <div class="slot-wrapper"> <div class="titler-wrapper">{{title}}</div> <slot>好听的歌曲</slot> </div> </template> <script> export default { name: 'testSlot', props: ['title'], data() { return { } } } </script> <style lang="css" scoped> .slot-wrapper { width: 200px; height: 500px; border: 1px solid #999; border-radius: 4px; } .titler-wrapper { width: 100%; height: 40px; line-height: 40px; background-color: aquamarine; text-align: center; } </style>
👀 像上面这种,slot标签上没有任何属性,那么这个插槽就是默认插槽,组件中只能有一个默认插槽
⏰ 1. 后备内容
<template> <div class="hello"> <testSlot :title="title"> </testSlot> //虽然定义了默认插槽,但是此时<testSlot> '填写内容区域' </testSlot> 没有填写任何内容 </div> </template> <script> import testSlot from './testSlot.vue'; export default { name: 'HelloWorld', components: { testSlot }, data() { return { title: '电影分类' } }, methods: { } } </script> <style scoped> </style>
如果父组件不传插槽的内容,那么就默认展示后备内容(意思就是说原先插槽里面,写了啥就显示啥,因为你父组件没定义插槽里面的内容,我只能显示原本默认的了)
⏰ 2. 展示配置的插槽内容
<template> <div class="hello"> <testSlot :title="title"> <!--以下都是父组件自定义的插槽里面的内容-->> <div>经典歌曲</div> <div>流行歌曲</div> <div>排行歌曲</div> <div>热门歌曲</div> </testSlot> </div> </template> <script> import testSlot from './testSlot.vue'; export default { name: 'HelloWorld', components: { testSlot }, data() { return { title: '电影分类' } }, methods: { } } </script> <style scoped> </style>
如果父组件自定义了插槽的内容,那么就默认展示后备内容就将被父组件自定义的内容所覆盖
具名插槽
当组件中需要根据结构区分很多插槽时,需要给每个插槽命一个名,这时就有了具名插槽
👀 一个插槽不够用了,我要用多个,怎么区分这多个插槽呢? 这就需要这多个插槽取个名字了!
<template> <div class="slot-wrapper"> <div class="titler-wrapper">{{title}}</div> <slot name="center"></slot> <slot name="footer"></slot> </div> </template> <script> export default { name: 'testSlot', props: ['title'], data() { return { } } } </script> <style lang="css" scoped> .slot-wrapper { width: 200px; height: 500px; border: 1px solid #999; border-radius: 4px; } .titler-wrapper { width: 100%; height: 40px; line-height: 40px; background-color: aquamarine; text-align: center; } </style>
⏰ 废弃写法
<template> <div class="hello"> <testSlot :title="title"> <div slot="center"> <div>经典歌曲</div> <div>流行歌曲</div> <div>排行歌曲</div> <div>热门歌曲</div> </div> <div slot="footer">更多好听音乐请关注公众号</div> </testSlot> </div> </template> <script> import testSlot from './testSlot.vue'; export default { name: 'HelloWorld', components: { testSlot }, data() { return { title: '电影分类' } }, methods: { } } </script> <style scoped> </style>
⏰ 最新写法
<template> <div class="hello"> <testSlot :title="title"> <template v-slot:center> //你去子组件插槽名字叫“center”那个位置 <div>经典歌曲</div> <div>流行歌曲</div> <div>排行歌曲</div> <div>热门歌曲</div> </template> <template v-slot:footer>更多好听音乐请关注公众号</template> //你去子组件内部插槽名字叫“footer”那个位置 </testSlot> </div> </template> <script> import testSlot from './testSlot.vue'; export default { name: 'HelloWorld', components: { testSlot }, data() { return { title: '电影分类' } }, methods: { } } </script> <style scoped> </style>
⏰ 简写形式
<template> <div class="hello"> <testSlot :title="title"> <template #center> <div>经典歌曲</div> <div>流行歌曲</div> <div>排行歌曲</div> <div>热门歌曲</div> </template> <template #footer>更多好听音乐请关注公众号</template> </testSlot> </div> </template>
效果如下:
⚠️ 注意:
v-slot
只能添加在<template>
上
作用域插槽
前面我们介绍过插槽中的作用域,父级作用域和子级作用域是不能互相直接访问的。如果要访问的话,那就只能使用作用域插槽了。
👀不能仅仅展示死数据,我们怎么让子组件和父组件两端通信呢?
⏰ 1. 基础用法
slot中要将内容绑定上
<template> <div class="slot-wrapper"> <div class="titler-wrapper">{{title}}</div> <slot :user="user">{{user.lastName}}</slot> </div> </template> <script> export default { name: 'testSlot', props: ['title'], data() { return { user: { firstName: '张', lastName: '阿强' } } } } </script> <style lang="css" scoped> .slot-wrapper { width: 200px; height: 500px; border: 1px solid #999; border-radius: 4px; } .titler-wrapper { width: 100%; height: 40px; line-height: 40px; background-color: aquamarine; text-align: center; } </style>
插槽中使用v-slot:插槽名=“变量名进行获取”,如果是默认插槽可以简写为v-slot="slotProps"
<template> <div class="hello"> <testSlot :title="title"> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> </testSlot> </div> </template> <script> import testSlot from './testSlot.vue'; export default { name: 'HelloWorld', components: { testSlot }, data() { return { title: '电影分类' } }, methods: { } } </script> <style scoped> </style>
效果如下:
⏰ 2. 解构插槽
如果插槽中的作用域变量是个对象,还可以进行解构。
<template> <div class="hello"> <testSlot :title="title"> <template v-slot:default="{ user }"> {{ user.firstName }} </template> </testSlot> </div> </template>
也可以赋值
<template> <div class="hello"> <testSlot :title="title"> <template v-slot:default="{ user = { firstName: '李' } }"> {{ user.firstName }} </template> </testSlot> </div> </template>
这种解构和es6中的解构是一样的