Skip to content

Commit 92ffdc8

Browse files
committed
feat(element-plus): 新增 ColumnsRender 组件
1 parent 6c76e3f commit 92ffdc8

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import type { TableColumnCtx } from 'element-plus'
2+
import type { FunctionalComponent, ObjectEmitsOptions, VNodeChild } from 'vue'
3+
import type { ComponentProps } from 'vue-component-type-helpers'
4+
import { isString, objectMap } from '@antfu/utils'
5+
import { ElTableColumn } from 'element-plus'
6+
7+
/**
8+
* `ElTableColumn` 的插槽类型
9+
*/
10+
export interface ColumnSlots<T extends { [K: PropertyKey]: any } = any> {
11+
'default'?: (data: {
12+
row: T
13+
column: TableColumnCtx<T>
14+
$index: number
15+
}) => VNodeChild
16+
17+
'header'?: (data: { column: TableColumnCtx<T>, $index: number }) => VNodeChild
18+
19+
'filter-icon'?: (data: { filterOpened: boolean }) => VNodeChild
20+
21+
'expand'?: (data: { expanded: boolean }) => VNodeChild
22+
}
23+
24+
export type ObjectColumnProps<T extends { [K: PropertyKey]: any } = any> =
25+
ComponentProps<typeof ElTableColumn> & {
26+
/**
27+
* 正常情况下应该是通过 `ComponentSlots<typeof ElTableColumn>` 提取出来,
28+
* 但是 `ElTableColumn` 类型定义存在缺失,这里根据官网进行补充并优化。
29+
*
30+
* 若想在 `<template>` 中使用,则需要使用 `<template #[slotType]:[slotName]>`,
31+
* 其中 `[slotName]` 为 `slots.[slotType]` 设置的名称(仅支持字符串),
32+
* 但是模板中会丢失 `ColumnProps<T>` 的泛型提示!
33+
*
34+
* @example
35+
* ```ts
36+
* // script 部分
37+
* const columns: ColumnProps[] = [
38+
* {
39+
* prop: 'name',
40+
* label: 'Name',
41+
* slots: {
42+
* // 引用模板中的插槽
43+
* default: 'name',
44+
*
45+
* // 使用自定义渲染函数
46+
* header({ column }) {
47+
* return <h3>{ column.label } - { Date.now() }</h3>
48+
* }
49+
* },
50+
* },
51+
* ]
52+
* ```
53+
*
54+
* ```html
55+
* <!-- template 部分 -->
56+
* <ColumnsRender :columns="columns">
57+
* <template #default:name="{ row }">
58+
* {{ row.name }}
59+
* </template>
60+
* </ColumnsRender>
61+
* ```
62+
*/
63+
slots?: {
64+
[K in keyof ColumnSlots<T>]: string | ColumnSlots<T>[K]
65+
} & {
66+
[K: string]: string | ((data: any) => VNodeChild)
67+
}
68+
69+
/**
70+
* 子列定义
71+
*/
72+
children?: ColumnProps[]
73+
}
74+
75+
type FalsyColumnProps = false | null | undefined
76+
77+
export type ColumnProps<T extends { [K: PropertyKey]: any } = any> =
78+
| FalsyColumnProps |
79+
ObjectColumnProps<T>
80+
81+
export interface ColumnsRenderProps {
82+
/**
83+
* 列定义,同 `ElTableColumn` 的属性,额外支持 `children` 用于定义子列,
84+
* 列的 `slots` 同 `ElTableColumn` 的 `slots`
85+
*/
86+
columns: ColumnProps[]
87+
}
88+
89+
/**
90+
* 由于 `ElTableColumn` 没有 `emit` 事件,这里只是为了类型占位
91+
*/
92+
interface ColumnsRenderEmits extends ObjectEmitsOptions {}
93+
94+
export type ColumnsRenderSlots = {
95+
[K in keyof ColumnSlots<any> as `${K}:${string}`]: NonNullable<
96+
ColumnSlots<any>[K]
97+
>
98+
} & {
99+
[K: string]: (data: any) => VNodeChild
100+
}
101+
102+
export const ColumnsRender: FunctionalComponent<
103+
ColumnsRenderProps,
104+
ColumnsRenderEmits,
105+
ColumnsRenderSlots
106+
> = ({ columns }, { slots }) => {
107+
const vNodes: VNodeChild = []
108+
109+
for (const column of columns) {
110+
if (!column) {
111+
continue
112+
}
113+
114+
const { children, slots: userSlots = {}, ...columnProps } = column
115+
const finalSlots = objectMap(userSlots, (key, value) => [
116+
key,
117+
isString(value) ? slots[`${key}:${value}`] : value,
118+
])
119+
120+
vNodes.push(
121+
<ElTableColumn {...columnProps}>
122+
{{
123+
...finalSlots,
124+
default:
125+
children && !finalSlots.default
126+
? () => <ColumnsRender columns={children} />
127+
: finalSlots.default,
128+
}}
129+
</ElTableColumn>,
130+
)
131+
}
132+
133+
return vNodes
134+
}
135+
136+
ColumnsRender.props = /* @__PURE__ */ {
137+
columns: {
138+
type: Array,
139+
required: true,
140+
},
141+
}

src/element-plus/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export * from './columns-render'
2+
export * from './pagination-render'
3+
4+
// Re-export
5+
export * from '@/shared'

0 commit comments

Comments
 (0)