插槽slot
API
插槽
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div id="root"> <child> <h1>hello</h1> </child> </div>
<script type="text/javascript"> Vue.component('child', { template: '<div><slot></slot></div>' })
var vm = new Vue({ el: '#root' }) </script>
|
上面代码中,组件标签内的h1
是要插入子组件内部的元素,子组件内使用slot
标签接收父组件插入的h1
标签。
默认值
1 2 3
| Vue.component('child', { template: '<div><slot>默认值</slot></div>' })
|
子组件slot
标签内可以添加默认值,它只会在父组件没有传入内容的时候被渲染。
具名插槽
::: warning
自 2.6.0 起有所更新。使用 slot
attribute 的语法已废弃。
:::
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <div id="root"> <child> <div slot="header">header</div> <div slot="footer">footer</div> </child> </div>
<script type="text/javascript"> Vue.component('child', { template: `<div> <slot name="header"></slot> <div>content</div> <slot name="footer"></slot> </div>` })
var vm = new Vue({ el: '#root' }) </script>
|
上面代码中,组件标签内有两个元素,分别添加了slot
属性赋予不同的值,子组件内分别有两个slot
插槽,添加了对应的name
属性,用于分别接收父组件传入的内容。
::: tip
自 2.6.0 起,使用v-slot
指令代替slot
attribute 的语法。
:::
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <div id="root"> <child> <template v-slot:header> <h1>标题</h1> </template> <p>内容</p> <template v-slot:footer> <p>页脚</p> </template> </child> </div> <script type="text/javascript"> Vue.component('child', { template: `<div> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>` })
var vm = new Vue({ el: '#root' }) </script>
|
自2.6.0版本起,具名插槽由原来的slot
标签属性改为v-slot
指令,例v-slot:header
。子组件内仍然是在slot
插槽标签添加name
属性用于分别接收内容。未具名的插槽接收未使用v-slot
指定的内容。
另外,具名插槽同样可以使用默认值。
注意 v-slot
只能添加在 <template
上 (只有一种例外情况),这一点和已经废弃的 slot
attribute不同。
作用域插槽
::: warning
自 2.6.0 起有所更新。使用 slot-scope
attribute 的语法已废弃。
:::
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <div id="root"> <child> <template slot-scope="dataObj"> <li>{{dataObj.dataItem}}</li> </template> </child> </div> <script type="text/javascript"> Vue.component('child', { data(){ return { list: [1, 2, 3, 4] } }, template: `<div> <ul> <slot v-for="item of list" :dataItem=item > </slot> </ul> </div>` })
var vm = new Vue({ el: '#root' }) </script>
|
上面代码中,组件标签内需要使用template
标签并且设置slot-scope
属性 用于接收子组件内传递的值,template
标签内的li
标签是传入插槽的元素,dataObj.dataItem
数据由子组件内提供。子组件内通过v-for
循环插入父组件提供的li
标签,并且通过:dataItem=item
把每个item
数据传递出去。
子组件提供数据,父组件中接收数据,可以对数据处理并插入到元素,然后把元素放入子组件插槽。
作用:
数据由子组件提供,但渲染什么元素由父组件决定,并且可以对数据做二次处理。
:::tip
自 2.6.0 起。使用v-slot
代替 slot-scope
attribute 的语法。
:::
为了让 user
在父级的插槽内容中可用,我们可以将 user
作为 <slot>
元素的一个 attribute 绑定上去:
1 2 3 4 5
| <span> <slot v-bind:user="user"> {{ user.lastName }} </slot> </span>
|
绑定在 <slot>
元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot
来定义我们提供的插槽 prop 的名字:
1 2 3 4 5
| <current-user> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> </current-user>
|
在这个例子中,我们选择将包含所有插槽 prop 的对象命名为 slotProps
,但你也可以使用任意你喜欢的名字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <div id="root"> <child> <template v-slot:default="dataObj"> <li>{{dataObj.dataItem}}</li> </template> </child> </div>
<script type="text/javascript"> Vue.component('child', { data(){ return { list: [1, 2, 3, 4] } }, template: `<div> <ul> <slot v-for="item of list" :dataItem=item > </slot> </ul> </div>` })
var vm = new Vue({ el: '#root' }) </script>
|
具名插槽的缩写
跟 v-on
和 v-bind
一样,v-slot
也有缩写,即把参数之前的所有内容 (v-slot:
) 替换为字符 #
。例如 v-slot:header
可以被重写为 #header
:
1 2 3 4 5 6 7 8 9 10 11 12
| <base-layout> <template #header> <h1>Here might be a page title</h1> </template>
<p>A paragraph for the main content.</p> <p>And another one.</p>
<template #footer> <p>Here's some contact info</p> </template> </base-layout>
|
然而,和其它指令一样,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:
1 2 3 4
| <current-user #="{ user }"> {{ user.firstName }} </current-user>
|
如果你希望使用缩写的话,你必须始终以明确插槽名取而代之:
1 2 3
| <current-user #default="{ user }"> {{ user.firstName }} </current-user>
|
Demo
See the Pen
插槽slot by xugaoyi (@xugaoyi)
on CodePen.