@xiaohaih/json-form-vant 0.0.1

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.
Files changed (213) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +807 -0
  3. package/TODO.md +36 -0
  4. package/components/area/index.ts +6 -0
  5. package/components/area/index.vue +120 -0
  6. package/components/area/types.ts +84 -0
  7. package/components/cascader/index.ts +6 -0
  8. package/components/cascader/index.vue +146 -0
  9. package/components/cascader/types.ts +75 -0
  10. package/components/checkbox/index.ts +6 -0
  11. package/components/checkbox/index.vue +59 -0
  12. package/components/checkbox/types.ts +54 -0
  13. package/components/checkbox-group/index.ts +6 -0
  14. package/components/checkbox-group/index.vue +67 -0
  15. package/components/checkbox-group/types.ts +63 -0
  16. package/components/component-definition/components.ts +29 -0
  17. package/components/component-definition/definition.ts +25 -0
  18. package/components/component-definition/index.ts +4 -0
  19. package/components/custom-render/index.ts +6 -0
  20. package/components/custom-render/index.vue +66 -0
  21. package/components/custom-render/types.ts +43 -0
  22. package/components/date-picker/index.ts +6 -0
  23. package/components/date-picker/index.vue +130 -0
  24. package/components/date-picker/types.ts +91 -0
  25. package/components/date-time-picker-group/index.ts +6 -0
  26. package/components/date-time-picker-group/index.vue +158 -0
  27. package/components/date-time-picker-group/types.ts +115 -0
  28. package/components/datetime-picker/index.ts +6 -0
  29. package/components/datetime-picker/index.vue +128 -0
  30. package/components/datetime-picker/types.ts +78 -0
  31. package/components/dynamic-group/index.ts +10 -0
  32. package/components/dynamic-group/index.vue +140 -0
  33. package/components/dynamic-group/types.ts +68 -0
  34. package/components/group/assist.ts +99 -0
  35. package/components/group/index.ts +7 -0
  36. package/components/group/index.vue +117 -0
  37. package/components/group/types.ts +57 -0
  38. package/components/group/virtual-group.vue +38 -0
  39. package/components/index.ts +10 -0
  40. package/components/input/index.ts +6 -0
  41. package/components/input/index.vue +83 -0
  42. package/components/input/types.ts +43 -0
  43. package/components/input-slot/index.ts +6 -0
  44. package/components/input-slot/index.vue +148 -0
  45. package/components/input-slot/types.ts +34 -0
  46. package/components/number-keyboard/index.ts +6 -0
  47. package/components/number-keyboard/index.vue +81 -0
  48. package/components/number-keyboard/types.ts +57 -0
  49. package/components/password-input/index.ts +6 -0
  50. package/components/password-input/index.vue +103 -0
  51. package/components/password-input/types.ts +64 -0
  52. package/components/picker/index.ts +6 -0
  53. package/components/picker/index.vue +136 -0
  54. package/components/picker/types.ts +94 -0
  55. package/components/radio/index.ts +6 -0
  56. package/components/radio/index.vue +68 -0
  57. package/components/radio/types.ts +58 -0
  58. package/components/radio-group/index.ts +6 -0
  59. package/components/radio-group/index.vue +74 -0
  60. package/components/radio-group/types.ts +65 -0
  61. package/components/rate/index.ts +6 -0
  62. package/components/rate/index.vue +63 -0
  63. package/components/rate/types.ts +47 -0
  64. package/components/share.ts +78 -0
  65. package/components/signature/index.ts +6 -0
  66. package/components/signature/index.vue +65 -0
  67. package/components/signature/instance.vue +161 -0
  68. package/components/signature/types.ts +79 -0
  69. package/components/slider/index.ts +6 -0
  70. package/components/slider/index.vue +63 -0
  71. package/components/slider/types.ts +53 -0
  72. package/components/stepper/index.ts +6 -0
  73. package/components/stepper/index.vue +62 -0
  74. package/components/stepper/types.ts +47 -0
  75. package/components/switch/index.ts +6 -0
  76. package/components/switch/index.vue +61 -0
  77. package/components/switch/types.ts +51 -0
  78. package/components/time-picker/index.ts +6 -0
  79. package/components/time-picker/index.vue +130 -0
  80. package/components/time-picker/types.ts +91 -0
  81. package/components/tree-select/index.ts +6 -0
  82. package/components/tree-select/index.vue +160 -0
  83. package/components/tree-select/types.ts +77 -0
  84. package/components/upload/index.ts +6 -0
  85. package/components/upload/index.vue +109 -0
  86. package/components/upload/types.ts +85 -0
  87. package/components/use.ts +45 -0
  88. package/components/utils.ts +52 -0
  89. package/components/wrapper/index.ts +6 -0
  90. package/components/wrapper/index.vue +117 -0
  91. package/components/wrapper/types.ts +94 -0
  92. package/dist/components/area/index.d.ts +5 -0
  93. package/dist/components/area/index.vue.d.ts +1843 -0
  94. package/dist/components/area/types.d.ts +1434 -0
  95. package/dist/components/cascader/index.d.ts +5 -0
  96. package/dist/components/cascader/index.vue.d.ts +2467 -0
  97. package/dist/components/cascader/types.d.ts +1419 -0
  98. package/dist/components/checkbox/index.d.ts +5 -0
  99. package/dist/components/checkbox/index.vue.d.ts +1550 -0
  100. package/dist/components/checkbox/types.d.ts +1313 -0
  101. package/dist/components/checkbox-group/index.d.ts +5 -0
  102. package/dist/components/checkbox-group/index.vue.d.ts +1643 -0
  103. package/dist/components/checkbox-group/types.d.ts +1372 -0
  104. package/dist/components/component-definition/components.d.ts +30 -0
  105. package/dist/components/component-definition/index.d.ts +4 -0
  106. package/dist/components/custom-render/index.d.ts +5 -0
  107. package/dist/components/custom-render/index.vue.d.ts +1473 -0
  108. package/dist/components/custom-render/types.d.ts +1175 -0
  109. package/dist/components/date-picker/index.d.ts +5 -0
  110. package/dist/components/date-picker/index.vue.d.ts +1888 -0
  111. package/dist/components/date-picker/types.d.ts +1458 -0
  112. package/dist/components/date-time-picker-group/index.d.ts +5 -0
  113. package/dist/components/date-time-picker-group/index.vue.d.ts +2181 -0
  114. package/dist/components/date-time-picker-group/types.d.ts +1549 -0
  115. package/dist/components/dynamic-group/index.d.ts +5 -0
  116. package/dist/components/dynamic-group/index.vue.d.ts +457 -0
  117. package/dist/components/dynamic-group/types.d.ts +403 -0
  118. package/dist/components/group/assist.d.ts +58 -0
  119. package/dist/components/group/index.d.ts +6 -0
  120. package/dist/components/group/index.vue.d.ts +139 -0
  121. package/dist/components/group/types.d.ts +189 -0
  122. package/dist/components/group/virtual-group.vue.d.ts +42 -0
  123. package/dist/components/index.d.ts +3 -0
  124. package/dist/components/input/index.d.ts +5 -0
  125. package/dist/components/input/index.vue.d.ts +2229 -0
  126. package/dist/components/input/types.d.ts +1258 -0
  127. package/dist/components/input-slot/index.d.ts +5 -0
  128. package/dist/components/input-slot/index.vue.d.ts +626 -0
  129. package/dist/components/input-slot/types.d.ts +311 -0
  130. package/dist/components/number-keyboard/index.d.ts +5 -0
  131. package/dist/components/number-keyboard/index.vue.d.ts +1643 -0
  132. package/dist/components/number-keyboard/types.d.ts +1324 -0
  133. package/dist/components/password-input/index.d.ts +5 -0
  134. package/dist/components/password-input/index.vue.d.ts +1715 -0
  135. package/dist/components/password-input/types.d.ts +1357 -0
  136. package/dist/components/picker/index.d.ts +5 -0
  137. package/dist/components/picker/index.vue.d.ts +1868 -0
  138. package/dist/components/picker/types.d.ts +1466 -0
  139. package/dist/components/radio/index.d.ts +5 -0
  140. package/dist/components/radio/index.vue.d.ts +1563 -0
  141. package/dist/components/radio/types.d.ts +1327 -0
  142. package/dist/components/radio-group/index.d.ts +5 -0
  143. package/dist/components/radio-group/index.vue.d.ts +1617 -0
  144. package/dist/components/radio-group/types.d.ts +1383 -0
  145. package/dist/components/rate/index.d.ts +5 -0
  146. package/dist/components/rate/index.vue.d.ts +1557 -0
  147. package/dist/components/rate/types.d.ts +1281 -0
  148. package/dist/components/share.d.ts +679 -0
  149. package/dist/components/signature/index.d.ts +5 -0
  150. package/dist/components/signature/index.vue.d.ts +3017 -0
  151. package/dist/components/signature/instance.vue.d.ts +1614 -0
  152. package/dist/components/signature/types.d.ts +1369 -0
  153. package/dist/components/slider/index.d.ts +5 -0
  154. package/dist/components/slider/index.vue.d.ts +1563 -0
  155. package/dist/components/slider/types.d.ts +1302 -0
  156. package/dist/components/stepper/index.d.ts +5 -0
  157. package/dist/components/stepper/index.vue.d.ts +1620 -0
  158. package/dist/components/stepper/types.d.ts +1281 -0
  159. package/dist/components/switch/index.d.ts +5 -0
  160. package/dist/components/switch/index.vue.d.ts +1529 -0
  161. package/dist/components/switch/types.d.ts +1296 -0
  162. package/dist/components/time-picker/index.d.ts +5 -0
  163. package/dist/components/time-picker/index.vue.d.ts +1936 -0
  164. package/dist/components/time-picker/types.d.ts +1458 -0
  165. package/dist/components/tree-select/index.d.ts +5 -0
  166. package/dist/components/tree-select/index.vue.d.ts +1802 -0
  167. package/dist/components/tree-select/types.d.ts +1411 -0
  168. package/dist/components/upload/index.d.ts +5 -0
  169. package/dist/components/upload/index.vue.d.ts +1697 -0
  170. package/dist/components/upload/types.d.ts +1376 -0
  171. package/dist/components/use.d.ts +53 -0
  172. package/dist/components/utils.d.ts +15 -0
  173. package/dist/components/wrapper/index.d.ts +5 -0
  174. package/dist/components/wrapper/index.vue.d.ts +1085 -0
  175. package/dist/components/wrapper/types.d.ts +541 -0
  176. package/dist/docs/.vitepress/config.d.ts +3 -0
  177. package/dist/docs/.vitepress/theme/index.d.ts +2 -0
  178. package/dist/index.cjs.js +5459 -0
  179. package/dist/index.cjs.js.map +1 -0
  180. package/dist/index.cjs.min.js +3568 -0
  181. package/dist/index.cjs.min.js.map +1 -0
  182. package/dist/index.esm.js +5264 -0
  183. package/dist/index.esm.js.map +1 -0
  184. package/dist/index.esm.min.js +3559 -0
  185. package/dist/index.esm.min.js.map +1 -0
  186. package/dist/index.umd.js +5465 -0
  187. package/dist/index.umd.js.map +1 -0
  188. package/dist/index.umd.min.js +3573 -0
  189. package/dist/index.umd.min.js.map +1 -0
  190. package/dist/src/assist.d.ts +32 -0
  191. package/dist/src/index.d.ts +5 -0
  192. package/dist/src/interface.d.ts +129 -0
  193. package/dist/src/utils.d.ts +9 -0
  194. package/dist/src/version.d.ts +2 -0
  195. package/docs/.vitepress/config.ts +99 -0
  196. package/docs/.vitepress/theme/index.ts +5 -0
  197. package/docs/README.md +20 -0
  198. package/docs/index.md +25 -0
  199. package/env.d.ts +8 -0
  200. package/package.json +71 -0
  201. package/scripts/generate-version.mjs +26 -0
  202. package/scripts/postinstall.cjs +13 -0
  203. package/scripts/utils.cjs +67 -0
  204. package/src/assist.ts +40 -0
  205. package/src/index.ts +5 -0
  206. package/src/interface.ts +293 -0
  207. package/src/utils.ts +22 -0
  208. package/src/version.ts +2 -0
  209. package/tsconfig.app.json +41 -0
  210. package/tsconfig.json +7 -0
  211. package/tsconfig.node.json +24 -0
  212. package/tsdown.config.ts +12 -0
  213. package/vite.config.ts +93 -0
