Vue 实现了一套内容分发的 API,这套 API 的设计灵感源自 Web Components 规范草案,将
元素作为承载分发内容的出口。
它允许你像这样合成组件:
Add todo
然后在
的模板中,你可能有:
当组件渲染的时候,将会被替换为“Add Todo”。
Add todo
不过,字符串只是开始!插槽还可以包含任何模板代码,包括 HTML:
Add todo
或其他组件
Add todo
如果
的 template 中没有包含一个
元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃
Create a new item
Add todo
当你想在一个插槽中使用数据时,例如:
Delete a {{ item.name }}
该插槽可以访问与模板其余部分相同的实例 property (即相同的“作用域”)。
插槽不能访问
的作用域。例如,尝试访问 action
将不起作用:
Clicking here will {{ action }} an item
作为一条规则,请记住:
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染。例如在一个
组件中:
我们可能希望这个 内绝大多数情况下都渲染文本“Submit”。为了将“Submit”作为后备内容,我们可以将它放在
标签内:
Submit
现在当我在一个父级组件中使用
后备内容“Submit”将会被渲染:
Submit
但是如果我们提供内容:
Save
则这个提供的内容将会被渲染从而取代后备内容:
Save
有时我们需要多个插槽。例如对于一个带有如下模板的
组件:
对于这样的情况,
元素有一个特殊的 attribute:name
。这个 attribute 可以用来定义额外的插槽:
一个不带 name
的
出口会带有隐含的名字“default”。
在向具名插槽提供内容的时候,我们可以在一个 元素上使用
v-slot
指令,并以 v-slot
的参数的形式提供其名称:
Here might be a page title
A paragraph for the main content.
And another one.
Here's some contact info
现在 元素中的所有内容都将会被传入相应的插槽。
渲染的 HTML 将会是:
Here might be a page title
A paragraph for the main content.
And another one.
Here's some contact info
注意,v-slot
只能添加在 上 (只有一种例外情况)
有时让插槽内容能够访问子组件中才有的数据是很有用的。当一个组件被用来渲染一个项目数组时,这是一个常见的情况,我们希望能够自定义每个项目的渲染方式。
例如,我们有一个组件,包含 todo-items 的列表。
app.component('todo-list', {
data() {
return {
items: ['Feed a cat', 'Buy milk']
}
},
template: `
{{ item }}
`
})
我们可能需要替换插槽以在父组件上自定义它:
{{ item }}
但是,这是行不通的,因为只有
组件可以访问 item
,我们将从其父组件提供槽内容。
要使 item
可用于父级提供的 slot 内容,我们可以添加一个
元素并将其绑定为属性:
绑定在 v-slot
来定义我们提供的插槽 prop 的名字:
{{ slotProps.item }}
在这个例子中,我们选择将包含所有插槽 prop 的对象命名为 slotProps
,但你也可以使用任意你喜欢的名字。
在上述情况下,当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot
直接用在组件上:
{{ slotProps.item }}
这种写法还可以更简单。就像假定未指明的内容对应默认插槽一样,不带参数的 v-slot
被假定对应默认插槽:
{{ slotProps.item }}
注意默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确:
{{ slotProps.item }}
slotProps is NOT available here
只要出现多个插槽,请始终为所有的插槽使用完整的基于 的语法:
{{ slotProps.item }}
...
作用域插槽的内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里:
function (slotProps) {
// ... 插槽内容 ...
}
这意味着 v-slot
的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。你也可以使用 ES2015 解构来传入具体的插槽 prop,如下:
{{ item }}
这样可以使模板更简洁,尤其是在该插槽提供了多个 prop 的时候。它同样开启了 prop 重命名等其它可能,例如将 item
重命名为 todo
:
{{ todo }}
你甚至可以定义后备内容,用于插槽 prop 是 undefined 的情形:
{{ item }}
动态指令参数也可以用在 v-slot
上,来定义动态的插槽名:
...
跟 v-on
和 v-bind
一样,v-slot
也有缩写,即把参数之前的所有内容 (v-slot:
) 替换为字符 #
。例如 v-slot:header
可以被重写为 #header
:
Here might be a page title
A paragraph for the main content.
And another one.
Here's some contact info
然而,和其它指令一样,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:
{{ item }}
如果你希望使用缩写的话,你必须始终以明确插槽名取而代之:
{{ item }}