具名插槽 和 作用域插槽

上篇对 slot 的基本概念和使用有一个初步的认识, 即通过 slot 的这种设计, 父组件可以在调用子组件的时候, 给组件之间传递一波 dom, 子组件通过 slot 标签来进行接收.

slot 默认值

即当父组件调用子组件, 传递 dom 通过 slot 方式时, 如果指定名称, 则在子组件的 slot 中可用一个默认值来表示

// 子组件
template: `
<div>
<slot>我是默认值啦</slot>
</div>
`

具名插槽 slot

即将原本一个大的内容拆分为几个小的片段, 并通过在占位符 template 中 用 v-slot=xxx 进行命名, 然后子组件会根据命名来灵活使用这些片段.

<!DOCTYPE html>
<html lang="en">

<head>
<title>具名插槽</title>
<script src="https://unpkg.com/vue@3"></script>
</head>

<body>
<div id="root"></div>
<script>
const app = Vue.createApp({
template: `
<layout>
<template v-slot:header>
<div >header</div>
</template>
<template v-slot:footer>
<div >footer</div>
</template>
</layout>

`
})

app.component('layout', {
template: `
<div>
<slot name="header"></slot>
<div>content</div>
<slot name="footer"></slot>
</div>
`

})

const vm = app.mount('#root')

</script>
</body>

</html>

在每一个父组件的 template 占位符中, 都是一个命为 v-slot=xxx 的具名插槽, 子组件在使用的时候, 在 slot 标签中记得通过 name="xxx" 的方式即可.

父组件中 template 标签里面的 v-slot:xxx 这个其实可以这样简写:

template: `
<layout>
<template #header>
<div >header</div>
</template>
<template #footer>
<div >footer</div>
</template>
</layout>

`

这个 slot 的应用场景更多就是 父组件向子组件传递 dom, 如果没有它则通过咱之前的 props 则会非常麻烦.

作用域插槽 slot

即子组件要用到子组件的数据, 但由于 slot 的特性又需要将其传递给父组件, 再传到子组件, 理解还好, 就是有点绕, 来个栗子说明一下.

<!DOCTYPE html>
<html lang="en">

<head>
<title>作用域插槽</title>
<script src="https://unpkg.com/vue@3"></script>
</head>

<body>
<div id="root"></div>
<script>
const app = Vue.createApp({
template: `
<list v-slot="{ cj }">
<span>{{cj}}</span>
</list>
`
})

app.component('list', {
data () {
return { list: [1, 2, 3, 4, 5] }
},
template: `
<div>
<slot v-for="item in list" :cj="item">{{item}}</slot>
</div>
`

})

const vm = app.mount('#root')

</script>
</body>

</html>

还是来仔细分析一波, 首先是子组件的 slot.

// 子组件
template: `
<div>
<slot v-for="item in list" :cj="item">{{item}}</slot>
</div>
`

这里就是由子组件的数据渲染多个 slot, 并将其数据绑定到名为 cj 的属性中.

然后是父组件在调用 子组件的时候, 通过 v-slot 来接收子组件的 slot 向父组件传递的 cj 属性数据.

// 父组件
template: `
<list v-slot="{ cj }">
<span>{{cj}}</span>
</list>
`

注意这里的 "{ cj }" 是一个 es6 的赋值结构语法而已啦, 核心还是父组件接收子组件 slot 通过 cj 传过来的数据, 然后将这个数据在父组件中通过 span 标签的方式, 一并再传递给子组件 slot . 这样最终渲染就是以 span 来对数据进行渲染啦.

可以看出, 作用域插槽的应用场景为: 当子组件渲染的内容要有父组件来决定时, 则就会用到作用域插槽, 因为其可以接收到子组件传递给父组件的数据. 而之前我们对 slot 的特性认识是: 父模板调用的数据属性, 用的是父模板数据属性; 子模板调用的数据属性, 用的是子模板数据属性.

耐心和恒心, 总会获得回报的.