这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战
这篇文章我们来讲一下v-slot的使用方法,以及在使用它的时候我们需要注意的地方。
如何使用
v-slot结合<slot>元素提供具名插槽或需要接收 prop 的插槽。v-slot的简写为#,只可用于<template>和组件中。
基础使用
假定我们自定义一个组件my-button为:
<button>
<slot>提交</slot>
</button>
slot元素中,我们可以给默认值(使用组件不传内容的时候会显示默认值,否则默认值会被替换),也可以为空,直接为<slot></slot>。那么我们该怎么去使用这个组件呢,如下:
<my-button>
1. 此处什么都不放,编译后显示默认值
2. 此处可以放字符串
3.此处可以放任何模板代码 或 组件
</my-button>
此外,需要我们注意的是:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。也就是说<my-button></my-button>包裹的内容不能访问my-button的作用域。
具名插槽
有时我们需要多个插槽,<slot> 元素有一个特殊的 attribute:name,我们可以使用这个属性来写你需要的插槽,假定一个组件base-layout如下:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
当属性name不存在的时候,<slot> 出口会带有隐含的名字“default”。那么我们该怎么使用呢,如下:
<base-layout>
//使用 v-slot
<template v-slot:header>
<h1>name为header的插槽</h1>
</template>
//默认插槽可以不用写 v-slot:default ,但是如果用缩写的方式就需要写上 #default
<template #default>
<p>v-slot 时可以不用写</p>
<p>缩写时要加上 #default</p>
</template>
//使用缩写 #
<template #footer>
<p>缩写形式</p>
</template>
</base-layout>
作用域插槽
为了让插槽内容能够访问子组件中才有的数据,我们可以使用作用于插槽。
用法
单个插槽
假定组件todo-list为:
<ul>
<li v-for="(item, index) in items">
<slot :item="item" :index="index"></slot>
</li>
</ul>
使用时我们可以有两种方式:
v-slot作用在组件上
<todo-list v-slot="slotProps">
//slotProps 是个对象,包含了绑定在 slot 上除 name 以外的所有属性,例如上述包含了item、index
//slotProps 是个变量,可以取任意名字
//此时不能用template包裹
<span>{{slotProps.item}}</span>
</todo-list>
我们这个例子是默认插槽,如果例子中是具名插槽,比如 slot 的 name="header",那我们要这样使用:
<todo-list v-slot:header="slotProps">
<span>{{slotProps.item}}</span>
</todo-list>
v-slot作用在插槽包裹元素template上
<todo-list>
//一定要用 template 包裹,因为v-slot只能用于 template 或 组件中
<template v-slot="slotProps">
<span>{{slotProps.item}}</span>
</template>
</todo-list>
如果组件给了一个具名插槽,使用方法和1相同。
多个插槽
此时v-slot只能作用在插槽包裹元素template上,假定组件todo-list为:
<ul>
<li v-for="(item, index) in items">
<slot name="slot1" :item="item" :index="index"></slot>
<slot name="slot2" :item="item" :index="index"></slot>
<slot name="slot3" :item="item" :index="index"></slot>
</li>
</ul>
使用方法如下:
<todo-list>
//slot1
<template v-slot:slot1="slotProps">
<span>{{slotProps.item}}</span>
</template>
//slot2
<template v-slot:slot2="slotProps">
<span>{{slotProps.item}}</span>
</template>
//slot3
<template v-slot:slot3="slotProps">
<span>{{slotProps.item}}</span>
</template>
</todo-list>
解构插槽Prop
通过上述内容我们知道slotProps是个对象,那么我们在使用的时候可以解构插槽。我们以1的具名插槽为例:
<todo-list v-slot:header="{item,index}">
<span>{{item}} {{index}}</span>
</todo-list>
或者
<todo-list v-slot:header="{item:x,index:y}">
<span>{{x}} {{y}}</span>
</todo-list>
动态插槽
动态指令参数也可以用在 v-slot 上,来定义动态的插槽名,也就是说你可以根据自己的需求,来动态的改变插槽内容,如下:
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
</base-layout>
假设你有三个插槽,但是你每次只想展示一个插槽内容,那么我们就可以用动态插槽来做这件事。
注意事项
Vue3统一了普通插槽和作用域插槽。当使用渲染函数时,即 h,将插槽定义为当前节点的子对象,如下:
h(LayoutComponent, {}, {
header: () => h('div', this.header),
content: () => h('div', this.content)
})
当你需要以编程方式引用作用域插槽时,Vue3与Vue2的用法是不一样的,在Vue3中它们现在被统一到 $slots 选项中,使用如下:
// 2.x 语法
this.$scopedSlots.header
// 3.x 语法
this.$slots.header()
总结
-
使用动态插槽可以让我们在处理同一区域复杂内容切换更灵活。
-
在
Vue3中<template>里面可以放代码片段,所以我们可以在使用插槽的时候,里面可以放很多的dom或组件。 -
具名插槽和解构插槽Prop都可以让我更好的去完成需求,我们可以根据自己的情况,去合理的使用它们。
想了解更多文章,传送门已开启:回首Vue3目录篇 !