vue中slot(插槽)详解,slot、slot-scope和v-slot
slot是什么
slot,也称插槽,可以类比为插卡式的FC游戏机,游戏机(子组件)暴露卡槽(插槽)让用户插入不同的游戏磁条(自定义内容),游戏机会读取并加载磁条里的游戏
Vue的slot,是组件的一块HTML模板,这块模板由使用组件者即父组件提供。可以说是子组件暴露的一个让父组件传入自定义内容的接口。
slot的作用
让用户可以拓展组件,去更好地复用组件和对其做定制处理
举一些例子,比如布局组件、表格列、下拉选项
slot怎么用
slot的用法可以分为三类,分别是默认插槽、具名插槽、作用域插槽
子组件中:
插槽用<slot>标签来确定渲染的位置,里面放如果父组件没传内容时的后备内容
具名插槽用name属性来表示插槽的名字,不传为默认插槽
作用域插槽在作用域上绑定属性来将子组件的信息传给父组件使用,这些属性会被挂在父组件slot-scope接收的对象上
//Child.vue
<template>
<div>
<main>
//默认插槽
<slot>
//slot内为后备内容
<h3>没传内容</h3>
</slot>
</main>
//具名插槽
<header>
<slot name="header">
<h3>没传header插槽</h3>
</slot>
</header>
//作用域插槽
<footer>
<slot name="footer" testProps="子组件的值">
<h3>没传footer插槽</h3>
</slot>
</footer>
</div>
</template>
<style scoped>
div{
border:1px solid #000;
}
</style>
父组件在使用时:
**默认插槽 **的话直接在子组件的标签内写入内容即可
具名插槽是在默认插槽的基础上加上slot属性,值为子组件插槽name属性值
作用域插槽则是通过slot-scope获取子组件的信息,在内容中使用。这里可以用解构语法去直接获取想要的属性
// Parent.vue
<child>
<!-- 默认插槽 -->
<div>默认插槽</div>
<!-- 具名插槽 -->
<div slot="header">具名插槽header</div>
<!-- 作用域插槽 -->
<div slot="footer" slot-scope="slotProps">
{{slotProps.testProps}}
</div>
</child>
渲染结果为
v-slot
在vue2.6中。上述的API被软废弃(3.0正式废弃),取而代之的是内置指令v-slot,可以缩写为【#】
1
子组件用法保持不变,父组件中
slot属性弃用,具名插槽通过指令参数v-slot:插槽名的形式传入,可以简化为#插槽名
slot-scope属性弃用,作用域插槽通过v-slot:xxx="slotProps"的slotProps来获取子组件传出的属性
v-slot属性只能在template上使用,但在**【只有默认插槽时】**可以在组件标签上使用
//Parent
<template>
<child>
<!--默认插槽-->
<template v-slot>
<div>默认插槽</div>
</template>
<!--具名插槽-->
<template #header>
<div>具名插槽</div>
</template>
<!--具名插槽(没有缩写)--> <template v-slot:header>
<div>具名插槽</div>
</template>
<!--作用域插槽-->
<template #footer="slotProps">
<div>
{{slotProps.testProps}}
</div>
</template>
<child>
</template>
拓展用法:
同样可以通过解构获取v-slot={user},还可以重命名v-slot="{user:newName}"和定义默认值v-slot="{user = '默认值'}"
插槽名可以是动态变化的v-slot:[slotName]
注意
默认插槽名为default,可以省略default直接写v-slot,缩写为#时不能不写参数,写成#default(这点所有指令都一样,v-bind、v-on)
多个插槽混用时,v-slot不能省略default
作用域插槽的原理
slot本质上是返回VNode的函数,一般情况下,Vue中的组件要渲染到页面上需要经过template>>render function >> NVode >> DOM过程。组件挂载的本质就是执行渲染函数得到VNode,至于data/props/computed这些属性都是给VNode提供数据来源
在2.5之前,如果是普通插槽就直接是VNode的形式了,而如果是作用域插槽,由于子组件需要再父组件访问子组件的数据,所以父组件下是一个未执行的函数(slotScopre) => return h('div',slotScope.msg),接受子组件的slotProps参数,在子组件渲染实例时会调用该函数传入数据。
在2.6之后,两者合并,普通插槽也变成一个函数,只是不接受参数了