前言
插槽就是子组件中的提供给父组件使用的一个占位符,用
插槽内容
1 | <SlotChild>Add todo</SlotChild> |
当 SlotChild
组件渲染的时候,将会被替换为“Add Todo”。
1 | <!-- 渲染 HTML --> |
如果 SlotChild
的 template 中没有包含一个 <slot>
元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃
1 | // SlotChild |
渲染作用域
当你想在一个插槽中使用数据时,例如:
1 | <todo-button> |
该插槽可以访问与模板其余部分相同的实例 property (即相同的“作用域”)。
插槽不能访问 <todo-button>
的作用域。例如,尝试访问 action
将不起作用:
1 | <todo-button action="delete"> |
作为一条规则,请记住:
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
备用内容
有时为一个插槽设置具体的备用 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。例如在一个 <submit-button>
组件中:
1 | <button type="submit"> |
我们可能希望这个 <button>
内绝大多数情况下都渲染文本“Submit”。为了将“Submit”作为备用内容,我们可以将它放在 <slot>
标签内:
1 | <button type="submit"> |
现在当我在一个父级组件中使用 <submit-button
> 并且不提供任何插槽内容时:
1 | <submit-button></submit-button> |
备用内容“Submit”将会被渲染:
1 | <button type="submit"> |
但是如果我们提供内容:
1 | <submit-button> |
则这个提供的内容将会被渲染从而取代备用内容:
1 | <button type="submit"> |
具名插槽
有时我们需要多个插槽。例如对于一个带有如下模板的 <base-layout>
组件:
1 | <div class="container"> |
对于这样的情况,<slot>
元素有一个特殊的 attribute:name
。这个 attribute 可以用来定义额外的插槽:
1 | <div class="container"> |
一个不带 name
的 <slot>
出口会带有隐含的名字“default”。
在向具名插槽提供内容的时候,我们可以在一个 <template>
元素上使用 v-slot
指令,并以 v-slot
的参数的形式提供其名称:
1 | <base-layout> |
现在 <template>
元素中的所有内容都将会被传入相应的插槽。
渲染的 HTML 将会是:
1 | <div class="container"> |
注意,**v-slot
只能添加在 <template>
上** (只有一种例外情况)
作用域插槽
有时让插槽内容能够访问子组件中才有的数据是很有用的。当一个组件被用来渲染一个项目数组时,这是一个常见的情况,我们希望能够自定义每个项目的渲染方式。
- 要使
item
可用于父级提供的 slot 内容,我们可以添加一个<slot>
元素并将其绑定为属性; - 绑定在
<slot
> 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的v-slot
来定义我们提供的插槽 prop 的名字; - 在这个例子中,我们选择将包含所有插槽 prop 的对象命名为
slotProps
,但你也可以使用任意你喜欢的名字。
1 | <SlotChild> |
独占默认插槽的缩写语法
在上述情况下,当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot
直接用在组件上:
1 | <todo-list v-slot:default="slotProps"> |
这种写法还可以更简单。就像假定未指明的内容对应默认插槽一样,不带参数的 v-slot
被假定对应默认插槽:
1 | <todo-list v-slot="slotProps"> |
注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:
1 | <!-- 无效,会导致警告 --> |
只要出现多个插槽,请始终为所有的插槽使用完整的基于 <template>
的语法:
1 | <todo-list> |
解构插槽 Prop
作用域插槽的内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里:
1 | function (slotProps) { |
这意味着 v-slot
的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。你也可以使用 ES2015 解构来传入具体的插槽 prop,如下:
1 | <todo-list v-slot="{ item }"> |
这样可以使模板更简洁,尤其是在该插槽提供了多个 prop 的时候。它同样开启了 prop 重命名等其它可能,例如将 item
重命名为 todo
:
1 | <todo-list v-slot="{ item: todo }"> |
你甚至可以定义备用内容,用于插槽 prop 是 undefined 的情形:
1 | <todo-list v-slot="{ item = 'Placeholder' }"> |
动态插槽名
动态指令参数也可以用在 v-slot
上,来定义动态的插槽名:
1 | <base-layout> |
具名插槽的缩写
跟 v-on
和 v-bind
一样,v-slot
也有缩写,即把参数之前的所有内容 (v-slot:
) 替换为字符 #
。例如 v-slot:header
可以被重写为 #header
:
1 | <base-layout> |
然而,和其它指令一样,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:
1 | <!-- This will trigger a warning --> |
如果你希望使用缩写的话,你必须始终以明确插槽名取而代之:
1 | <todo-list #default="{ item }"> |