前言
上一章说了组件,组件有着很多的特点,灵活、高复用、逻辑分离、专注点分离 ,但时只使用组件通讯好像并不能让组件太灵活,组件之间的通讯只能改变一些参数、变量。那我们如果想要更加灵活的改变组件内的模板展示该怎么办呢?
上一章:初识vue-组件及组件传值 - 掘金 (juejin.cn)
插槽
当我们封装高复用组件的时候,有时候不仅要考虑它内部的一些变量是否要改变,还要考虑这个组件内的模板是否可控,怎么才能定义控制组件内的模板呢?这个时候就要使用到插槽了(slot)
官方解释:
定义使用插槽
定义的时候只需要在子组件内部使用vue内置组件solt来占位即可,使用的时候就是将单标签组件改为双标签,在两个标签内写入的模板就自动映射到子组件内部solt所在的位置了
vue
Dialog.vue
子组件 自定义一个弹窗组件
<div v-show="flag">
<div><i @click="$emit('chang', false)">X</i></div>
//父组件调用这个组件,并在两个标签内写入模板就会映射到这里
<slot></slot>
</div>
//组件使用v-mode定义
export default {
props: {
flag: {
type: Boolean,
default: false,
},
},
model: {
prop: "flag",
event: "change",
},
};
父组件
Home.vue
<Dialog v-model="flag">
<img src="xxx.png" alt="" />//如果当我们不写入这个img标签时,弹窗组件除了弹窗外,什么都不会显示
</Dialog>
插槽默认值
这个就很好理解,就是当我们没有在父组件内传入模板的时候,子组件内定义插槽的位置会默认显示,否者就显示传入映射的模板
vue
Dialog.vue
<template>
<div v-show="flag">
<div><i @click="$emit('chang', false)">X</i></div>
//slot里可以定义任何模板中的数据 slot在解析的时候不会有任何含义
//当父组件标签内没有传入模板片段,或者使用的是单标签的时候,这里会默认显示,否则显示父组件传入的那内容
<slot>
<ul>
<li>颤三</li>
</ul>
</slot>
</div>
</template>
Home.vue
此时调用子组件显示的就是li标签内的'颤三'
<Dialog v-model="flag"/>
命名插槽
有些情况在一个组件内可能需要不止一个插槽,当组件内封装有多个插槽的时候,可以使用命名插槽来指定要将显示的内容
只需要在slot上添加name属性即可
父组件指定插槽位置时vue2中使用slot,到vue2.6之后就变为纯正的指令了 v-slot:指定插槽名
vue
//子组件
Dialog.vue
<div v-show="flag">
<div><i @click="$emit('chang', false)">X</i></div>
//子组件内添加name属性即可 命名插槽一样可以有默认内容
<slot name="header"> </slot>//这里就是'页眉'
<br />
<slot> </slot>//这里就是'内容'
<hr />
<slot name="footer"> </slot>//这里就是'页脚'
</div>
父组件 vue2.6之前
vue
Home.vue
<Dialog v-model="flag">
<template slot="header"> 页眉 </template>
内容
<template slot="footer"> 页脚 </template>
</Dialog>
父组件 vue2.6之后
vue
Home.vue
//v-slot也可以简写为# 下面v-slot:header === #header
<Dialog v-model="flag">
//#headrer
<template v-slot:header> 页眉 </template>
内容
//#footer
<template v-slot:footer> 页脚 </template>
</Dialog>
作为指令 它一样是可以使用动态命名的
使用v-slot:[变量] 或者使用#[变量]
之前有写指令内容:初识vue--基础认识(1) - 掘金 (juejin.cn)
作用域插槽
还有一种情况,我们在父组件内的插槽中需要渲染子组件内部的数据,正常来说是拿不到的。但是在插槽里vue提供了这种写法。当我们在slot上添加除name 属性外的属性,都可以在父元素插上拿到的 官方示意图:
vue
子组件内
Dialog.vue
<template>
<div v-show="flag">
<div><i @click="$emit('chang', false)">X</i></div>
//在slot组件上可以是任意属性 参数也可以是动态的
<slot name="header" :num="1" title="iceCode"> </slot>
<br />
<slot title="默认的"> </slot>
<hr />
<slot name="footer" :num="+new Date() % 2 === 0 ? true : false"> </slot>
</div>
</template>
父组件 vue2.6之前
vue
Home.vue
<Dialog v-model="flag">
//可以使用slot-coppe 拿到所要传的参数
//此时row={num:1,title:'iceCode'}
<template slot="header" slot-scope='row'> 页眉 </template>
//默认插槽会有一个固定的名字 default
//此时row={title:'默认的'}
<template slot="default" slot-scope='row'> 内容 </template>
//这里同理
<template slot="footer" slot-scope='row'> 页脚 </template>
</Dialog>
父组件 vue2.6之后
vue
Home.vue
//v-slot也可以简写为# 下面v-slot:header === #header
<Dialog v-model="flag">
//这里获得的数据和上面是一致的
<template #header='row'> 页眉 </template>
//默认插槽 也是为default
<template #default='row'> 内容 </template>
<template #footer='row'> 页脚 </template>
</Dialog>
注意
不管vue2.6之前还是之后,这里插槽里的数据都可以解构使用的
插槽的高阶用法
这里是官方演示的一个高阶用法,作为小菜鸡,本人暂时没有使用过
主要是在使用v-for渲染的时候,item作为一个对象 可以直接使用v-bind动态绑定这些item,key作为属性,value作为属性值通过插槽传递(这种写法有些像react里面利用jsx快速绑定属性名,属性值,不过不用展开)
结尾
插槽的基本使用就这些,学会使用插槽,可以让自己封装更加灵活的组件。高复用,低耦合性的组件离不开组件传值和插槽的