Design table组件的hook二次封装

Thursday , 2022-4-21 15:47

踩了一段时间arco的坑,总的来说arco的设计我还是比较喜欢的,组件库谈不上丰富,就将个烂就够用吧,最近在公司的后台管理生产环境中采用其集成框架, 预览地址 http://pro.arco.design/ ,table组件是后台管理的最最核心的组件,没有之一 arco table组件文档 https://arco.design/vue/component/table

这里面涉及到大量的table属性,方法绑定的复用,如果每个页面都去设置….那画面太美都不敢想象。遂封装之,这里依然是ts的操作,js是不可能再写了,这辈子都不可能再写了!

思路大概是通过vue3的hook函数(不得不说vue3+ts是很愉悦的开发体验,想起以前的mixin混入,浑身鸡皮疙瘩都要起,恐怖如斯!),将table的数据加载,分页请求,分页变换,显示属性做统一的封装,最大程度的降低单个在table上的代码量。

接下里看码:

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// 核心的封装方法,详细参数看文档  https://arco.design/vue/component/table
// hook/table-props.ts

import { ref } from 'vue';
// @/types/global 这个自己根据类型定义一下就行了,这里不写
import { Pagination, PaginationRes } from '@/types/global';

type GetListFunc = <T>(v: object) => Promise<T>;
export default function useTbleProps(loadListFunc: GetListFunc) {
const defaultProps = {
'row-key': 'id',
'bordered': { cell: true },
'hover': true,
'border': true,
'stripe': true,
'size': 'small',
'column-resizable': true,
// "scroll": { y: 550, x: '100%' },
'expandable': false,
'loading': true,
'data': [] as any[],
'pagination': {
current: 1,
pageSize: 20,
total: 0,
showPageSize: true,
} as Pagination,
};

// 属性组
const propsRes = ref(defaultProps);

// 加载效果
const setLoading = (status: boolean) => {
propsRes.value.loading = status;
};

/**
* 分页设置
* @param current //当前页数
* @param total //总页数默认是0条,可选
* @param fetchData 获取列表数据,可选
*/
interface SetPaginationPrams {
current: number;
total?: number;
}

const setPagination = ({ current, total }: SetPaginationPrams) => {
propsRes.value.pagination.current = current;
total && (propsRes.value.pagination.total = total);
};

// 单独设置默认属性
const setProps = (params: object) => {
for (const key in params) {
defaultProps[key] = params[key];
}
};

// 设置请求参数,如果出了分页参数还有搜索参数,在模板页面调用此方法,可以加入参数
const loadListParams = ref<object>({});
const setLoadListParams = (params?: object) => {
loadListParams.value = params;
};

// 加载分页列表数据
const loadList = async <T>() => {
setLoading(true);
let data = await loadListFunc<PaginationRes<T>>({
...propsRes.value.pagination,
...loadListParams.value,
});
propsRes.value.data = data.list as T[];
setPagination({ current: data.current, total: data.total });
setLoading(false);
return data;
};

// 事件触发组
const propsEvent = ref({
//排序触发
sorterChange: (dataIndex: string, direction: string) => {
console.log(dataIndex, direction);
},
//分页触发
pageChange: (current: number) => {
setPagination({ current });
loadList();
},
// 修改每页显示条数
pageSizeChange:(pageSize:number)=>{
propsRes.value.pagination.pageSize = pageSize;
loadList();
}
});

return {
propsRes,
propsEvent,
setProps,
setLoading,
loadList,
setPagination,
setLoadListParams,
};
}
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
<!--在页面模板中使用-->
<template>
<div class="container">
<a-table
v-on="propsEvent"
v-bind="propsRes">
<template #columns>
<a-table-column title="创建时间" data-index="createTime" />
<!--其他变量自己绑定....-->
</template>
</a-table>

</div>
</template>

<script lang="ts">
import { defineComponent, reactive, ref, toRefs, onMounted } from 'vue';
import { getRollingInfoList, GetRollingInfoList } from '@/fetch/apis';
import useTableProps from '@/hooks/table-props';

export default defineComponent({
setup() {
//这里开始引入使用,将请求方法默认传入
const { propsRes, propsEvent, loadList } = useTableProps(getRollingInfoList);

onMounted(()=>{fetchData()})
// 数据获取
const fetchData = async () => {
//hook里面做了泛型的返回
await loadList<GetRollingInfoList['Res']>();
};

return {
propsRes,
propsEvent
};
}, //setup

});
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// /fetch/apis.ts 的封装

//这里Requset对axio做了二次封装,返回传入的泛型值
import Requset from '@/fetch/requset';
import { Pagination } from '@/types/global';

export interface GetRollingInfoList {
Res:{
id?: number;
creatorName?: string;
createTime?: string;
}
}

export function getRollingInfoList<T>(data:Pagination) {//获取跑马灯列表
return Requset<T>({
method:'POST',
url: `/yourUrl`,
data
});
}

其实核心的就是hook的统一封装,这样在业务页面中,我们只用关心对调用列表的方法跟对应字段即可。