Vue3 + TypeScript 开发一个 ProTable(第二弹)
第一弹链接欢迎访问哈:Vue3 + ts 开发一个ProTable,这期先实现了目标功能里面的两个,后序如果再有什么想法,会加入到里面的,仅仅提供一个思路。
增强了那些功能
- 1. 用到的table原有的
props
和column
原有的props, form 原有的props。 - 2.
table
支持自定义slot
和支持自己维护业务slot
(cellField下面的组件) - 3. 支持
表头复制
功能 - 4. 支持
合并行
和合并列
功能 - 5. 支持用户
自定义新增弹窗
功能,因为表单最不确定的地方就是添加
的地方,复杂的时候涉及好多逻辑,考虑要不要做,感觉还是不要这个功能啦。
代码演示
1、table支持其余props
<pro-table
type="user"
:columns="columns"
:table-attrs="{
border: true, // 边框
rowClassName: tableRowClassName // 带状态表格
}"
:request-url="requestUrl"
>
</pro-table>
<script lang="ts" setup>
interface User {
date: string
name: string
address: string
}
const tableRowClassName = ({
row,
rowIndex
}: {
row: User
rowIndex: number
}) => {
if (rowIndex === 1) {
console.log(rowIndex)
return 'warning-row'
} else if (rowIndex === 3) {
return 'success-row'
}
return ''
}
</script>
效果如下
2、column支持其余props
表格也可以设置固定列,
<pro-table
type="user"
:columns="columns"
:request-url="requestUrl"
:table-attrs="{
border: true
}"
>
</pro-table>
const columns: ColumnProps[] = [
{
key: 'userName',
title: '用户名',
searchType: 'el-input',
width: 120,
attrs: {
sortable: true,
resizable: true
}
}
]
显示效果
3、form支持原有props
const formAttrs = reactive<Partial<FormProps>>({
labelPosition: 'right',
rules: reactive<FormRules>({
userName: [
{ required: true, message: '此字段不能为空!' }
]
})
})
实现效果
4、table slotType JsonField
这里我们就使用一个展示json
的插件来帮我们完成查看JSON
的功能。
同样代码写代码的时候,我们只需要确定这个字段是什么类型就可以了,就不用再写一堆的具体代码了。
const columns: ColumnProps[] = [{
key: 'jsonParams',
title: 'JsonField',
searchType: 'z-json',
search: false,
width: 120,
add: true,
show: true,
slotType: 'JsonField'
}]
yarn add vue-json-viewer@3
5、table slotType ProgressField
这个思路与上面的一致,....... 要展示成进度条样式的列
6、table slotType SingleArray
这个思路与上面的一致,....... [1,2,3] 或者['a', 'b', 'c']这样的数据
7、table slotType StatusTag
这块主要是将tag
组件进行了封装
<template>
<el-tag
:type="type"
disable-transitions
>{{ text }}
</el-tag>
</template>
<script lang="ts" setup>
import { PropType } from 'vue'
type keys = string | 0 | 1
type IStatus = {
[key in keys] : {
type: string
text: string
}
}
const props = defineProps({
data: {
type: String as PropType<keys>,
required: true
}
})
const statusMap: IStatus = {
0: {
type: 'danger',
text: '禁用'
},
1: {
type: 'success',
text: '启用'
}
}
const type = statusMap[props.data!].type
const text = statusMap[props.data!].text
</script>
使用
const columns: ColumnProps[] = [{
key: 'status',
title: '状态',
searchType: 'z-select',
width: 100,
options: [
{
label: '启用',
value: 1
},
{
label: '禁用',
value: 0
}
],
slotType: 'StatusTag'
}]
效果如下:
8、table slotType TableField
这个思路与上面的一致,就不再贴代码了....... 表格的列要展示成一个小的table
9、支持用户自己传入 slot
但是我觉得如果是能够抽象出去的slot
类型尽量抽离出去,copy
次数大于2
的代码,直接抽离成一个slot
组件在内部处理不同的展示形式。
代码实现,与使用方式
<pro-table
type="user"
:columns="columns"
:request-url="requestUrl"
:form-attrs="formAttrs"
>
<template v-slot:userName="slotProps">
{{'666'}}
</template>
</pro-table>
const columns: ColumnProps[] = [{
key: 'userName',
title: '用户名',
searchType: 'el-input',
width: 120,
attrs: {
sortable: true,
resizable: true
},
slot: 'userName'
}]
内部实现,短短一行代码,就是指定slot
的名字,同时将row
的数据回传给外部可以进行使用,交给别人自定义。
<slot v-if="item.slot" :row="row" :name="item.slot"></slot>
实现效果:
用到的ts知识
1、Partial
让属性全部变成可选的,
// 在饿了么的column字段上面进行扩展
export type ColumnProps = {
attrs?: Partial<TableColumnCtx<any>> // 其他属性
}
2、ExtractPropTypes
这个是从element-plus
源码里面看见的,大概的作用就是,如果我们要提取公共的props
类型,可以借助这个函数进行帮助。在搜这个帮助类型的时候,突然发现之前在知乎上讨论的一片文章
为什么我感觉 Vue 3 TypeScript 还是不行?,其中的有个回答,貌似也提到这个问题。其他参考文章
vue3 defineProps 引入定义的接口报错
示例用法:(暂不支持的)
export const proTableProps = {
columns: {
type: Array as PropType<ColumnProps[]> // 列的字段
},
type: {
type: String as PropType<string> // 这个属于业务字段啦, 会在组件内部使用,后面处理如果不传的情况
},
requestUrl: {
type: Object as PropType<RequestUrl>
},
tableAttrs: {
type: Object as PropType<Partial<TableProps<any>>> // 这里的 T 指的是数据项 item
},
formAttrs: {
type: Object as PropType<Partial<FormProps>>
},
beforeSubmit: {
type: Function // 提交之前的钩子
}
} as const
export type ProTableProps = ExtractPropTypes<typeof proTableProps>
const props = withDefaults(defineProps<ProTableProps>(), {
columns: () => []
})
按道理来说我们这块,只是把之前的interface
换成了type
从外部引入的,但是很不幸,将会收到一下的报错
[@vue/compiler-sfc] type argument passed to defineProps() must be a literal type, or a reference to an interface or literal type.
export type ProTableProps = Partial<ExtractPropTypes<typeof proTableProps>>
const x: ProTableProps = {
columns: []
}
我们来观察一下这个类型,传给defineProps
按道理来说是没有问题的,找了一会放弃了。
后面我参考了element-plus
中的写法,把提出去的props
还是当做参数使用。这样我们就可以提取公共的props
啦。可以在多处使用公共的props
类型了。
export const proTableProps = {
columns: {
type: Array as PropType<ColumnProps[]>, // 列的字段
default: () => {
return []
}
},
type: {
type: String as PropType<string> // 这个属于业务字段啦, 会在组件内部使用,后面处理如果不传的情况
},
requestUrl: {
type: Object as PropType<RequestUrl>,
default: () => {
return {}
}
},
tableAttrs: {
type: Object as PropType<Partial<TableProps<any>>>, // 这里的 T 指的是数据项 item
default: () => {
return {}
}
},
formAttrs: {
type: Object as PropType<Partial<FormProps>>,
default: () => {
return {}
}
},
beforeSubmit: {
type: Function, // 提交之前的钩子
default () {
return 'Default function'
}
}
} as const
const props = defineProps(proTableProps)
仓库地址
转载自:https://juejin.cn/post/7121887173062131742