@qin-ui/element-plus-pro 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI-CONTEXT.md +266 -162
- package/README.md +303 -84
- package/api.json +95 -1
- package/bin/init-ai.mjs +118 -99
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @qin-ui/element-plus-pro
|
|
2
2
|
|
|
3
|
-
> 基于 **Element Plus** 和 **Vue 3.x** 的二次封装高级组件库,提供高度可配置、Schema 驱动的 `ProForm` 和 `
|
|
3
|
+
> 基于 **Element Plus** 和 **Vue 3.x** 的二次封装高级组件库,提供高度可配置、Schema 驱动的 `ProForm`、`ProTable` 和 `ProComponentProvider`,助您摆脱繁琐的模板代码,极速搭建现代化桌面端中后台应用。
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<img src="https://img.shields.io/badge/Element%20Plus-2.x-blue" alt="Element Plus" />
|
|
@@ -16,23 +16,42 @@
|
|
|
16
16
|
## ✨ 核心特性
|
|
17
17
|
|
|
18
18
|
- 🛡️ **极简设计**:基于 Element Plus 构建,原生支持 Vue 3.5+。
|
|
19
|
-
-
|
|
19
|
+
- 🔥 **Schema 驱动**:使用声明式 JSON 配置即可快速生成表单与表格,极大地减少模板代码。
|
|
20
20
|
- 🔄 **语义对齐**:针对 Element Plus 深度定制,数据源语义统一为 `data`(不再使用 `dataSource`),默认 `modelProp` 统一为 `modelValue`。
|
|
21
21
|
- 🧩 **极致扩展**:原生支持自定义渲染组件与插槽定制,提供 `ProComponentProvider` 进行全局默认属性覆盖。
|
|
22
|
-
- 📐 **强类型推导**:基于 TypeScript
|
|
22
|
+
- 📐 **强类型推导**:基于 TypeScript 提供完备的强类型推导和自动补全。
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
26
26
|
## 📦 安装
|
|
27
27
|
|
|
28
|
-
确保您的项目中已安装 `element-plus` 和 `vue
|
|
28
|
+
确保您的项目中已安装 `element-plus` (v2.13.6+) 和 `vue` (v3.5+):
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
+
npm i @qin-ui/element-plus-pro
|
|
32
|
+
# 或使用 pnpm
|
|
31
33
|
pnpm add @qin-ui/element-plus-pro element-plus
|
|
32
34
|
```
|
|
33
35
|
|
|
34
36
|
---
|
|
35
37
|
|
|
38
|
+
## 🤖 AI 辅助开发
|
|
39
|
+
|
|
40
|
+
本项目内置 AI 上下文初始化工具。安装后在项目根目录执行:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx @qin-ui/element-plus-pro init-ai
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
将在项目中生成双载体 AI 上下文,使 Cursor / Claude Code / Codex 等 AI 工具深度理解本库的 Schema 驱动用法与属性透传规则:
|
|
47
|
+
|
|
48
|
+
- `AGENTS.md` - 核心使用规则(跨工具开放约定,会话时自动注入,AI 默认加载)
|
|
49
|
+
- `.agents/skills/element-plus-pro.md` - 完整 API 参考(支持 skills 发现的工具按需调取)
|
|
50
|
+
|
|
51
|
+
> 生成的 `AGENTS.md` 使用标记区块写入,重复执行 `init-ai` 可安全更新,不影响项目内其他库的指令。建议将生成的文件提交到 Git 仓库,团队共享 AI 上下文。
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
36
55
|
## 🚀 快速开始
|
|
37
56
|
|
|
38
57
|
### 1. 全局配置与注册
|
|
@@ -62,34 +81,30 @@ interface UserForm {
|
|
|
62
81
|
role: string;
|
|
63
82
|
}
|
|
64
83
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
label: '
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
],
|
|
90
|
-
},
|
|
91
|
-
]
|
|
92
|
-
);
|
|
84
|
+
const form = useForm<UserForm>({ username: '', age: 18, role: 'user' }, [
|
|
85
|
+
{
|
|
86
|
+
path: 'username',
|
|
87
|
+
label: '用户名',
|
|
88
|
+
component: 'input',
|
|
89
|
+
rules: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
path: 'age',
|
|
93
|
+
label: '年龄',
|
|
94
|
+
component: 'input-number',
|
|
95
|
+
min: 1,
|
|
96
|
+
max: 120,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
path: 'role',
|
|
100
|
+
label: '角色',
|
|
101
|
+
component: 'select',
|
|
102
|
+
options: [
|
|
103
|
+
{ label: '管理员', value: 'admin' },
|
|
104
|
+
{ label: '普通用户', value: 'user' },
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
]);
|
|
93
108
|
|
|
94
109
|
const handleSubmit = async () => {
|
|
95
110
|
try {
|
|
@@ -123,7 +138,6 @@ interface UserRow {
|
|
|
123
138
|
age: number;
|
|
124
139
|
}
|
|
125
140
|
|
|
126
|
-
// 使用适配 Element Plus 的 useTable 实例
|
|
127
141
|
const table = useTable<any, UserRow>({
|
|
128
142
|
columns: [
|
|
129
143
|
{ prop: 'id', label: 'ID', width: 80 },
|
|
@@ -146,6 +160,30 @@ const table = useTable<any, UserRow>({
|
|
|
146
160
|
|
|
147
161
|
---
|
|
148
162
|
|
|
163
|
+
## 🧱 属性分层透传(核心规则)
|
|
164
|
+
|
|
165
|
+
ProForm/ProTable 是渲染引擎,所有真实 UI 来自 element-plus。**Field 上的属性会被"剥离到不同 DOM 层",不是全塞给输入控件**。写错层就会失效,这是最容易踩的坑:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
<el-col :span="8"> ← Grid 层(仅 grid 开启时)
|
|
169
|
+
<el-form-item label="..."> ← FormItem 层
|
|
170
|
+
<el-input placeholder /> ← 输入控件层
|
|
171
|
+
</el-form-item>
|
|
172
|
+
</el-col>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
| 属性 | 落到哪一层 | 说明 |
|
|
176
|
+
| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------- | :------------------- |
|
|
177
|
+
| `span` / `offset` / `push` / `pull` / `xs`..`xl` | `<el-col>` Grid 层 | 仅 `grid` 开启时生效 |
|
|
178
|
+
| `label` / `rules` / `error` / `required` / `size` / `showMessage` / `inlineMessage` / `labelWidth` / `formItemStyle` / `formItemClass` / `formItemDataAttrs` | `<el-form-item>` 层 | 表单项相关属性 |
|
|
179
|
+
| `disabled` / `placeholder` / `clearable` / `options` / `filterable` / `multiple` / `maxlength` / `componentStyle` / `componentClass` / `componentDataAttrs` + 该控件其余 element-plus 原生属性 | 输入控件本身(`el-input` 等) | 其余全部 |
|
|
180
|
+
| `component` / `hidden` / `modelProp` / `valueFormatter` / `fields` / `slots` / `formItemContainer` / `componentContainer` / `extraProps` | ProForm 逻辑消费,**不绑到 DOM** | 框架级属性 |
|
|
181
|
+
|
|
182
|
+
> **规则**:`span` 给 Grid,`label`/`rules` 给 FormItem,其余给输入控件。输入控件的具体属性名/类型请以 [element-plus 官方文档](https://element-plus.org) 为准。
|
|
183
|
+
> **element-plus 命名约定**:用 `clearable`(不是 `allowClear`)、`showWordLimit`(不是 `showCount`)、`filterable`(不是 `searchable`)。
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
149
187
|
## 📚 组件 API 说明
|
|
150
188
|
|
|
151
189
|
### 1. ProComponentProvider
|
|
@@ -158,6 +196,26 @@ const table = useTable<any, UserRow>({
|
|
|
158
196
|
| :--------------- | :-------------------------------------- | :-------------- | :----- |
|
|
159
197
|
| `component-vars` | 需要全局 provide 给子组件的默认属性配置 | `ComponentVars` | - |
|
|
160
198
|
|
|
199
|
+
#### 内置默认预设(INJECT_CONFIG)
|
|
200
|
+
|
|
201
|
+
ProComponentProvider 内置了一套默认属性预设,**即使不配置 `component-vars` 也会生效**。Field 配置优先级最高,会覆盖这些预设。以下为各组件的内置默认值(写代码时需知晓,避免行为与预期不符):
|
|
202
|
+
|
|
203
|
+
| component | 默认预设 |
|
|
204
|
+
| :----------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
205
|
+
| `switch` | `{ modelProp: 'modelValue' }` -- v-model 绑定 `modelValue`(element-plus 惯例,即 `v-model`) |
|
|
206
|
+
| `input` | `{ maxlength: 100, clearable: true, placeholder: '请输入' }` |
|
|
207
|
+
| `input.textarea` | `{ maxlength: 200, autosize: { minRows: 3, maxRows: 6 }, showWordLimit: true, clearable: true, placeholder: '请输入' }` |
|
|
208
|
+
| `input.password` | `{ showPassword: true, maxlength: 100, clearable: true, placeholder: '请输入' }` |
|
|
209
|
+
| `input-number` | `{ max: 1e15-1, min: -(1e15+1), controls: false, placeholder: '请输入', style: { width: '100%' } }` |
|
|
210
|
+
| `select` / `cascader` / `autocomplete` / `tree-select` | `{ clearable: true, placeholder: '请选择' }` |
|
|
211
|
+
| `date-picker` / `time-picker` / `time-select` | `{ style: { width: '100%' }, placeholder: '请选择' }` |
|
|
212
|
+
| `pro-form` | `{ grid: { gutter: 24 } }` |
|
|
213
|
+
| `pro-form-item` | `{ span: 8 }` |
|
|
214
|
+
| `pro-table` | `{ pagination: { layout: 'total,sizes,prev,pager,next,jumper', pageSizes: [10,20,30,40,50,100], background: true }, searchFormConfig: { layout: 'grid', expand: { minExpandRows: 2 } }, control: true, addIndexColumn: true }` |
|
|
215
|
+
|
|
216
|
+
> `modelProp` 控制 v-model 绑定的属性名,element-plus 默认 `'modelValue'`(即 `v-model`)。`switch` 经预设同样为 `modelValue`,通常无需手动设置。
|
|
217
|
+
> `date-picker` 支持按 type 子类型分别预设:`date-picker.date` / `.daterange` / `.datetime` / `.week` / `.month` / `.monthrange` / `.year` / `.yearrange` 等。
|
|
218
|
+
|
|
161
219
|
---
|
|
162
220
|
|
|
163
221
|
### 2. ProForm
|
|
@@ -169,27 +227,60 @@ const table = useTable<any, UserRow>({
|
|
|
169
227
|
| 参数名 | 说明 | 类型 | 默认值 |
|
|
170
228
|
| :----- | :------------------------------------------------------- | :--------------------- | :------ |
|
|
171
229
|
| `form` | 由 `useForm` 返回的表单实例 | `Form` | - |
|
|
172
|
-
| `grid` |
|
|
230
|
+
| `grid` | 是否启用栅格网格布局,支持传入 Grid 配置以配置自适应 | `boolean \| GridProps` | `false` |
|
|
173
231
|
| `...` | 其余属性均继承自 Element Plus `el-form` 组件的原生 Props | `FormProps` | - |
|
|
174
232
|
|
|
175
233
|
---
|
|
176
234
|
|
|
177
235
|
### 3. ProTable
|
|
178
236
|
|
|
179
|
-
基于 Element Plus Table
|
|
237
|
+
基于 Element Plus Table 深度封装的高级表格组件,将搜索表单、列配置、分页高度集成。
|
|
180
238
|
|
|
181
239
|
#### Props
|
|
182
240
|
|
|
183
|
-
| 参数名 | 说明
|
|
184
|
-
| :----------------- |
|
|
185
|
-
| `table` | 由 `useTable` 返回的表格实例
|
|
186
|
-
| `search` | 触发表格查询的回调函数,需返回 Promise
|
|
187
|
-
| `addIndexColumn` | 是否自动在表格首列插入序号列
|
|
188
|
-
| `immediateSearch` | 表格挂载时(onMounted)是否立即触发一次 `search` 查询
|
|
189
|
-
| `control` |
|
|
190
|
-
| `searchFormConfig` | 查询表单的布局配置参数
|
|
191
|
-
| `tableContainer` | 表格的外部包裹容器,默认为 false
|
|
192
|
-
| `...` | 其余参数继承自 Element Plus `el-table` 的原生属性
|
|
241
|
+
| 参数名 | 说明 | 类型 | 默认值 |
|
|
242
|
+
| :----------------- | :-------------------------------------------------------- | :------------------------------------- | :------ |
|
|
243
|
+
| `table` | 由 `useTable` 返回的表格实例 | `Table` | - |
|
|
244
|
+
| `search` | 触发表格查询的回调函数,需返回 Promise 或直接返回查询数据 | `(params: any) => Promise<any> \| any` | - |
|
|
245
|
+
| `addIndexColumn` | 是否自动在表格首列插入序号列 | `boolean` | `false` |
|
|
246
|
+
| `immediateSearch` | 表格挂载时(onMounted)是否立即触发一次 `search` 查询 | `boolean` | `false` |
|
|
247
|
+
| `control` | 是否在表格右上角工具栏中展示尺寸调节和列动态显示控制按钮 | `boolean` | `true` |
|
|
248
|
+
| `searchFormConfig` | 查询表单的布局配置参数 | `SearchFormConfig` | - |
|
|
249
|
+
| `tableContainer` | 表格的外部包裹容器,默认为 false | `Component \| false` | - |
|
|
250
|
+
| `...` | 其余参数继承自 Element Plus `el-table` 的原生属性 | `TableProps` | - |
|
|
251
|
+
|
|
252
|
+
#### Slots
|
|
253
|
+
|
|
254
|
+
| 插槽名 | 说明 |
|
|
255
|
+
| :------------ | :------------------------------------------------- |
|
|
256
|
+
| `search-form` | 自定义搜索栏表单内容 |
|
|
257
|
+
| `button-bar` | 自定义操作按钮组区域(位于搜索栏下方,表格左上方) |
|
|
258
|
+
| `toolbar` | 自定义工具栏区域(位于表格右上方控制按钮旁) |
|
|
259
|
+
| `table` | 完全自定义渲染表格区域 |
|
|
260
|
+
|
|
261
|
+
#### 数据流
|
|
262
|
+
|
|
263
|
+
ProTable 不会自动请求数据,**查询由你提供的 `search` 回调驱动**。内部串联逻辑:
|
|
264
|
+
|
|
265
|
+
```
|
|
266
|
+
点击搜索 -> 重置分页到第 1 页 -> 调用 search()
|
|
267
|
+
分页/排序变化 -> 更新 pageParam -> 调用 search()
|
|
268
|
+
点击重置 -> resetQueryParams() -> 调用 search()
|
|
269
|
+
挂载(immediateSearch) -> 立即触发一次 -> 调用 search()
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
`search` 回调内通常组装查询参数并赋值数据源:
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
const fetchData = async () => {
|
|
276
|
+
const res = await api.list({
|
|
277
|
+
...table.searchForm.formData, // 搜索条件
|
|
278
|
+
...table.pageParam, // 分页
|
|
279
|
+
});
|
|
280
|
+
table.data.value = res.data; // element-plus 语义:data(非 dataSource)
|
|
281
|
+
table.setPageParam({ total: res.total });
|
|
282
|
+
};
|
|
283
|
+
```
|
|
193
284
|
|
|
194
285
|
---
|
|
195
286
|
|
|
@@ -197,7 +288,7 @@ const table = useTable<any, UserRow>({
|
|
|
197
288
|
|
|
198
289
|
### 1. `useForm`
|
|
199
290
|
|
|
200
|
-
|
|
291
|
+
用于创建表单管理对象,整合了表单数据、字段规则和 ref 控制。
|
|
201
292
|
|
|
202
293
|
#### 入参定义
|
|
203
294
|
|
|
@@ -205,20 +296,25 @@ const table = useTable<any, UserRow>({
|
|
|
205
296
|
const form = useForm<D>(initFormData?, initFields?, root?)
|
|
206
297
|
```
|
|
207
298
|
|
|
299
|
+
- `initFormData`: 表单初始数据对象(`DeepPartial<D>`)
|
|
300
|
+
- `initFields`: 初始字段配置数组(`Field[]`)
|
|
301
|
+
- `root`: 是否创建根 Form 实例,默认为 `true`。若为 `false`,则内部会隐式 inject 父级表单上下文。
|
|
302
|
+
|
|
208
303
|
#### 返回值 (Form 实例)
|
|
209
304
|
|
|
210
|
-
| 属性/方法 | 说明
|
|
211
|
-
| :----------------------------- |
|
|
212
|
-
| `formData` | 响应式表单数据对象(由 reactive 包装)
|
|
213
|
-
| `fields` | 响应式表单字段配置数组引用
|
|
214
|
-
| `formRef` | 底层 Element Plus `el-form` 的组件引用实例
|
|
215
|
-
| `getFormData(path)` |
|
|
216
|
-
| `setFormData(path, val)` | 安全更新指定路径的值,支持批量对象或函数式更新
|
|
217
|
-
| `getField(path, opts?)` | 获取指定 path
|
|
218
|
-
| `setField(path, patch, opts?)` |
|
|
219
|
-
| `deleteField(path)` |
|
|
220
|
-
| `appendField(path, field)` | 在特定的字段 path 后面,动态追加一个新的表单字段配置
|
|
221
|
-
| `prependField(path, field)` | 在特定的字段 path 前面,动态插入一个新的表单字段配置
|
|
305
|
+
| 属性/方法 | 说明 | 类型 |
|
|
306
|
+
| :----------------------------- | :---------------------------------------------------------------------------------- | :------------------------------- |
|
|
307
|
+
| `formData` | 响应式表单数据对象(由 reactive 包装) | `Reactive<D>` |
|
|
308
|
+
| `fields` | 响应式表单字段配置数组引用 | `Ref<Field[]>` |
|
|
309
|
+
| `formRef` | 底层 Element Plus `el-form` 的组件引用实例 | `Ref<FormInstance \| undefined>` |
|
|
310
|
+
| `getFormData(path)` | 安全获取指定字段路径(支持深层 'a.b')的数据值 | `(path) => any` |
|
|
311
|
+
| `setFormData(path, val)` | 安全更新指定路径的值,支持批量对象或函数式更新 | `(path, val) => void` |
|
|
312
|
+
| `getField(path, opts?)` | 获取指定 path 的字段配置,支持查找函数定位,支持配置 `{ all: true }` 获取所有匹配项 | `(path, opts) => Field` |
|
|
313
|
+
| `setField(path, patch, opts?)` | 增量更新指定字段的配置参数(如改变 label、hidden 等),支持 merge 或 rewrite 更新 | `(path, patch, opts) => void` |
|
|
314
|
+
| `deleteField(path)` | 从当前配置数组中删除特定 path 的表单字段配置 | `(path) => void` |
|
|
315
|
+
| `appendField(path, field)` | 在特定的字段 path 后面,动态追加一个新的表单字段配置 | `(path, field) => void` |
|
|
316
|
+
| `prependField(path, field)` | 在特定的字段 path 前面,动态插入一个新的表单字段配置 | `(path, field) => void` |
|
|
317
|
+
| `getParentField(path)` | 查找获取当前子字段的父级配置项,一级字段返回虚拟根容器 | `(path) => Field` |
|
|
222
318
|
|
|
223
319
|
---
|
|
224
320
|
|
|
@@ -231,7 +327,7 @@ const form = useForm<D>(initFormData?, initFields?, root?)
|
|
|
231
327
|
```ts
|
|
232
328
|
const table = useTable<D, T>({
|
|
233
329
|
columns: [], // 初始列配置
|
|
234
|
-
data: [], // Element Plus
|
|
330
|
+
data: [], // Element Plus 数据源(语义对齐 Element Plus,而非 dataSource)
|
|
235
331
|
pageParam: {}, // 分页参数配置
|
|
236
332
|
searchParam: {}, // 搜索栏初始数据
|
|
237
333
|
searchFields: [], // 搜索栏字段 Schema 配置
|
|
@@ -240,18 +336,18 @@ const table = useTable<D, T>({
|
|
|
240
336
|
|
|
241
337
|
#### 返回值 (Table 实例)
|
|
242
338
|
|
|
243
|
-
| 属性/方法 | 说明
|
|
244
|
-
| :------------------------ |
|
|
245
|
-
| `columns` | 响应式表格列配置数组
|
|
246
|
-
| `data` |
|
|
247
|
-
| `pageParam` | 响应式分页参数对象(包含 `current`, `pageSize`, `total`)
|
|
248
|
-
| `searchForm` | 搜索栏表单关联的 `useForm` 实例,提供完美的表单操作 API
|
|
249
|
-
| `setColumn(key, patch)` | 合并或重置修改指定 key 的列配置属性(如 width、label 等)
|
|
250
|
-
| `deleteColumn(key)` | 动态移除某一个指定 key 对应的表格列配置
|
|
251
|
-
| `appendColumn(key, col)` | 在某一个列的后方动态追加配置列
|
|
252
|
-
| `prependColumn(key, col)` | 在某一个列的前方动态插入配置列
|
|
253
|
-
| `setPageParam(param)` | 增量设置当前分页参数值,支持传入对象或更新函数
|
|
254
|
-
| `resetQueryParams()` | 重置搜索参数,并恢复分页至第 1 页
|
|
339
|
+
| 属性/方法 | 说明 | 类型 |
|
|
340
|
+
| :------------------------ | :----------------------------------------------------------------- | :--------------------- |
|
|
341
|
+
| `columns` | 响应式表格列配置数组 | `Ref<Column[]>` |
|
|
342
|
+
| `data` | **响应式表格数据源(Element Plus 语义,对应 core 的 dataSource)** | `Ref<T[]>` |
|
|
343
|
+
| `pageParam` | 响应式分页参数对象(包含 `current`, `pageSize`, `total`) | `Reactive<PageParam>` |
|
|
344
|
+
| `searchForm` | 搜索栏表单关联的 `useForm` 实例,提供完美的表单操作 API | `Form<D>` |
|
|
345
|
+
| `setColumn(key, patch)` | 合并或重置修改指定 key 的列配置属性(如 width、label 等) | `(key, patch) => void` |
|
|
346
|
+
| `deleteColumn(key)` | 动态移除某一个指定 key 对应的表格列配置 | `(key) => void` |
|
|
347
|
+
| `appendColumn(key, col)` | 在某一个列的后方动态追加配置列 | `(key, col) => void` |
|
|
348
|
+
| `prependColumn(key, col)` | 在某一个列的前方动态插入配置列 | `(key, col) => void` |
|
|
349
|
+
| `setPageParam(param)` | 增量设置当前分页参数值,支持传入对象或更新函数 | `(param) => void` |
|
|
350
|
+
| `resetQueryParams()` | 重置搜索参数,并恢复分页至第 1 页 | `() => void` |
|
|
255
351
|
|
|
256
352
|
---
|
|
257
353
|
|
|
@@ -267,10 +363,13 @@ const table = useTable<D, T>({
|
|
|
267
363
|
|
|
268
364
|
> [!TIP]
|
|
269
365
|
> 渲染优先级为:`render(scope)` > `formatter`。
|
|
366
|
+
> Element Plus Table 列用 `prop`(不是 `dataIndex`),数据源用 `data`(不是 `dataSource`)。
|
|
270
367
|
|
|
271
368
|
---
|
|
272
369
|
|
|
273
|
-
## 📄 表单字段配置(`Field
|
|
370
|
+
## 📄 表单字段配置(`Field`)详解
|
|
371
|
+
|
|
372
|
+
在进行表单 Schema 编写时,`Field` 数组中的每一项都支持以下属性定义:
|
|
274
373
|
|
|
275
374
|
### 公共基础属性
|
|
276
375
|
|
|
@@ -296,6 +395,61 @@ const table = useTable<D, T>({
|
|
|
296
395
|
| `fields` | 嵌套子表单项的 Schema 数组配置 | `Field[]` | - |
|
|
297
396
|
| `grid` | 针对当前嵌套子表单项所使用的网格布局参数(仅当有 `fields` 时有效) | `boolean \| GridProps` | - |
|
|
298
397
|
|
|
398
|
+
#### `valueFormatter` 字段值转换
|
|
399
|
+
|
|
400
|
+
控制表单值与组件值之间的转换。在 `onUpdate:modelValue` 之前(即 v-model 写回前)执行,支持两种形态:
|
|
401
|
+
|
|
402
|
+
```ts
|
|
403
|
+
// 函数形态:(新值, 旧值) => 转换后的值,写回 formData
|
|
404
|
+
{ path: 'name', component: 'input', valueFormatter: (val, oldVal) => val?.trim() }
|
|
405
|
+
|
|
406
|
+
// 对象形态:get 读出时转换,set 写入时转换
|
|
407
|
+
{
|
|
408
|
+
path: 'birthday',
|
|
409
|
+
component: 'date-picker',
|
|
410
|
+
valueFormatter: {
|
|
411
|
+
get: (val) => (val ? new Date(val) : null), // formData -> 组件显示
|
|
412
|
+
set: (val) => (val ? dayjs(val).format('YYYY-MM-DD') : null), // 组件 -> formData
|
|
413
|
+
},
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
> ⚠️ `valueFormatter` 不支持响应式(不能包 `ref`/`computed`),与 `component` / `fields` / `slots` / `modelProp` 等同属不支持响应式的属性。
|
|
418
|
+
|
|
419
|
+
#### 🔄 响应式联动
|
|
420
|
+
|
|
421
|
+
控制类属性(`disabled` / `hidden` / `rules` 等)支持三种响应式模式,按场景选最简的:
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
// A. computed() 声明式 -- 初始化时已知的联动(首选)
|
|
425
|
+
disabled: computed(() => !form.formData.enabled),
|
|
426
|
+
rules: computed(() => form.formData.hasLimit ? [{ required: true, message: '必填' }] : []),
|
|
427
|
+
|
|
428
|
+
// B. ref() -- 外部共享状态
|
|
429
|
+
const isDisabled = ref(false);
|
|
430
|
+
disabled: isDisabled,
|
|
431
|
+
|
|
432
|
+
// C. setField() 命令式 -- 事件驱动的运行时变更
|
|
433
|
+
form.setField('limitCount', { disabled: true });
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
> **规则**:初始化时已知的联动用 `computed()`,运行时事件触发的用 `setField()`,外部共享状态用 `ref()`。能用 `computed()` 解决就不要用 `setField()`。
|
|
437
|
+
|
|
438
|
+
##### 不支持响应式的属性
|
|
439
|
+
|
|
440
|
+
以下属性不能包 `ref`/`computed`(会失效或引发渲染异常),只能传静态值:
|
|
441
|
+
|
|
442
|
+
| 属性 | 原因 |
|
|
443
|
+
| :----------------------------------------- | :-------------------------------------------------- |
|
|
444
|
+
| `component` | 组件对象/函数,响应式代理会破坏渲染(需 `markRaw`) |
|
|
445
|
+
| `valueFormatter` | 纯转换函数,无需响应式 |
|
|
446
|
+
| `fields` | 嵌套字段数组结构,响应式代理会干扰内部解析 |
|
|
447
|
+
| `slots` | 插槽内容,响应式代理会破坏渲染 |
|
|
448
|
+
| `modelProp` | 字符串标识,无需响应式 |
|
|
449
|
+
| `formItemContainer` / `componentContainer` | 容器组件,需 `markRaw` |
|
|
450
|
+
|
|
451
|
+
> 动态切换 `component` 或 `slots` 时,用 `setField()` 命令式更新,而非包 `computed`。
|
|
452
|
+
|
|
299
453
|
---
|
|
300
454
|
|
|
301
455
|
### 内置组件映射(`component` 可选值)
|
|
@@ -322,51 +476,116 @@ const table = useTable<D, T>({
|
|
|
322
476
|
|
|
323
477
|
---
|
|
324
478
|
|
|
325
|
-
|
|
479
|
+
### 🧩 自定义组件(4 种方式)
|
|
480
|
+
|
|
481
|
+
`Field.component` 的解析优先级(高 -> 低):
|
|
326
482
|
|
|
327
|
-
|
|
483
|
+
`teleport 插槽注入` > `ProComponentProvider.componentMap` > `内置 componentMap` > `原始 component 值`
|
|
484
|
+
|
|
485
|
+
#### 方式 1:传入 SFC 单文件组件对象(推荐,单字段最常用)
|
|
486
|
+
|
|
487
|
+
`component` 直接传组件对象,**必须用 `markRaw` 包裹**:
|
|
488
|
+
|
|
489
|
+
```ts
|
|
490
|
+
import { markRaw } from 'vue';
|
|
491
|
+
import MyInput from './MyInput.vue';
|
|
492
|
+
|
|
493
|
+
const fields = [{ path: 'code', label: '验证码', component: markRaw(MyInput) }];
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
> ⚠️ **必须 `markRaw`**:不包会被 Vue 当成响应式对象深度代理,触发性能警告甚至渲染异常。类型上 `component` 接受 `RenderComponentType | Raw<RenderComponentType>`,`Raw<T>` 即 markRaw 的类型标记。此字段不支持响应式(不能包 `ref`/`computed`)。
|
|
497
|
+
|
|
498
|
+
#### 方式 2:传入 render 函数(单字段,需动态拼装 props 时)
|
|
499
|
+
|
|
500
|
+
`component` 传 `(props, ctx) => VNode`。`props` 含 v-model 绑定值与 path,`ctx.attrs` 含透传属性:
|
|
501
|
+
|
|
502
|
+
```ts
|
|
503
|
+
import { h } from 'vue';
|
|
504
|
+
import MyInput from './MyInput.vue';
|
|
505
|
+
|
|
506
|
+
const fields = [
|
|
507
|
+
{
|
|
508
|
+
path: 'code',
|
|
509
|
+
label: '验证码',
|
|
510
|
+
component: (p, ctx) => h(MyInput, { ...p, ...ctx.attrs }),
|
|
511
|
+
},
|
|
512
|
+
];
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
#### 方式 3:ProComponentProvider 注入 componentMap(全局复用,推荐多字段场景)
|
|
516
|
+
|
|
517
|
+
在根用 `componentMap` 注册,Field 里用字符串引用。**可覆盖内置组件**(如 `input: MyInput` 替换全局 `input`)。
|
|
328
518
|
|
|
329
519
|
```vue
|
|
330
520
|
<script setup lang="ts">
|
|
331
521
|
import { ProComponentProvider } from '@qin-ui/element-plus-pro';
|
|
332
|
-
import
|
|
522
|
+
import MyRichTextEditor from './components/MyRichTextEditor.vue';
|
|
333
523
|
|
|
334
524
|
const componentMap = {
|
|
335
|
-
'
|
|
525
|
+
'rich-editor': MyRichTextEditor,
|
|
336
526
|
};
|
|
337
527
|
</script>
|
|
338
528
|
|
|
339
529
|
<template>
|
|
340
530
|
<ProComponentProvider :component-map="componentMap">
|
|
341
|
-
<
|
|
531
|
+
<AppLayout />
|
|
342
532
|
</ProComponentProvider>
|
|
343
533
|
</template>
|
|
344
534
|
```
|
|
345
535
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
在项目任意 `.d.ts` 类型文件中写入以下代码:
|
|
536
|
+
追加 TypeScript 全局声明获取强类型补全(项目任意 `.d.ts`):
|
|
349
537
|
|
|
350
538
|
```ts
|
|
351
539
|
declare module '@qin-ui/element-plus-pro' {
|
|
352
540
|
interface ComponentMap {
|
|
353
|
-
'
|
|
541
|
+
'rich-editor': typeof MyRichTextEditor;
|
|
354
542
|
}
|
|
355
543
|
}
|
|
356
544
|
```
|
|
357
545
|
|
|
546
|
+
之后 `component: 'rich-editor'` 即获精准属性类型联想与校验。
|
|
547
|
+
|
|
548
|
+
#### 方式 4:模板 scoped slot(声明式,简单替换)
|
|
549
|
+
|
|
550
|
+
插槽名 = 字段 `path`,绑定参数通过 `v-bind="scoped"` 转发(teleport 机制,优先级最高):
|
|
551
|
+
|
|
552
|
+
```vue
|
|
553
|
+
<ProForm :form="form">
|
|
554
|
+
<template #agreement="scoped">
|
|
555
|
+
<el-checkbox v-bind="scoped">同意协议</el-checkbox>
|
|
556
|
+
</template>
|
|
557
|
+
</ProForm>
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
#### 选择建议
|
|
561
|
+
|
|
562
|
+
| 场景 | 推荐方式 |
|
|
563
|
+
| :--------------------------- | :-------------------------------- |
|
|
564
|
+
| 单字段复用一个 SFC | 方式 1(`markRaw(SFC)`) |
|
|
565
|
+
| 单字段、需动态拼装 props | 方式 2(render 函数) |
|
|
566
|
+
| 多处复用 / 替换内置组件 | 方式 3(componentMap + 声明扩充) |
|
|
567
|
+
| 简单声明式替换、不想写 `h()` | 方式 4(scoped slot) |
|
|
568
|
+
|
|
569
|
+
#### 自定义组件需遵守的约定
|
|
570
|
+
|
|
571
|
+
- **v-model**:默认绑 `modelValue`(`v-model`)。若组件用别的 prop,通过字段 `modelProp` 指定,或在 `componentVars` 预设 `modelProp`。
|
|
572
|
+
- **接收 path**:组件会收到 `path` prop(字段路径),可用于透传或标识。
|
|
573
|
+
- **属性透传**:Field 上除框架级属性外(`component` / `hidden` / `modelProp` / `valueFormatter` / `fields` / `slots` / `formItemContainer` / `componentContainer` / `extraProps` 等),其余作为 attrs 透传给自定义组件。
|
|
574
|
+
|
|
358
575
|
---
|
|
359
576
|
|
|
360
577
|
## Peer Dependencies
|
|
361
578
|
|
|
362
|
-
|
|
363
|
-
|
|
579
|
+
| 依赖包名称 | 推荐版本要求 |
|
|
580
|
+
| :------------- | :----------- |
|
|
581
|
+
| `vue` | `^3.5.0` |
|
|
582
|
+
| `element-plus` | `^2.13.6` |
|
|
364
583
|
|
|
365
584
|
---
|
|
366
585
|
|
|
367
586
|
## 🤝 贡献与反馈
|
|
368
587
|
|
|
369
|
-
如有任何问题,欢迎通过 [GitHub Issues](https://github.com/dufan3715/pro-components/issues)
|
|
588
|
+
如有任何问题,欢迎通过 [GitHub Issues](https://github.com/dufan3715/pro-components/issues) 提交对本子包的优化建议和反馈。
|
|
370
589
|
|
|
371
590
|
## 📄 开源许可证
|
|
372
591
|
|