package/README.md ADDED
@@ -0,0 +1,807 @@
1
+ # @xiaohaih/json-form-vant
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@xiaohaih/json-form-vant.svg)](https://www.npmjs.com/package/@xiaohaih/json-form-vant)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@xiaohaih/json-form-vant.svg)](https://www.npmjs.com/package/@xiaohaih/json-form-vant)
5
+
6
+ `@xiaohaih/json-form-vant` 是基于 Vant 的 json-form 适配层, 提供现代化的表单组件解决方案。通过 JSON 配置即可渲染完整的表单, 支持表单项间的依赖关系、数据校验等高级功能。
7
+
8
+ ## ✨ 特性
9
+
10
+ - 🎨 **Vant 集成**: 深度集成 Vant 组件库
11
+ - 📋 **JSON 配置**: 通过 JSON 对象配置表单结构, 支持配置动态表单
12
+ - 🔗 **依赖关系**: 支持表单项间的复杂依赖关系
13
+ - ✅ **表单校验**: 复用 Vant 的校验机制
14
+ - 🎯 **类型安全**: 完整的 TypeScript 类型定义
15
+ - 🔧 **高度可定制**: 支持所有 Vant 组件属性和插槽
16
+ - 📱 **响应式**: 支持响应式表单配置
17
+ - 🚀 **开箱即用**: 无需额外配置, 开箱即用
18
+ - 🎪 **Vue 3 原生**: 基于 Vue 3 Composition API
19
+
20
+ ## 📚 在线文档
21
+
22
+ - [Vant 版本文档](https://xiaohaih.github.io/json-form/docs-vant/index.html)
23
+
24
+ ## 📦 安装
25
+
26
+ ```bash
27
+ # 使用 pnpm
28
+ pnpm add @xiaohaih/json-form-vant
29
+
30
+ # 或使用 npm
31
+ npm install @xiaohaih/json-form-vant
32
+
33
+ # 或使用 yarn
34
+ yarn add @xiaohaih/json-form-vant
35
+ ```
36
+
37
+ ## 🏗️ 架构设计
38
+
39
+ ### 设计理念
40
+
41
+ Vant 适配层基于 `@xiaohaih/json-form-core` 核心模块实现, 将纯逻辑层与 UI 层完美结合:
42
+
43
+ ```
44
+ JSON 配置 ──► 适配层解析 ──► Vant 组件
45
+ │ │
46
+ └──────────────┼──────────────► 核心逻辑层
47
+
48
+
49
+ 依赖管理、校验、状态同步
50
+ ```
51
+
52
+ ### 核心组件
53
+
54
+ #### HForm (主表单组件)
55
+
56
+ 表单容器组件,负责:
57
+
58
+ - 解析 JSON 配置
59
+ - 管理表单状态
60
+ - 协调组件间通信
61
+ - 处理表单提交和校验
62
+
63
+ #### 表单项组件
64
+
65
+ 支持的所有表单项类型:
66
+
67
+ - **基础输入**: `input`, `input-number`, `autocomplete`
68
+ - **选择器**: `select`, `cascader`, `radio`, `radio-group`, `checkbox`, `checkbox-group`, `tree-select`
69
+ - **日期时间**: `date-picker`, `time-picker`
70
+ - **其他**: `switch`, `slider`, `rate`, `color-picker`, `upload` 等
71
+
72
+ ## 🚀 快速开始
73
+
74
+ ### 基础用法
75
+
76
+ ```vue
77
+ <template>
78
+ <HForm :model-value="formData" :config="formConfig">
79
+ <VanButton @click="submit">
80
+ 提交
81
+ </VanButton>
82
+ </HForm>
83
+ </template>
84
+
85
+ <script setup lang="ts">
86
+ import { defineOption, HForm } from '@xiaohaih/json-form-vant';
87
+ import { ref } from 'vue';
88
+
89
+ const formData = ref({
90
+ username: '',
91
+ email: '',
92
+ password: '',
93
+ });
94
+
95
+ /** 数组形式定义 */
96
+ const formConfig = defineOption([
97
+ {
98
+ field: 'username',
99
+ t: 'input',
100
+ label: '用户名',
101
+ placeholder: '请输入用户名',
102
+ rules: [
103
+ { required: true, message: '请输入用户名' },
104
+ ],
105
+ },
106
+ {
107
+ field: 'email',
108
+ t: 'input',
109
+ label: '邮箱',
110
+ placeholder: '请输入邮箱',
111
+ },
112
+ {
113
+ field: 'password',
114
+ t: 'input',
115
+ label: '密码',
116
+ type: 'password',
117
+ placeholder: '请输入密码',
118
+ showPassword: true,
119
+ },
120
+ ]);
121
+
122
+ function submit() {
123
+ console.log('提交数据:', formData.value);
124
+ }
125
+ </script>
126
+ ```
127
+
128
+ ### 依赖关系
129
+
130
+ ```typescript
131
+ /** 对象形式定义 */
132
+ const formConfig = defineOption({
133
+ province: {
134
+ t: 'select',
135
+ label: '省份',
136
+ options: [
137
+ { label: '北京市', value: 'beijing' },
138
+ { label: '上海市', value: 'shanghai' },
139
+ ],
140
+ },
141
+ city: {
142
+ t: 'select',
143
+ label: '城市',
144
+ depend: true,
145
+ dependFields: 'province',
146
+ async getOptions(cb, query) {
147
+ const cities = await fetchCities(query.province);
148
+ cb(cities);
149
+ },
150
+ },
151
+ });
152
+ ```
153
+
154
+ ## 📚 API 参考
155
+
156
+ ### HForm Props
157
+
158
+ | 属性名 | 类型 | 默认值 | 描述 |
159
+ | :---------- | :-------------------------------- | :------ | :--------------- |
160
+ | v-model | `Record<string, any>` | - | 表单数据双向绑定 |
161
+ | config | `ReturnType<typeof defineOption>` | - | 表单配置对象 |
162
+ | label-width | `string \| number` | - | 标签宽度 |
163
+ | readonly | `boolean` | `false` | 是否只读 |
164
+ | disabled | `boolean` | `false` | 是否禁用 |
165
+ | rules | `Record<string, Rule[]>` | - | 表单级校验规则 |
166
+
167
+ ### HForm Events
168
+
169
+ | 事件名 | 参数 | 描述 |
170
+ | :----- | :------------------------------------ | :------- |
171
+ | search | `(data: Record<string, any>) => void` | 搜索事件 |
172
+
173
+ ### HForm Methods
174
+
175
+ | 方法名 | 参数 | 描述 |
176
+ | :------------ | :------------------------------------------------- | :----------- |
177
+ | validate | `() => Promise<boolean>` | 校验表单 |
178
+ | validateField | `(fields: string \| string[]) => Promise<boolean>` | 校验指定字段 |
179
+ | clearValidate | `(fields?: string \| string[]) => void` | 清空校验 |
180
+ | reset | `() => void` | 重置表单 |
181
+
182
+ ### defineOption
183
+
184
+ 用于创建响应式表单配置的函数。
185
+
186
+ - 推荐用数组形式, 能推断出子级 `config` 下的字段, 且通过函数返回配置值时, 不主动声明泛型参数时, `typescript` 也不会报错
187
+ - 数组形式定义配置项时, 如果声明报错, 可以试试在数组后加上 `const`(深层 `config` 是函数形式返回时会出现这种声明报错) -> `defineOption([{}, ...config] as const)`
188
+ - 未补充泛型声明时, 不建议通过函数返回对象形式的配置项(声明会报错)
189
+
190
+ ```typescript
191
+ // 数组形式创建配置项
192
+ function defineOption(config: JSONFormOption[]): JSONFormOption[];
193
+ // 基于函数返回数组形式创建配置项
194
+ function defineOption(config: (option: ConfigOption) => JSONFormOption[]): () => JSONFormOption[];
195
+ // 对象形式创建配置项
196
+ function defineOption(config: Record<string, JSONFormOption>): Record<string, JSONFormOption>;
197
+ // 基于函数返回对象形式创建配置项
198
+ function defineOption(config: (option: ConfigOption) => Record<string, JSONFormOption>): () => Record<string, JSONFormOption>;
199
+
200
+ interface ConfigOption {
201
+ /** 表单的 model 对象 */
202
+ query: Record<string, any>;
203
+ /** 表单级的共用属性 */
204
+ wrapper: ReturnType<typeof useWrapper>;
205
+ /** vant 表单实例 */
206
+ formRef: ReturnType<typeof ElForm>;
207
+ }
208
+ ```
209
+
210
+ ### 字段配置结构
211
+
212
+ ```typescript
213
+ interface BaseFieldConfig {
214
+ // 组件类型标识
215
+ t: string;
216
+
217
+ // 显示标签
218
+ label?: string;
219
+
220
+ // 默认值
221
+ defaultValue?: any;
222
+
223
+ // 占位符
224
+ placeholder?: string;
225
+
226
+ // 是否必填
227
+ required?: boolean;
228
+
229
+ // 校验规则
230
+ rules?: Rule[];
231
+
232
+ // 是否隐藏(v-if隐藏 form-item)
233
+ hide?: boolean;
234
+
235
+ // 依赖配置
236
+ depend?: boolean;
237
+ dependFields?: string | string[];
238
+
239
+ // 数据源
240
+ options?: any[];
241
+ getOptions?: (cb: (data: any) => void, query: Record<string, any>) => void;
242
+
243
+ // 表单组件属性(直接传递给 Vant 组件), 与 FormItem Prop 冲突的属性
244
+ contentProps?: Record<string, any>;
245
+
246
+ // 插槽配置
247
+ slots?: Record<string, any>;
248
+ itemSlots?: Record<string, any>;
249
+
250
+ // 其他配置
251
+ [key: string]: any;
252
+ }
253
+ ```
254
+
255
+ ## 🎛️ 支持的组件类型
256
+
257
+ ### 基础输入
258
+
259
+ #### `input` - 文本输入框
260
+
261
+ ```typescript
262
+ const formConfig = defineOption([
263
+ {
264
+ field: 'username',
265
+ t: 'input',
266
+ label: '用户名',
267
+ placeholder: '请输入用户名',
268
+ clearable: true,
269
+ maxlength: 20,
270
+ showWordLimit: true,
271
+ rules: [
272
+ { required: true, message: '请输入用户名' },
273
+ ],
274
+ },
275
+ ]);
276
+ ```
277
+
278
+ #### `input-number` - 数字输入框
279
+
280
+ ```javascript
281
+ const formConfig = defineOption([
282
+ {
283
+ field: 'age',
284
+ t: 'input-number',
285
+ label: '年龄',
286
+ min: 0,
287
+ max: 120,
288
+ step: 1,
289
+ precision: 0,
290
+ },
291
+ ]);
292
+ ```
293
+
294
+ #### `autocomplete` - 自动补全输入框
295
+
296
+ ```javascript
297
+ const formConfig = defineOption([
298
+ {
299
+ field: 'city',
300
+ t: 'autocomplete',
301
+ label: '城市',
302
+ placeholder: '请输入城市',
303
+ getOptions(cb) {
304
+ const { status, data } = fetchData();
305
+ cb(status ? data : []);
306
+ },
307
+ itemSlots: {
308
+ suffix: () => <ElIcon><Search /></ElIcon>,
309
+ },
310
+ },
311
+ ]);
312
+ ```
313
+
314
+ ### 选择器
315
+
316
+ #### `select` - 下拉选择
317
+
318
+ ```typescript
319
+ const formConfig = defineOption([
320
+ {
321
+ field: 'status',
322
+ t: 'select',
323
+ label: '状态',
324
+ options: [
325
+ { label: '启用', value: 1 },
326
+ { label: '禁用', value: 0 },
327
+ ],
328
+ clearable: true,
329
+ filterable: true,
330
+ },
331
+ ]);
332
+ ```
333
+
334
+ #### `select-v2` - 虚拟化下拉选择
335
+
336
+ ```javascript
337
+ const formConfig = defineOption([
338
+ {
339
+ field: 'user',
340
+ t: 'select-v2',
341
+ label: '用户',
342
+ options: largeUserList,
343
+ placeholder: '请选择用户',
344
+ filterable: true,
345
+ },
346
+ ]);
347
+ ```
348
+
349
+ #### `cascader` - 级联选择
350
+
351
+ ```javascript
352
+ const formConfig = defineOption([
353
+ {
354
+ field: 'region',
355
+ t: 'cascader',
356
+ label: '地区',
357
+ options: regionData,
358
+ props: { value: 'code', label: 'name', children: 'children' },
359
+ filterable: true,
360
+ showAllLevels: false,
361
+ },
362
+ ]);
363
+ ```
364
+
365
+ #### `tree-select` - 树形选择
366
+
367
+ ```javascript
368
+ const formConfig = defineOption([
369
+ {
370
+ field: 'department',
371
+ t: 'tree-select',
372
+ label: '部门',
373
+ data: treeData,
374
+ props: { value: 'id', label: 'name', children: 'children' },
375
+ multiple: true,
376
+ checkStrictly: true,
377
+ },
378
+ ]);
379
+ ```
380
+
381
+ #### `radio-group` - 单选框组
382
+
383
+ ```javascript
384
+ const formConfig = defineOption([
385
+ {
386
+ field: 'gender',
387
+ t: 'radio-group',
388
+ label: '性别',
389
+ options: [
390
+ { label: '男', value: 'male' },
391
+ { label: '女', value: 'female' },
392
+ ],
393
+ },
394
+ ]);
395
+ ```
396
+
397
+ #### `checkbox-group` - 多选框组
398
+
399
+ ```javascript
400
+ const formConfig = defineOption([
401
+ {
402
+ field: 'hobbies',
403
+ t: 'checkbox-group',
404
+ label: '爱好',
405
+ options: [
406
+ { label: '阅读', value: 'reading' },
407
+ { label: '运动', value: 'sports' },
408
+ { label: '音乐', value: 'music' },
409
+ ],
410
+ },
411
+ ]);
412
+ ```
413
+
414
+ ### 日期时间
415
+
416
+ #### `date-picker` - 日期选择
417
+
418
+ ```javascript
419
+ const formConfig = defineOption([
420
+ {
421
+ field: 'birthday',
422
+ t: 'date-picker',
423
+ label: '生日',
424
+ type: 'date',
425
+ placeholder: '选择日期',
426
+ format: 'YYYY-MM-DD',
427
+ valueFormat: 'YYYY-MM-DD',
428
+ },
429
+ ]);
430
+ ```
431
+
432
+ #### `time-picker` - 时间选择
433
+
434
+ ```javascript
435
+ const formConfig = defineOption([
436
+ {
437
+ field: 'meetingTime',
438
+ t: 'time-picker',
439
+ label: '会议时间',
440
+ placeholder: '选择时间',
441
+ format: 'HH:mm:ss',
442
+ valueFormat: 'HH:mm:ss',
443
+ },
444
+ ]);
445
+ ```
446
+
447
+ #### `time-select` - 时间选择器
448
+
449
+ ```javascript
450
+ const formConfig = defineOption([
451
+ {
452
+ field: 'startTime',
453
+ t: 'time-select',
454
+ label: '开始时间',
455
+ placeholder: '选择时间',
456
+ start: '08:30',
457
+ end: '18:30',
458
+ step: '00:15',
459
+ },
460
+ ]);
461
+ ```
462
+
463
+ ### 其他组件
464
+
465
+ #### `switch` - 开关
466
+
467
+ ```javascript
468
+ const formConfig = defineOption([
469
+ {
470
+ field: 'enabled',
471
+ t: 'switch',
472
+ label: '启用',
473
+ activeText: '开',
474
+ inactiveText: '关',
475
+ activeValue: 1,
476
+ inactiveValue: 0,
477
+ },
478
+ ]);
479
+ ```
480
+
481
+ #### `slider` - 滑块
482
+
483
+ ```javascript
484
+ const formConfig = defineOption([
485
+ {
486
+ field: 'volume',
487
+ t: 'slider',
488
+ label: '音量',
489
+ min: 0,
490
+ max: 100,
491
+ step: 1,
492
+ showInput: true,
493
+ },
494
+ ]);
495
+ ```
496
+
497
+ #### `rate` - 评分
498
+
499
+ ```javascript
500
+ const formConfig = defineOption([
501
+ {
502
+ field: 'rating',
503
+ t: 'rate',
504
+ label: '评分',
505
+ max: 5,
506
+ allowHalf: true,
507
+ showScore: true,
508
+ },
509
+ ]);
510
+ ```
511
+
512
+ #### `color-picker` - 颜色选择
513
+
514
+ ```javascript
515
+ const formConfig = defineOption([
516
+ {
517
+ field: 'themeColor',
518
+ t: 'color-picker',
519
+ label: '主题色',
520
+ showAlpha: true,
521
+ predefine: ['#ff4500', '#ff8c00', '#ffd700', '#90ee90', '#00ced1', '#1e90ff', '#c71585'],
522
+ },
523
+ ]);
524
+ ```
525
+
526
+ #### `upload` - 文件上传
527
+
528
+ ```javascript
529
+ const formConfig = defineOption([
530
+ {
531
+ field: 'files',
532
+ t: 'upload',
533
+ label: '附件',
534
+ action: '/api/upload',
535
+ multiple: true,
536
+ limit: 5,
537
+ accept: '.jpg,.jpeg,.png,.gif',
538
+ listType: 'picture-card',
539
+ },
540
+ ]);
541
+ ```
542
+
543
+ #### `custom-render` - 自定义渲染
544
+
545
+ ```javascript
546
+ const formConfig = defineOption([
547
+ {
548
+ field: 'customField',
549
+ t: 'custom-render',
550
+ render: ({ plain }) => {
551
+ function onClick() {
552
+ if (!plain.checked.value) return plain.checked.value = 1;
553
+ ++plain.checked.value;
554
+ }
555
+ return () => {
556
+ return (
557
+ <div>
558
+ <span>自定义内容</span>
559
+ <span>{plain.checked.value || 0}</span>
560
+ <ElButton onClick={onClick}>自增</ElButton>
561
+ </div>
562
+ );
563
+ };
564
+ },
565
+ },
566
+ ]);
567
+ ```
568
+
569
+ ## 🔧 高级用法
570
+
571
+ ### 动态属性
572
+
573
+ ```typescript
574
+ const formConfig = defineOption(({ query }) => [
575
+ {
576
+ field: 'email',
577
+ t: 'input',
578
+ label: '邮箱',
579
+ placeholder: '请输入邮箱',
580
+ // 静态属性
581
+ clearable: true,
582
+ // 动态属性,根据表单其他字段的值动态设置
583
+ disabled: !query.username,
584
+ placeholder: query.username ? '请输入邮箱' : '请先输入用户名',
585
+ },
586
+ ]);
587
+ ```
588
+
589
+ ### 插槽使用
590
+
591
+ ```tsx
592
+ const formConfig = defineOption([
593
+ {
594
+ field: 'password',
595
+ t: 'input',
596
+ label: '密码',
597
+ type: 'password',
598
+ showPassword: true,
599
+ // 表单项插槽
600
+ itemSlots: {
601
+ label: () => (
602
+ <span class="custom-label">
603
+ 密码
604
+ <ElIcon><Star /></ElIcon>
605
+ </span>
606
+ ),
607
+ suffix: () => <ElButton text type="primary">生成密码</ElButton>,
608
+ },
609
+ },
610
+ ]);
611
+ ```
612
+
613
+ ### 异步数据源
614
+
615
+ ```typescript
616
+ const formConfig = defineOption([
617
+ {
618
+ field: 'city',
619
+ t: 'select',
620
+ label: '城市',
621
+ depend: true,
622
+ dependFields: 'province',
623
+ async getOptions(cb, query) {
624
+ try {
625
+ const cities = await fetchCities(query.province);
626
+ cb(cities);
627
+ }
628
+ catch (error) {
629
+ console.error('获取城市数据失败:', error);
630
+ cb([]);
631
+ }
632
+ },
633
+ },
634
+ ]);
635
+ ```
636
+
637
+ ### 表单分组
638
+
639
+ ```typescript
640
+ const formConfig = defineOption([
641
+ {
642
+ field: 'userInfo',
643
+ t: 'group',
644
+ label: '用户信息',
645
+ config: [
646
+ {
647
+ field: 'username',
648
+ t: 'input',
649
+ label: '用户名',
650
+ },
651
+ {
652
+ field: 'email',
653
+ t: 'input',
654
+ label: '邮箱',
655
+ },
656
+ ],
657
+ },
658
+ ]);
659
+ ```
660
+
661
+ ### 动态列表
662
+
663
+ ```tsx
664
+ const formConfig = defineOption([
665
+ {
666
+ field: 'users',
667
+ t: 'dynamic-group',
668
+ label: '用户列表',
669
+ config: ({ item, index }) => ([
670
+ {
671
+ field: 'name',
672
+ t: 'input',
673
+ label: '姓名',
674
+ placeholder: '请输入姓名',
675
+ },
676
+ {
677
+ field: 'age',
678
+ t: 'input-number',
679
+ label: '年龄',
680
+ min: 0,
681
+ max: 120,
682
+ },
683
+ ]),
684
+ itemSlots: {
685
+ append: ({ checked, index }) => (
686
+ <ElButton onClick={() => checked.splice(index, 1)} type="danger" size="small">
687
+ 删除
688
+ </ElButton>
689
+ ),
690
+ },
691
+ slots: {
692
+ append: ({ query }) => (
693
+ <ElButton onClick={() => query.users.push({ name: '', age: 0 })} type="primary">
694
+ 添加用户
695
+ </ElButton>
696
+ ),
697
+ },
698
+ },
699
+ ]);
700
+ ```
701
+
702
+ ### 表单联动
703
+
704
+ ```typescript
705
+ const formConfig = defineOption([
706
+ {
707
+ field: 'country',
708
+ t: 'select',
709
+ label: '国家',
710
+ options: countryList,
711
+ },
712
+ {
713
+ field: 'province',
714
+ t: 'select',
715
+ label: '省份',
716
+ depend: true,
717
+ dependFields: 'country',
718
+ getOptions: async (cb, query) => {
719
+ const provinces = await fetchProvinces(query.country);
720
+ cb(provinces);
721
+ },
722
+ },
723
+ ]);
724
+ ```
725
+
726
+ ### 自定义校验
727
+
728
+ ```typescript
729
+ const formConfig = defineOption([
730
+ {
731
+ t: 'input',
732
+ field: 'password',
733
+ label: '密码',
734
+ rules: [
735
+ { required: true, message: '密码不能为空' },
736
+ { min: 6, message: '密码不能少于6位' },
737
+ {
738
+ validator: async (rule, value, callback) => {
739
+ const response = await checkPasswordStrength(value);
740
+ if (!response.strong) {
741
+ callback(new Error('密码强度不够'));
742
+ }
743
+ else {
744
+ callback();
745
+ }
746
+ },
747
+ },
748
+ ],
749
+ },
750
+ ]);
751
+ ```
752
+
753
+ ## 🗂️ 目录结构
754
+
755
+ ```
756
+ packages/element-vant/
757
+ ├── index.ts # 入口文件
758
+ ├── components/ # 组件实现
759
+ │ ├── index.ts # 组件导出
760
+ │ ├── wrapper/ # 表单容器
761
+ │ ├── input/ # 输入框组件
762
+ │ ├── select/ # 下拉框组件
763
+ │ ├── cascader/ # 级联选择组件
764
+ │ └── ... # 其他组件
765
+ ├── docs/ # 文档
766
+ │ ├── index.md # 文档首页
767
+ │ ├── examples/ # 示例
768
+ │ └── options/ # 配置选项
769
+ ├── src/ # 源码
770
+ │ ├── index.ts # 源码入口
771
+ │ └── utils.ts # 工具函数
772
+ └── README.md # 文档
773
+ ```
774
+
775
+ ## 🔧 开发指南
776
+
777
+ ### 环境要求
778
+
779
+ - Vue 3.0+
780
+ - Vant 2.x
781
+ - TypeScript 4.0+
782
+
783
+ ### 添加新组件
784
+
785
+ 1. 在 `components/` 目录下创建组件目录
786
+ 2. 实现组件逻辑, 继承基础属性
787
+ 3. 在 `components/index.ts` 中导出
788
+ 4. 更新文档和示例
789
+
790
+ ## 🌟 在线示例
791
+
792
+ - [Vue 3 + Vant 示例](https://xiaohaih.github.io/json-form/example-vant-vue3/index.html)
793
+
794
+ ## 🤝 贡献
795
+
796
+ 欢迎提交 Issue 和 Pull Request!
797
+
798
+ ## 📄 许可证
799
+
800
+ MIT License
801
+
802
+ ## 🔗 相关链接
803
+
804
+ - [项目主页](https://github.com/xiaohaiH/json-form/tree/master/packages/vant)
805
+ - [核心模块](https://github.com/xiaohaiH/json-form/tree/master/packages/core/README.md)
806
+ - [Element Plus 版本](https://github.com/xiaohaiH/json-form/tree/master/packages/element-plus/README.md)
807
+ - [Element UI 版本](https://github.com/xiaohaiH/json-form/tree/master/packages/element-ui/README.md)