关于 Vue 中的 slot-scope

其实这个特性我见的不多,所以一直没去了解他的功能,现在觉得这个特性挺灵活的,能写出高复用性的组件。

概述

slot scope 是对 slot 功能的增强,主要功能是将子组件中的数据带出给父组件使用,以函数作为例子,可以看作是:

1
2
3
function (list) {
return list.map().reduce() // ......
}

让子组件可以对 props 做一系列的操作,之后将结果通过 slot scope 传递给父组件,让父组件决定显示的方式。

这种需求之所以要用到 slot scope,原因在于在父组件的作用域中,是无法访问子组件作用域的,就算子组件和父组件同时拥有 user 这个属性,在父组件中 this.user 指向的还是自己本身的 user,所以需要 slot scope 把数据带出来。

举个例子🌰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div>
<li v-for="(item, k) in list" :key="k">
<slot :index="k" :payload="item"></slot>
</li>
</div>
</template>

<script>
export default {
props: {
list: Array
}
}
</script>

这个组件叫做 MakeOrderedList,用于作为有序列表的容器,在父组件中是这样的:

1
2
3
4
5
6
7
<make-ordered-list :list="[{name: 'a', age: 12}, {name: 'abc', age: 10}]">
<template slot-scope="scope">
<span>{{ scope.index }}</span>
<input type="text" :value="scope.payload.name">
<input type="number" :value="scope.payload.age">
</template>
</make-ordered-list>

list 是任意格式的列表,子组件会将 list 拆分为 key 和 value,并将这两个属性通过 v-bind 的形式回传,在父组件中通过 slot-scope="scope" 新建一个名为 scope 的对象承接子组件回传的属性,template 中的就是显示的具体结构了。

换个例子🌰

刚刚的例子仅仅是为了展示功能,没有意义,这里举 UI 框架中常见的 table 组件作为例子,在 Vuetify 中,table 组件的用法为:

1
2
3
4
5
6
7
8
9
10
11
<v-data-table
:headers="headers"
:items="list"
>
<template v-slot:items="props">
<td>{{ props.item.planet }}</td>
<td class="text-xs-left">{{ props.item.mission }}</td>
<td class="text-xs-left">{{ props.item.type }}</td>
<td class="text-xs-left">{{ props.item.enemy }}</td>
</template>
</v-data-table>

data table 这个组件接受了两个 props,他根据 headers 渲染出表头,接受 items 作为表内容,但是不立即渲染出来,而是将元素回传给父组件,目的是让父组件去决定显示的效果

关于语法

以上两个例子用了不同的 slot 语法,第二个例子中的语法是新的,大概是 2.6.0 更新的。

改动:

插槽的语法从 slotslot="name" 变成了 v-slotv-slot:name

插槽作用域从 slot-scope 改成了 v-slot:slotName,旧版本只能和 slot 组合使用以指定插槽。

特性:

新增了动态插槽,通过 v-slot:[dynamicSlotName] 来声明,参考 ES6 的语法。

新增了具名插槽的缩写 #,比如 #name#header,要注意的是具名,默认插槽不能简写,可参考 v-bind 或 v-on(除非写成 #default)。