Vue-查缺补漏(3)-插槽(slot)

当需要让组件组合使用,混合父组件的内容与子组件的模板时,就会用到slot,这个过程叫作内容分发.将<slot>元素作为承载分发内容的出口。
props传递数据,events触发事件,slot内容分发,再复杂的组件也是由这 3 部分构成的

插槽内容

插槽可以包含任何模板代码,包括 HTML,甚至其他组件

作用域

父组件模板的内容是在父组件作用域内编译,子组件模板内容在子组件作用内编译。

  • slot分发的内容,作用域是在父组件上。
1
2
3
4
5
<my-child url="/profile">
send to :{{url}}
Logged in as {{use.name}}
</my-child>
<!-- 这里的url,是undefined,因为'/profile是传递给<my-child>组件的,并不在父组件作用域内' -->

默认内容

父组件在没有提供任何插槽内容时,则会渲染插槽默认内容

1
2
3
4
5
6
7
8
9
10
11
<button type="submit">
<slot>Submit</slot>
</button>
<!-- 如果父组件使用改组件,并且不提供任何插槽内容,则渲染: -->
<button type="submit">
Submit
</button>
<!-- 如果提供了内容,<submit-buton>Save</submit-button>,则渲染为: -->
<button type="submit">
Save
</button>

####(2.6.0 中,具名插槽和作用域插槽会引入统一的语法v-slot指令,它取代了slotslot-scope目前已被废弃但未移除,在 Vue3 中将被移除)

具名插槽

<slot>元素,用特殊的特性name,来定义额外的插槽,一个不带name<slot>出口会自动带有隐含的名字default.
在向具名插槽提供内容时,可在<template>元素上使用v-slot指令,以v-slot的参数的形式提供其插槽名称。

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
<!-- 带有具名插槽的组件<base-layout> -->
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
<!--实际上: <slot name="default"></slot> -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>

<!-- 向具名插槽提供内容 -->
<base-layout>
<template v-slot:header>
<h1>page title</h1>
</template>
<template v-slot:default>
<h1>page main</h1>
</template>
<template v-slot:footer>
<h1>page foter</h1>
</template>
</base-layout>

作用域插槽

让插槽内容能够访问子组件才有的数据。

1
2
3
4
5
6
<!-- <current-user>组件的模板 -->
<span>
<slot v-bind:user="user">
{{user.lastName}}
</slot>
</span>

绑定在<slot>元素上的特性被称作插槽prop.
在父级作用域中,给v-slot带一个值来定义我们提供的插槽 prop 的名字.

1
2
3
4
5
<current-user>
<template v-slot:default="slotProps">
{{slotProps.user.firstName}}
</template>
</current-user>

在此例中,把包含所有插槽 prop 的对象命名为slotProps

解构插槽 Prop

作用域插槽的内部工作原理:将你的插槽内容包括在一个需要传入单个参数的函数里

1
2
3
function (slotProps) {
// 插槽内容
}

所以, v-slot的值实际上可以是任何能过作为函数的参数的 js 表达式,也就可以使用ES2015 解构来传入具体的插槽 prop.

1
2
3
<current-user v-slot:default="{ user }">
{{ user.firstName }}
</current-user>

动态插槽名

动态指令参数也可以用在v-slot指令上,来定义动态的插槽名

  • 动态指令参数: 2.6.0 新增,可用 方括号括起来的 js 表达式作为一个指令的参数

    1
    2
    3
    <a v-bind:[attributeName]="url"></a>

    <a v-on:[eventName]="doSomething"></a>

动态插槽名

1
2
3
4
5
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
</base-layout>