ant-design-vue(vue3)组件二次开发记录

背景

react 如果想在 ant-design 封装的组件上二次开发, 因为 jsx 的特性, 可以将 dom 作为 props, 所以很简单, 但 vue 就有点麻烦, 需要使用 slot 插槽的方式, 以下是业务开发中时间成功后的记录, 感觉还是学到了挺多东西.

$attrs 和$slots

在具体时间之前需要了解一些前置知识, $attrsslots都是绑定在组件作用域上的私有属性, 不需要在setup中 return, 同时, 也可以在setup(props, ctx)的 ctx 上下文中看到 attrs 和 slots 两个属性, 表示的含义都是一样的.

$attrs

先看下官方的解释:

The $attrs object includes all attributes that are not declared by the component’s props or emits options (e.g., class, style, v-on listeners, etc.).

也就是说父组件传入子组件的属性中没被子组件 props 声明的都会包含在$attr 中, 包括 class, style, v-on 这些 dom 原生的属性或 vue 绑定的事件.
这就很适合我们需要二次开发组件的场景, 保证传入的原有属性不受影响的前提下, 传入新的属性进行改造

在子组件中开启$attrs

$attr想在子组件中使用需要设置inheritAttrs: true, vue3 默认该设置, 所以可以直接使用

$slots

顾名思义, $attrs包含了所有传入的非 props 属性, 那$slots就是包含了传入的所有插槽了

v-bind

$attrs包含了父组件传入的所有非 props 属性, v-bind="$attrs"则将所有属性绑定在对应组件标签上

具名插槽和作用域插槽

具名插槽

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
<!-- 子组件 -->
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>

<template v-slot:default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>

<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>

<!-- 父组件 -->
<div class="container">
<header>
<h1>Here might be a page title</h1>
</header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer>
<p>Here's some contact info</p>
</footer>
</div>

作用域插槽

一般情况下父组件和子组件属于各自的作用域, 作用域插槽则可以让父组件使用插槽时访问子组件的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 子组件 -->
<ul>
<li v-for="( item, index ) in items">
<slot
:item="item"
:index="index"
:another-attribute="anotherAttribute"
></slot>
</li>
</ul>

<!-- 父组件 -->
<todo-list>
<template v-slot:default="slotProps">
<i class="fas fa-check"></i>
<span class="green">{{ slotProps.item }}</span>
</template>
</todo-list>

其中, v-slot:default可以简写为#default, slotProps为包含绑定在<slot>上所有属性的对象, 变量名可以自定义, 也可以直接v-slot:default="{item, index, anotherAttribute}"这样写.
下面这张图可以帮助理解:

二次开发 Table 组件

ant-design 原生的Table组件不支持将整个表格 disabled, 接下来就要实现该功能,(这也是我业务中所需要的功能)
改造完组件使用方式和 ant-design 原生的Table相同, 只是支持了表格全局 disabled, 这里使用官方的案例

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<!-- 父组件 -->
<template>
<a-table :columns="columns" :data-source="data" :disabled>
<template #name="{ text }">
<a>{{ text }}</a>
</template>
<template #customTitle>
<span>
<smile-outlined />
Name
</span>
</template>
<template #tags="{ text: tags }">
<span>
<a-tag
v-for="tag in tags"
:key="tag"
:color="tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'"
>
{{ tag.toUpperCase() }}
</a-tag>
</span>
</template>
<template #action="{ record }">
<span>
<a>Invite 一 {{ record.name }}</a>
<a-divider type="vertical" />
<a>Delete</a>
<a-divider type="vertical" />
<a class="ant-dropdown-link">
More actions
<down-outlined />
</a>
</span> </template></a-table
></template>

<!-- a-table.vue -->
<template>
<div class="table-wrap">
<div :class="disabled ? 'mask': ''"></div>
<!-- 把disabled作为props, ant-design自带的那些属性都作为$attrs透传 -->
<antd-table v-bind="$attrs">
<!--
important! 这里template根据父组件的$lots遍历, slotProps为ant-design作用于插槽向外暴露的属性, <slot>则使用v-bind重新将slotProps重新暴露给父组件
-->
<template v-for="(value, key) in $slots" #[key]="slotProps">
<slot :name="key" v-bind="slotProps" />
</template>
</antd-table>
</div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import { Table } from "ant-design-vue";

export default defineComponent({
name: "ATable",
inheritAttrs: true,
props: {
disabled: Boolean,
},
components: {
"antd-table": Table,
},
setup(props, ctx) {
return {};
},
});
</script>

<style lang="scss" scoped>
.table-wrap {
position: relative;
.mask {
position: absolute;
width: 100%;
height: 100%;
background-color: #f5f5f570;
z-index: 1;
}
}
</style>

reference

  1. v-bind
  2. Fallthrough Attributes (attrs 穿透属性)
  3. 具名插槽
  4. slot

ant-design-vue(vue3)组件二次开发记录
https://mariana-yui.github.io/2022/07/15/2022-07-26-vue-slot/
作者
Mariana
发布于
2022年7月15日
许可协议