Vue3插槽的使用
如果想要子组件渲染父组件指定的数据,可以使用
props
,将父组件的数据传入进去。但如果我们要子组件渲染一段父组件指定的内容呢?Vue提供了一个特别的组件
< slot>
(插槽),它的作用就是在子组件中标记一个位置,然后将父组件中传入的内容渲染到它所以的位置中。
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
1. 基本使用
子组件:通过 < slot>< /slot>
标签来定义插槽
//hello-world组件中
<div>
<!--定义插槽-->
<slot></slot>
</div>
父组件:
<hello-world>
<!--向插槽插入内容-->
<button>按钮</button>
</hello-world>
在子组件中通过 <slot>
定义插槽,父组件中插入的内容将被放到<slot>
定义的地方进行渲染。
最终子组件的渲染结果:
<div>
<button>按钮</button>
</div>
2. 插槽的作用域
**插槽的内容可以访问到父组件的数据,但是不能访问到子组件的数据。**这是因为插槽的内容是在父组件总进行编译,然后将编译好的内容传给子组件进行渲染。子组件并不会解析和编译,只是负责渲染父组件编译好的插槽内容。
插槽的内容是由它的定义者进行解析编译的,然后将编译好的内容传入到插槽中,由插槽进行渲染。
interface Person {
name: string,
age: number
}
const person = reactive<Person>({
age: 18,
name: "tom"
})
<hello-world>
<!--向插槽插入内容-->
<button>{{person.name}}</button> //可以使用person。
</hello-world>
引用Vue官网文档的一段话:
插槽内容无法访问子组件的数据,请牢记一条规则:
任何父组件模板中的东西都只被编译到父组件的作用域中;而任何子组件模板中的东西都只被编译到子组件的作用域中。
3.插槽的默认内容
可以为插槽定义默认内容,就和给
props
定义默认值一样,如果在父组件中没有传入,则使用默认内容。反之如果父组件有传入内容,则使用父组件传入的内容。
子组件中:
<div>
<slot>
<!--默认内容-->
<button>按钮1</button>
</slot>
</div>
父组件中没有传入值:
<hello-world></hello-world>
渲染结果:渲染默认内容
<div>
<button>按钮1</button>
</div>
父组件传入值:
<hello-world>
<button>按钮2</button>
</hello-world>
渲染结果:渲染父组件传入的内容
<div>
<button>按钮2</button>
</div>
4. 具名插槽
具名插槽:就是给插槽定义一个标识,因为有时候一个组件中可能会定义多个插槽,为了能够区分他们,就需要给他们定义一个标识。
子组件:通过name
属性给插槽定义标识:
<div>
<slot name="header">
</slot>
<slot name="main">
</slot>
</div>
父组件:通过 < template v-slot:标识>
来将内容插入到指定的插槽中。
<hello-world>
<template v-slot:header>
<button>按钮01</button>
</template>
<template v-slot:main>
<button>按钮02</button>
</template>
</hello-world>
注意:如果一个插槽没有指定name
属性,则会使用它的默认值:default
子组件:
<div>
<slot></slot>
</div>
父组件使用:
<hello-world>
<template v-slot:default>
<button>按钮</button>
</template>
</hello-world>
上面的写法等价于:
<hello-world>
<button>按钮2</button>
</hello-world>
直接使用就是传入给默认插槽。
v-slot
有对应的简写方式 #
,因此 <template v-slot:header>
可以简写为 <template #header>
。
<hello-world>
<template v-slot:header>
<button>按钮01</button>
</template>
</hello-world>
等价于:
<hello-world>
<template #header>
<button>按钮01</button>
</template>
</hello-world>
5.作用域插槽
在上面我们有提到过,插槽的内容是无法获取到子组件中的数据的。如果我们想要获取子组件中的数据呢?
*可以在给插槽组件定义属性,在插槽上定义的属性,会因为属性的透传的特性,流入到组件内的标签元素中。*当然,如果只是这样我们还是没有办法去获取和使用的。
我们需要使用Vue给我们提供了一个指令
v-slot
,这个指令不止能用来指定具名插槽,还可以用来获取< slot>
组件的透传对象。
在slot
组件上定义透传属性:
interface Person {
name: string,
age: number
}
const person = reactive<Person>({
age: 18,
name: "tom"
})
<div>
<slot :brand="phone.brand" class="item" :price="phone.price"></slot>
</div>
通过 v-slot
指令获取透传对象:
<hello-world v-slot="row">
<div>{{ row.class }}</div>
<div>{{ row.price }}</div>
<div>{{ row.brand }}</div>
</hello-world>
上面的例子是获取默认插槽的透传对象。如果是具名插槽该怎么获取?还是使用 v-slot
指令来获取,不过使用方式有点变化。
定义具名插槽:
<div>
<slot name="slot1" class="slot1" title="标题1"></slot>
<slot name="slot2" class="slot2" title="标题2"></slot>
</div>
获取具名插槽的透传对象:
<hello-world>
<template v-slot:slot1="row1">
<div>{{ row1.title }}</div> //标题1
</template>
<template v-slot:slot2="row2">
<div>{{ row2.title }}</div> //标题2
</template>
</hello-world>
通过 v-slot:插槽标识="透传对象"
的方法来获取具名插槽的透传对象。