mwl-components 0.1.5 → 0.1.8
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/README.md +1191 -57
- package/dist/ContextMenu/index.d.ts +12 -20
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +3 -589
- package/dist/index.es.js +148 -145
- package/dist/index.umd.js +1 -1
- package/dist/types/index.d.ts +4 -0
- package/package.json +3 -2
- /package/dist/MenuTree/{components/index.vue.d.ts → index.vue.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,50 +1,75 @@
|
|
|
1
|
-
# mwl-components
|
|
1
|
+
# mwl-components 基于vue 3.0 + ts + vite + element-plus 组件库
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## 一、技术栈概述
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### 核心技术
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
| 技术 | 版本 | 说明 |
|
|
8
|
+
| ------------ | ------- | -------------------- |
|
|
9
|
+
| Vue | ^3.5.17 | 渐进式JavaScript框架 |
|
|
10
|
+
| TypeScript | ~5.8.0 | 类型系统 |
|
|
11
|
+
| Element Plus | ^2.10.4 | UI组件库 |
|
|
12
|
+
| Vite | ^7.0.0 | 构建工具 |
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
### 开发工具
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
| 技术 | 版本 | 说明 |
|
|
17
|
+
| -------- | ------- | ------------------ |
|
|
18
|
+
| ESLint | ^9.29.0 | 代码检查 |
|
|
19
|
+
| Prettier | 3.5.3 | 代码格式化 |
|
|
20
|
+
| vue-tsc | ^2.2.10 | TypeScript类型检查 |
|
|
21
|
+
| tsup | ^8.5.0 | TypeScript打包工具 |
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
---
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
pnpm link 或者 npm link
|
|
21
|
-
```
|
|
25
|
+
## 二、组件库安装与使用
|
|
22
26
|
|
|
23
|
-
###
|
|
27
|
+
### 安装
|
|
24
28
|
|
|
25
|
-
```
|
|
26
|
-
|
|
29
|
+
```bash
|
|
30
|
+
npm install mwl-components
|
|
31
|
+
# 或
|
|
32
|
+
pnpm add mwl-components
|
|
27
33
|
```
|
|
28
34
|
|
|
29
|
-
###
|
|
35
|
+
### 全局注册
|
|
30
36
|
|
|
31
|
-
```
|
|
37
|
+
```typescript
|
|
38
|
+
import { createApp } from 'vue'
|
|
39
|
+
import App from './App.vue'
|
|
40
|
+
import mwlComponents from 'mwl-components'
|
|
32
41
|
import ElementPlus from 'element-plus'
|
|
33
42
|
import 'element-plus/dist/index.css'
|
|
34
|
-
import mwlComponents from 'mwl-components'
|
|
35
|
-
import 'mwl-components/dist/index.css'
|
|
36
43
|
|
|
37
44
|
const app = createApp(App)
|
|
45
|
+
|
|
38
46
|
app.use(ElementPlus)
|
|
39
47
|
app.use(mwlComponents)
|
|
48
|
+
|
|
40
49
|
app.mount('#app')
|
|
41
50
|
```
|
|
42
51
|
|
|
43
|
-
###
|
|
52
|
+
### 按需引入
|
|
44
53
|
|
|
45
|
-
```
|
|
54
|
+
```typescript
|
|
55
|
+
import {
|
|
56
|
+
EasyButton,
|
|
57
|
+
ContentWarp,
|
|
58
|
+
Dialog,
|
|
59
|
+
EasyForm,
|
|
60
|
+
EasyTable,
|
|
61
|
+
MenuTree,
|
|
62
|
+
Pagination,
|
|
63
|
+
EasyContextMenu,
|
|
64
|
+
ContextMenu,
|
|
65
|
+
} from 'mwl-components'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### ⚠️**注意:** 如果你不想全局注册 element-plus,你需要单独注册组件库使用的 element-plus 组件
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
46
71
|
import 'element-plus/dist/index.css'
|
|
47
|
-
import 'element-plus/theme-chalk/dark/css-vars.css'
|
|
72
|
+
import 'element-plus/theme-chalk/dark/css-vars.css' // 暗黑模式
|
|
48
73
|
|
|
49
74
|
import mwlComponents from 'mwl-components'
|
|
50
75
|
import 'mwl-components/dist/mwl-components.css'
|
|
@@ -52,6 +77,7 @@ import {
|
|
|
52
77
|
ElForm,
|
|
53
78
|
ElFormItem,
|
|
54
79
|
ElInput,
|
|
80
|
+
ElInputNumber,
|
|
55
81
|
ElSelect,
|
|
56
82
|
ElSelectV2,
|
|
57
83
|
ElTreeSelect,
|
|
@@ -60,10 +86,11 @@ import {
|
|
|
60
86
|
ElSwitch,
|
|
61
87
|
ElCascader,
|
|
62
88
|
ElCheckbox,
|
|
89
|
+
ElCheckboxGroup,
|
|
63
90
|
ElRadio,
|
|
64
91
|
ElRadioGroup,
|
|
65
|
-
|
|
66
|
-
|
|
92
|
+
ElSlider,
|
|
93
|
+
ElUpload,
|
|
67
94
|
ElTable,
|
|
68
95
|
ElTableColumn,
|
|
69
96
|
ElButton,
|
|
@@ -75,15 +102,14 @@ import {
|
|
|
75
102
|
ElScrollbar,
|
|
76
103
|
ElCard,
|
|
77
104
|
ElTooltip,
|
|
78
|
-
ElIcon
|
|
105
|
+
ElIcon,
|
|
79
106
|
} from 'element-plus'
|
|
80
|
-
```
|
|
81
107
|
|
|
82
|
-
```sh
|
|
83
108
|
const components = [
|
|
84
109
|
ElForm,
|
|
85
110
|
ElFormItem,
|
|
86
111
|
ElInput,
|
|
112
|
+
ElInputNumber,
|
|
87
113
|
ElSelect,
|
|
88
114
|
ElSelectV2,
|
|
89
115
|
ElTreeSelect,
|
|
@@ -92,10 +118,11 @@ const components = [
|
|
|
92
118
|
ElSwitch,
|
|
93
119
|
ElCascader,
|
|
94
120
|
ElCheckbox,
|
|
121
|
+
ElCheckboxGroup,
|
|
95
122
|
ElRadio,
|
|
96
123
|
ElRadioGroup,
|
|
97
|
-
|
|
98
|
-
|
|
124
|
+
ElSlider,
|
|
125
|
+
ElUpload,
|
|
99
126
|
ElTable,
|
|
100
127
|
ElTableColumn,
|
|
101
128
|
ElButton,
|
|
@@ -107,13 +134,10 @@ const components = [
|
|
|
107
134
|
ElScrollbar,
|
|
108
135
|
ElCard,
|
|
109
136
|
ElTooltip,
|
|
110
|
-
ElIcon
|
|
137
|
+
ElIcon,
|
|
111
138
|
]
|
|
112
|
-
```
|
|
113
139
|
|
|
114
|
-
|
|
115
|
-
export const installs = (app: any) => {
|
|
116
|
-
// app.use(ElementPlus)
|
|
140
|
+
export const install = (app: any) => {
|
|
117
141
|
components.forEach((component) => {
|
|
118
142
|
app.component(component.name, component)
|
|
119
143
|
})
|
|
@@ -121,47 +145,1157 @@ export const installs = (app: any) => {
|
|
|
121
145
|
}
|
|
122
146
|
```
|
|
123
147
|
|
|
124
|
-
|
|
148
|
+
---
|
|
125
149
|
|
|
126
|
-
|
|
150
|
+
## 三、组件详解
|
|
127
151
|
|
|
128
|
-
|
|
152
|
+
---
|
|
129
153
|
|
|
130
|
-
|
|
131
|
-
|
|
154
|
+
### 1. EasyButton 按钮组件
|
|
155
|
+
|
|
156
|
+
基于 Element Plus 的 `el-button` 封装的带加载状态的按钮组件。
|
|
157
|
+
|
|
158
|
+
**源码位置**: [src/components/EasyButton/index.vue](file:///Users/max/Desktop/学习项目/mwl-components/src/components/EasyButton/index.vue)
|
|
159
|
+
|
|
160
|
+
#### 1.1 基础用法
|
|
161
|
+
|
|
162
|
+
```vue
|
|
163
|
+
<template>
|
|
164
|
+
<EasyButton type="primary" @click="handleClick"> 点击按钮 </EasyButton>
|
|
165
|
+
</template>
|
|
166
|
+
|
|
167
|
+
<script setup>
|
|
168
|
+
import { EasyButton } from 'mwl-components'
|
|
169
|
+
|
|
170
|
+
const handleClick = async () => {
|
|
171
|
+
console.log('按钮点击')
|
|
172
|
+
}
|
|
173
|
+
</script>
|
|
132
174
|
```
|
|
133
175
|
|
|
134
|
-
|
|
176
|
+
#### 1.2 Props
|
|
135
177
|
|
|
136
|
-
|
|
137
|
-
|
|
178
|
+
支持 Element Plus `el-button` 的所有属性,以下是常用属性:
|
|
179
|
+
|
|
180
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
181
|
+
| ----------- | ------- | ------ | ----------------------------------------------------------- |
|
|
182
|
+
| type | String | - | 按钮类型 primary / success / warning / danger / info / text |
|
|
183
|
+
| size | String | - | 按钮尺寸 large / default / small |
|
|
184
|
+
| plain | Boolean | false | 是否朴素按钮 |
|
|
185
|
+
| round | Boolean | false | 是否圆角按钮 |
|
|
186
|
+
| circle | Boolean | false | 是否圆形按钮 |
|
|
187
|
+
| loading | Boolean | false | 是否加载中 |
|
|
188
|
+
| disabled | Boolean | false | 是否禁用 |
|
|
189
|
+
| autofocus | Boolean | false | 是否自动聚焦 |
|
|
190
|
+
| native-type | String | button | 原生 type 属性 |
|
|
191
|
+
|
|
192
|
+
#### 1.3 Slots
|
|
193
|
+
|
|
194
|
+
| 插槽名 | 说明 |
|
|
195
|
+
| ------- | -------- |
|
|
196
|
+
| default | 按钮内容 |
|
|
197
|
+
|
|
198
|
+
#### 1.4 Events
|
|
199
|
+
|
|
200
|
+
| 事件名 | 参数 | 说明 |
|
|
201
|
+
| ------ | --------------- | -------------- |
|
|
202
|
+
| click | (e: MouseEvent) | 点击按钮时触发 |
|
|
203
|
+
|
|
204
|
+
#### 1.5 特性
|
|
205
|
+
|
|
206
|
+
- 自动处理 loading 状态:点击按钮后自动显示 loading,等待异步操作完成后关闭
|
|
207
|
+
- 支持所有 el-button 属性(通过 v-bind="$attrs" 透传)
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### 2. ContentWarp 内容容器组件
|
|
212
|
+
|
|
213
|
+
一个基于 ElCard 的内容包装容器,提供统一的卡片样式和布局结构。
|
|
214
|
+
|
|
215
|
+
**源码位置**: [src/components/ContentWarp/index.vue](file:///Users/max/Desktop/学习项目/mwl-components/src/components/ContentWarp/index.vue)
|
|
216
|
+
|
|
217
|
+
#### 2.1 基础用法
|
|
218
|
+
|
|
219
|
+
```vue
|
|
220
|
+
<template>
|
|
221
|
+
<ContentWarp title="标题" message="副标题">
|
|
222
|
+
<div>内容区域</div>
|
|
223
|
+
<template #footer>
|
|
224
|
+
<div>底部区域</div>
|
|
225
|
+
</template>
|
|
226
|
+
</ContentWarp>
|
|
227
|
+
</template>
|
|
228
|
+
|
|
229
|
+
<script setup>
|
|
230
|
+
import { ContentWarp } from 'mwl-components'
|
|
231
|
+
</script>
|
|
138
232
|
```
|
|
139
233
|
|
|
140
|
-
|
|
234
|
+
#### 2.2 Props
|
|
141
235
|
|
|
142
|
-
|
|
143
|
-
|
|
236
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
237
|
+
| ------- | ------ | ------ | ---------------- |
|
|
238
|
+
| title | String | - | 卡片标题 |
|
|
239
|
+
| message | String | - | 标题旁的提示信息 |
|
|
240
|
+
|
|
241
|
+
#### 2.3 Slots
|
|
242
|
+
|
|
243
|
+
| 插槽名 | 说明 |
|
|
244
|
+
| ------- | -------------------------- |
|
|
245
|
+
| default | 默认内容区域 |
|
|
246
|
+
| header | 自定义头部(覆盖默认标题) |
|
|
247
|
+
| footer | 底部区域 |
|
|
248
|
+
|
|
249
|
+
#### 2.4 特性
|
|
250
|
+
|
|
251
|
+
- 自动根据父元素 class 是否包含 `content-wrap` 来计算表格最大高度
|
|
252
|
+
- 包裹 el-form 时自动调整内边距
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
### 3. Dialog 对话框组件
|
|
257
|
+
|
|
258
|
+
基于 Element Plus 的 `el-dialog` 封装的增强型对话框组件。
|
|
259
|
+
|
|
260
|
+
**源码位置**: [src/components/Dialog/index.vue](file:///Users/max/Desktop/学习项目/mwl-components/src/components/Dialog/index.vue)
|
|
261
|
+
|
|
262
|
+
#### 3.1 基础用法
|
|
263
|
+
|
|
264
|
+
```vue
|
|
265
|
+
<template>
|
|
266
|
+
<Dialog v-model="dialogVisible" title="对话框标题" width="50%" :fullscreen="false" :scroll="true">
|
|
267
|
+
<div>对话框内容</div>
|
|
268
|
+
<template #footer>
|
|
269
|
+
<el-button @click="dialogVisible = false">取消</el-button>
|
|
270
|
+
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
|
271
|
+
</template>
|
|
272
|
+
</Dialog>
|
|
273
|
+
</template>
|
|
274
|
+
|
|
275
|
+
<script setup>
|
|
276
|
+
import { ref } from 'vue'
|
|
277
|
+
import { Dialog } from 'mwl-components'
|
|
278
|
+
|
|
279
|
+
const dialogVisible = ref(false)
|
|
280
|
+
const handleConfirm = () => {
|
|
281
|
+
dialogVisible.value = false
|
|
282
|
+
}
|
|
283
|
+
</script>
|
|
144
284
|
```
|
|
145
285
|
|
|
146
|
-
|
|
286
|
+
#### 3.2 Props
|
|
147
287
|
|
|
148
|
-
|
|
149
|
-
|
|
288
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
289
|
+
| -------------------- | --------------- | ------- | ---------------- |
|
|
290
|
+
| modelValue / v-model | Boolean | false | 是否显示对话框 |
|
|
291
|
+
| title | String | '' | 对话框标题 |
|
|
292
|
+
| fullscreen | Boolean | false | 是否全屏显示 |
|
|
293
|
+
| scroll | Boolean | false | 是否开启内容滚动 |
|
|
294
|
+
| width | String | '61.8%' | 对话框宽度 |
|
|
295
|
+
| maxHeight | String / Number | '' | 最大高度 |
|
|
296
|
+
|
|
297
|
+
支持 Element Plus `el-dialog` 的所有属性,通过 `v-bind="$attrs"` 透传:
|
|
298
|
+
|
|
299
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
300
|
+
| --------------------- | ------- | ------ | ------------------ |
|
|
301
|
+
| close-on-click-modal | Boolean | false | 点击遮罩是否关闭 |
|
|
302
|
+
| close-on-press-escape | Boolean | true | 按 ESC 是否关闭 |
|
|
303
|
+
| show-close | Boolean | true | 是否显示关闭按钮 |
|
|
304
|
+
| destroy-on-close | Boolean | true | 关闭时是否销毁内容 |
|
|
305
|
+
| draggable | Boolean | true | 是否可拖拽 |
|
|
306
|
+
| center | Boolean | false | 是否居中对齐 |
|
|
307
|
+
| align-center | Boolean | false | 是否垂直居中 |
|
|
308
|
+
| modal-class | String | - | 遮罩类名 |
|
|
309
|
+
|
|
310
|
+
#### 3.3 Slots
|
|
311
|
+
|
|
312
|
+
| 插槽名 | 说明 |
|
|
313
|
+
| ------- | -------------- |
|
|
314
|
+
| default | 对话框内容 |
|
|
315
|
+
| title | 自定义标题区域 |
|
|
316
|
+
| footer | 底部操作区 |
|
|
317
|
+
|
|
318
|
+
#### 3.4 特性
|
|
319
|
+
|
|
320
|
+
- 支持全屏切换(点击标题栏右侧图标)
|
|
321
|
+
- 可配置内容滚动(scroll 为 true 时启用 ElScrollbar)
|
|
322
|
+
- 自动计算全屏模式下的最大高度
|
|
323
|
+
- 销毁时自动关闭(destroy-on-close)
|
|
324
|
+
- 默认点击遮罩不关闭、不可拖拽、按 ESC 可关闭
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
### 4. EasyForm 表单组件
|
|
329
|
+
|
|
330
|
+
强大的动态表单生成组件,基于 Element Plus 的表单项封装。
|
|
331
|
+
|
|
332
|
+
**源码位置**: [src/components/EasyForm/index.vue](file:///Users/max/Desktop/学习项目/mwl-components/src/components/EasyForm/index.vue)
|
|
333
|
+
|
|
334
|
+
#### 4.1 基础用法
|
|
335
|
+
|
|
336
|
+
```vue
|
|
337
|
+
<template>
|
|
338
|
+
<EasyForm v-model="formData" :form-items="formItems" :inline="true" label-width="120px">
|
|
339
|
+
<template #append>
|
|
340
|
+
<el-button type="primary" @click="handleQuery">查询</el-button>
|
|
341
|
+
<el-button @click="handleReset">重置</el-button>
|
|
342
|
+
</template>
|
|
343
|
+
</EasyForm>
|
|
344
|
+
</template>
|
|
345
|
+
|
|
346
|
+
<script setup>
|
|
347
|
+
import { ref } from 'vue'
|
|
348
|
+
import { EasyForm, type FormItem } from 'mwl-components'
|
|
349
|
+
|
|
350
|
+
const formData = ref({})
|
|
351
|
+
|
|
352
|
+
const formItems = ref<FormItem[]>([
|
|
353
|
+
{
|
|
354
|
+
label: '用户名',
|
|
355
|
+
type: 'text',
|
|
356
|
+
prop: 'username',
|
|
357
|
+
placeholder: '请输入用户名'
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
label: '状态',
|
|
361
|
+
type: 'select',
|
|
362
|
+
prop: 'status',
|
|
363
|
+
options: [
|
|
364
|
+
{ label: '启用', value: 1 },
|
|
365
|
+
{ label: '禁用', value: 0 }
|
|
366
|
+
]
|
|
367
|
+
}
|
|
368
|
+
])
|
|
369
|
+
</script>
|
|
150
370
|
```
|
|
151
371
|
|
|
152
|
-
|
|
372
|
+
#### 4.2 Props
|
|
153
373
|
|
|
154
|
-
|
|
155
|
-
|
|
374
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
375
|
+
| -------------------- | --------------- | ------- | -------------- |
|
|
376
|
+
| v-model / modelValue | Object | {} | 表单数据对象 |
|
|
377
|
+
| formItems | FormItem[] | [] | 表单项配置数组 |
|
|
378
|
+
| inline | Boolean | true | 是否行内表单 |
|
|
379
|
+
| labelWidth | String / Number | '120px' | 表单标签宽度 |
|
|
380
|
+
| itemWidth | String | '200px' | 表单项宽度 |
|
|
381
|
+
|
|
382
|
+
支持 Element Plus `el-form` 的所有属性,通过 `v-bind="$attrs"` 透传。
|
|
383
|
+
|
|
384
|
+
#### 4.3 FormItem 完整配置
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
interface FormItem {
|
|
388
|
+
// 基础属性
|
|
389
|
+
type: string // 表单类型(见下表)
|
|
390
|
+
prop: string // 字段名(必填)
|
|
391
|
+
label: string | (() => any) // 标签文本
|
|
392
|
+
hidden?: boolean // 是否隐藏
|
|
393
|
+
|
|
394
|
+
// 校验规则
|
|
395
|
+
rule?: Rule[] // 校验规则数组
|
|
396
|
+
required?: boolean // 是否必填(自动生成校验规则)
|
|
397
|
+
|
|
398
|
+
// 禁用与只读
|
|
399
|
+
disabled?: boolean // 是否禁用
|
|
400
|
+
readonly?: boolean // 是否只读
|
|
401
|
+
|
|
402
|
+
// 占位符与提示
|
|
403
|
+
placeholder?: string // 占位符(自动生成)
|
|
404
|
+
tooltip?: string // 标签旁边的提示文字
|
|
405
|
+
|
|
406
|
+
// 样式相关
|
|
407
|
+
width?: string // 控件宽度
|
|
408
|
+
labelWidth?: string // 单独设置标签宽度
|
|
409
|
+
|
|
410
|
+
// 清空与搜索
|
|
411
|
+
clearable?: boolean // 是否可清空
|
|
412
|
+
filterable?: boolean // 是否可搜索(select/cascader)
|
|
413
|
+
|
|
414
|
+
// 选项配置(select/checkbox/radio/tree-select)
|
|
415
|
+
options?: Options // 选项数组 [{ label, value }]
|
|
416
|
+
data?: Array<any> // 数据数组(备用)
|
|
417
|
+
props?: { label: string; value: string } // 选项字段映射
|
|
418
|
+
multiple?: boolean // 是否多选
|
|
419
|
+
|
|
420
|
+
// 日期相关
|
|
421
|
+
valueFormat?: string // 时间值格式化(如 'YYYY-MM-DD HH:mm:ss')
|
|
422
|
+
format?: string // 时间显示格式化
|
|
423
|
+
disabledDate?: (time: Date) => boolean // 禁用日期函数
|
|
424
|
+
shortcuts?: Array<{ text: string; value: Date | (() => Date) }> // 快捷选项
|
|
425
|
+
|
|
426
|
+
// 级联选择
|
|
427
|
+
showAllLevels?: boolean // 是否显示完整路径
|
|
428
|
+
checkStrictly?: boolean // 是否严格遵循父子不关联
|
|
429
|
+
|
|
430
|
+
// 输入框相关
|
|
431
|
+
maxlength?: number // 最大输入长度
|
|
432
|
+
min?: number // 最小值(number 类型)
|
|
433
|
+
max?: number // 最大值(number 类型)
|
|
434
|
+
precision?: number // 数值精度
|
|
435
|
+
step?: number // 步进值
|
|
436
|
+
stepStrictly?: boolean // 是否只能输入步进倍数
|
|
437
|
+
|
|
438
|
+
// 下拉菜单
|
|
439
|
+
placement?: Placement // 下拉菜单展开方向
|
|
440
|
+
popperClass?: String // 下拉菜单类名
|
|
441
|
+
teleported?: boolean // 是否将下弹框放置于 body
|
|
442
|
+
allowCreate?: boolean // 是否允许创建新选项(select)
|
|
443
|
+
collapseTags?: boolean // 多选时是否折叠标签
|
|
444
|
+
collapseTagsTooltip?: boolean // 是否hover显示所有标签
|
|
445
|
+
|
|
446
|
+
// 树形选择
|
|
447
|
+
checkOnClickNode?: boolean // 点击节点时是否选中
|
|
448
|
+
|
|
449
|
+
// 上传
|
|
450
|
+
fileLimit?: number // 上传文件数量限制
|
|
451
|
+
|
|
452
|
+
// 插槽
|
|
453
|
+
slots?: Slots // 组件内部插槽配置
|
|
454
|
+
[key: string]: any // 其他属性透传到底层组件
|
|
455
|
+
}
|
|
156
456
|
```
|
|
157
457
|
|
|
158
|
-
|
|
458
|
+
#### 4.4 支持的表单项类型 (type)
|
|
159
459
|
|
|
160
|
-
|
|
161
|
-
|
|
460
|
+
| type 值 | 对应组件 | 默认属性 | 说明 |
|
|
461
|
+
| ------------- | ----------------- | -------------------------------- | ---------------- |
|
|
462
|
+
| text | el-input | clearable: true | 单行文本输入 |
|
|
463
|
+
| textarea | el-input | type: textarea | 多行文本输入 |
|
|
464
|
+
| number | el-input-number | controlsPosition: right | 数字输入 |
|
|
465
|
+
| switch | el-switch | - | 开关 |
|
|
466
|
+
| slider | el-slider | - | 滑块 |
|
|
467
|
+
| checkbox | el-checkbox-group | - | 多选框组 |
|
|
468
|
+
| radio | el-radio-group | - | 单选框组 |
|
|
469
|
+
| select | el-select | - | 下拉选择 |
|
|
470
|
+
| select-v2 | el-select-v2 | - | 虚拟化下拉选择 |
|
|
471
|
+
| tree-select | el-tree-select | checkStrictly: true | 树形选择 |
|
|
472
|
+
| date | el-date-picker | valueFormat: YYYY-MM-DD | 日期选择 |
|
|
473
|
+
| dates | el-date-picker | valueFormat: YYYY-MM-DD | 多日期选择 |
|
|
474
|
+
| datetime | el-date-picker | valueFormat: YYYY-MM-DD HH:mm:ss | 日期时间选择 |
|
|
475
|
+
| week | el-date-picker | valueFormat: YYYY 第WW周 | 周选择 |
|
|
476
|
+
| month | el-date-picker | valueFormat: YYYY-MM | 月份选择 |
|
|
477
|
+
| year | el-date-picker | valueFormat: YYYY | 年份选择 |
|
|
478
|
+
| daterange | el-date-picker | rangeSeparator: 至 | 日期范围选择 |
|
|
479
|
+
| datetimerange | el-date-picker | rangeSeparator: 至 | 日期时间范围选择 |
|
|
480
|
+
| monthrange | el-date-picker | rangeSeparator: 至 | 月份范围选择 |
|
|
481
|
+
| yearrange | el-date-picker | rangeSeparator: 至 | 年份范围选择 |
|
|
482
|
+
| cascader | el-cascader | clearable: true | 级联选择 |
|
|
483
|
+
| upload | el-upload | - | 文件上传 |
|
|
484
|
+
| custom | el-form-item | - | 自定义组件 |
|
|
485
|
+
|
|
486
|
+
#### 4.5 预设属性 (componentsMap)
|
|
487
|
+
|
|
488
|
+
组件库为每种类型预设了常用属性,这些属性可被 formItems 中的配置覆盖:
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
// 通用预设
|
|
492
|
+
const commonAttrs = {
|
|
493
|
+
clearable: true,
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// text / textarea
|
|
497
|
+
{
|
|
498
|
+
type: 'text' | 'textarea',
|
|
499
|
+
component: 'el-input',
|
|
500
|
+
attrs: { clearable: true }
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// number
|
|
504
|
+
{
|
|
505
|
+
type: 'number',
|
|
506
|
+
component: 'el-input-number',
|
|
507
|
+
attrs: { controlsPosition: 'right' }
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// switch
|
|
511
|
+
{
|
|
512
|
+
type: 'switch',
|
|
513
|
+
component: 'el-switch'
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// checkbox
|
|
517
|
+
{
|
|
518
|
+
type: 'checkbox',
|
|
519
|
+
component: 'el-checkbox-group',
|
|
520
|
+
slots: (item) => ({
|
|
521
|
+
default: () => item.options?.map(option => h(elCheckbox, { value: option.value }, () => option.label))
|
|
522
|
+
})
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// radio
|
|
526
|
+
{
|
|
527
|
+
type: 'radio',
|
|
528
|
+
component: 'el-radio-group',
|
|
529
|
+
slots: (item) => ({
|
|
530
|
+
default: () => item.options?.map(option => h(elRadio, { value: option.value }, () => option.label))
|
|
531
|
+
})
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// select
|
|
535
|
+
{
|
|
536
|
+
type: 'select',
|
|
537
|
+
component: 'el-select',
|
|
538
|
+
slots: presetSelectSlot // 自动渲染 el-option
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// tree-select
|
|
542
|
+
{
|
|
543
|
+
type: 'tree-select',
|
|
544
|
+
component: 'el-tree-select',
|
|
545
|
+
attrs: { checkStrictly: true, renderAfterExpand: true }
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// 日期类型
|
|
549
|
+
{
|
|
550
|
+
type: 'date,dates',
|
|
551
|
+
component: 'el-date-picker',
|
|
552
|
+
attrs: { showConfirm: false, valueFormat: 'YYYY-MM-DD', format: 'YYYY-MM-DD' }
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
{
|
|
556
|
+
type: 'datetime,week',
|
|
557
|
+
component: 'el-date-picker',
|
|
558
|
+
attrs: { showConfirm: false, valueFormat: 'YYYY-MM-DD HH:mm:ss', format: 'YYYY-MM-DD HH:mm:ss' }
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
{
|
|
562
|
+
type: 'month,months',
|
|
563
|
+
component: 'el-date-picker',
|
|
564
|
+
attrs: { showConfirm: false, valueFormat: 'YYYY-MM', format: 'YYYY-MM' }
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
{
|
|
568
|
+
type: 'year,years',
|
|
569
|
+
component: 'el-date-picker',
|
|
570
|
+
attrs: { showConfirm: false, valueFormat: 'YYYY', format: 'YYYY' }
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
{
|
|
574
|
+
type: 'datetimerange,daterange,monthrange,yearrange',
|
|
575
|
+
component: 'el-date-picker',
|
|
576
|
+
attrs: { rangeSeparator: '至', startPlaceholder: '开始日期', endPlaceholder: '结束日期' }
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// cascader
|
|
580
|
+
{
|
|
581
|
+
type: 'cascader',
|
|
582
|
+
component: 'el-cascader',
|
|
583
|
+
attrs: { clearable: true }
|
|
584
|
+
}
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
#### 4.6 工具函数
|
|
588
|
+
|
|
589
|
+
**getPlaceholder**: 自动生成占位符
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
import { getPlaceholder } from 'mwl-components'
|
|
593
|
+
|
|
594
|
+
const placeholder = getPlaceholder(formItem)
|
|
595
|
+
// text/number 类型: "请输入{label}"
|
|
596
|
+
// select/cascader/date 类型: "请选择{label}"
|
|
162
597
|
```
|
|
163
598
|
|
|
164
|
-
|
|
599
|
+
#### 4.7 Slots(模板插槽)
|
|
600
|
+
|
|
601
|
+
EasyForm 支持以下模板插槽:
|
|
602
|
+
|
|
603
|
+
| 插槽名 | 作用域参数 | 说明 |
|
|
604
|
+
| ------ | ---------- | ------------------------------------------- |
|
|
605
|
+
| {prop} | { item } | 单个表单项的自定义插槽(prop 为表单字段名) |
|
|
606
|
+
| append | - | 表单底部的操作按钮区域 |
|
|
607
|
+
|
|
608
|
+
```vue
|
|
609
|
+
<template>
|
|
610
|
+
<EasyForm v-model="formData" :form-items="formItems">
|
|
611
|
+
<!-- 自定义某个表单项 -->
|
|
612
|
+
<template #username="{ item }">
|
|
613
|
+
<el-input v-model="formData.username" :placeholder="item.placeholder">
|
|
614
|
+
<template #prefix>
|
|
615
|
+
<el-icon><User /></el-icon>
|
|
616
|
+
</template>
|
|
617
|
+
</el-input>
|
|
618
|
+
</template>
|
|
619
|
+
|
|
620
|
+
<!-- 底部操作按钮 -->
|
|
621
|
+
<template #append>
|
|
622
|
+
<el-button type="primary">提交</el-button>
|
|
623
|
+
</template>
|
|
624
|
+
</EasyForm>
|
|
625
|
+
</template>
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
#### 4.8 自定义类型 (custom)
|
|
629
|
+
|
|
630
|
+
使用 `type: 'custom'` 可以完全自定义表单项:
|
|
631
|
+
|
|
632
|
+
```typescript
|
|
633
|
+
const formItems = [
|
|
634
|
+
{
|
|
635
|
+
type: 'custom',
|
|
636
|
+
prop: 'customField',
|
|
637
|
+
label: '自定义',
|
|
638
|
+
width: '300px',
|
|
639
|
+
// 方式一:通过 slots 配置
|
|
640
|
+
slots: {
|
|
641
|
+
default: () => h('div', '自定义内容'),
|
|
642
|
+
},
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
type: 'custom',
|
|
646
|
+
prop: 'customField2',
|
|
647
|
+
label: '自定义2',
|
|
648
|
+
// 方式二:通过模板插槽
|
|
649
|
+
},
|
|
650
|
+
]
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
```vue
|
|
654
|
+
<template>
|
|
655
|
+
<EasyForm v-model="formData" :form-items="formItems">
|
|
656
|
+
<template #customField2="{ item }">
|
|
657
|
+
<el-date-picker v-model="formData.customField2" type="datetime" placeholder="选择日期时间" />
|
|
658
|
+
</template>
|
|
659
|
+
</EasyForm>
|
|
660
|
+
</template>
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
---
|
|
664
|
+
|
|
665
|
+
### 5. EasyTable 表格组件
|
|
666
|
+
|
|
667
|
+
基于 Element Plus 的 `el-table` 封装的增强型表格组件。
|
|
668
|
+
|
|
669
|
+
**源码位置**: [src/components/EasyTable/index.vue](file:///Users/max/Desktop/学习项目/mwl-components/src/components/EasyTable/index.vue)
|
|
670
|
+
|
|
671
|
+
#### 5.1 基础用法
|
|
672
|
+
|
|
673
|
+
```vue
|
|
674
|
+
<template>
|
|
675
|
+
<EasyTable :data="tableData" :table-columns="tableColumns" :buttons="buttons" button-width="120">
|
|
676
|
+
<!-- 自定义列内容 -->
|
|
677
|
+
<template #methodName="{ row }"> {{ row.methodName }}({{ row.methodParams }}) </template>
|
|
678
|
+
</EasyTable>
|
|
679
|
+
</template>
|
|
680
|
+
|
|
681
|
+
<script setup>
|
|
682
|
+
import { ref } from 'vue'
|
|
683
|
+
import { EasyTable, type TableColumn, type buttonType } from 'mwl-components'
|
|
684
|
+
|
|
685
|
+
const tableData = ref([
|
|
686
|
+
{
|
|
687
|
+
id: 1,
|
|
688
|
+
methodName: '新增',
|
|
689
|
+
methodParams: '参数1',
|
|
690
|
+
operateTime: '2023-01-01'
|
|
691
|
+
}
|
|
692
|
+
])
|
|
693
|
+
|
|
694
|
+
const tableColumns = ref<TableColumn[]>([
|
|
695
|
+
{
|
|
696
|
+
type: 'index',
|
|
697
|
+
label: '序号',
|
|
698
|
+
width: '80'
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
label: '操作内容',
|
|
702
|
+
prop: 'methodName'
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
label: '操作时间',
|
|
706
|
+
prop: 'operateTime'
|
|
707
|
+
}
|
|
708
|
+
])
|
|
709
|
+
|
|
710
|
+
const buttons = ref<buttonType[]>([
|
|
711
|
+
{
|
|
712
|
+
label: '编辑',
|
|
713
|
+
type: 'edit',
|
|
714
|
+
click: (row) => handleEdit(row)
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
label: '删除',
|
|
718
|
+
type: 'del',
|
|
719
|
+
click: (row) => handleDelete(row)
|
|
720
|
+
}
|
|
721
|
+
])
|
|
722
|
+
</script>
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
#### 5.2 Props
|
|
726
|
+
|
|
727
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
728
|
+
| ------------ | --------------- | -------- | ------------------------------------ |
|
|
729
|
+
| data | Array | required | 表格数据 |
|
|
730
|
+
| tableColumns | TableColumn[] | [] | 列配置数组 |
|
|
731
|
+
| buttons | buttonType[] | [] | 操作按钮配置数组 |
|
|
732
|
+
| buttonWidth | Number / String | 120 | 操作列宽度 |
|
|
733
|
+
| align | String | 'center' | 文字对齐方式 left / center / right |
|
|
734
|
+
| height | Number / String | - | 表格高度 |
|
|
735
|
+
| maxHeight | Number / String | - | 表格最大高度 |
|
|
736
|
+
| footerHeight | Number | 65 | 底部分页高度(用于自动计算表格高度) |
|
|
737
|
+
|
|
738
|
+
支持 Element Plus `el-table` 的所有属性,通过 `v-bind="$attrs"` 透传:
|
|
739
|
+
|
|
740
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
741
|
+
| --------------------- | ----------------- | ---------- | -------------------------------- |
|
|
742
|
+
| stripe | Boolean | false | 是否斑马纹 |
|
|
743
|
+
| border | Boolean | false | 是否带边框 |
|
|
744
|
+
| size | String | - | 表格尺寸 large / default / small |
|
|
745
|
+
| fit | Boolean | true | 列宽度是否自适应 |
|
|
746
|
+
| show-header | Boolean | true | 是否显示表头 |
|
|
747
|
+
| highlight-current-row | Boolean | false | 是否高亮当前行 |
|
|
748
|
+
| row-key | String / Function | - | 行数据的 Key |
|
|
749
|
+
| empty-text | String | '暂无数据' | 空数据时显示的文本 |
|
|
750
|
+
| default-expand-all | Boolean | false | 默认展开所有行 |
|
|
751
|
+
| expand-row-keys | Array | - | 展开行的 keys |
|
|
752
|
+
|
|
753
|
+
#### 5.3 TableColumn 配置
|
|
754
|
+
|
|
755
|
+
```typescript
|
|
756
|
+
interface TableColumn {
|
|
757
|
+
// 基础属性
|
|
758
|
+
label: string // 列标题(必填)
|
|
759
|
+
prop?: string // 字段名
|
|
760
|
+
width?: String / Number // 列宽度
|
|
761
|
+
minWidth?: String / Number // 最小列宽
|
|
762
|
+
fixed?: String / Boolean // 固定列 left / right / true
|
|
763
|
+
|
|
764
|
+
// 列类型
|
|
765
|
+
type?: 'index' | 'selection' | 'expand' // 序号列 / 多选列 / 展开列
|
|
766
|
+
|
|
767
|
+
// 样式
|
|
768
|
+
align?: String // 对齐方式 left / center / right
|
|
769
|
+
header-align?: String // 表头对齐方式
|
|
770
|
+
sortable?: Boolean / 'custom' // 是否可排序
|
|
771
|
+
sort-method?: Function // 排序方法
|
|
772
|
+
sort-by?: String // 按哪个字段排序
|
|
773
|
+
sort-orders?: Array // 排序顺序数组
|
|
774
|
+
|
|
775
|
+
// 显示与隐藏
|
|
776
|
+
show-overflow-tooltip?: Boolean // 是否显示省略号tooltip
|
|
777
|
+
resizable?: Boolean // 是否可拖拽调整宽度
|
|
778
|
+
|
|
779
|
+
// 渲染
|
|
780
|
+
formatter?: Function // 格式化函数 (row, column, cellValue, index)
|
|
781
|
+
selectable?: Function // 选择框是否禁用 (row, index)
|
|
782
|
+
|
|
783
|
+
// 插槽(配置插槽,非模板插槽)
|
|
784
|
+
slots?: {
|
|
785
|
+
default?: (scope: { row: any; $index: number }) => VNode // 自定义列内容
|
|
786
|
+
header?: (scope: { column: any; $index: number }) => VNode // 自定义表头
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// 嵌套表头
|
|
790
|
+
children?: TableColumn[] // 子列配置(用于多级表头)
|
|
791
|
+
|
|
792
|
+
// 其他属性透传
|
|
793
|
+
[key: string]: any // 其他 el-table-column 属性
|
|
794
|
+
}
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
#### 5.4 buttonType 操作按钮配置
|
|
798
|
+
|
|
799
|
+
```typescript
|
|
800
|
+
interface buttonType {
|
|
801
|
+
label: string // 按钮文本(必填)
|
|
802
|
+
type: String // 按钮类型(必填,用于样式和判断:edit/del 等)
|
|
803
|
+
permi?: any[] | String // 权限标识(预留)
|
|
804
|
+
hide?: Boolean // 是否隐藏
|
|
805
|
+
disabled?: (row: any) => Boolean // 禁用条件函数
|
|
806
|
+
show?: (row: any) => Boolean // 显示条件函数
|
|
807
|
+
click?: (row: any) => void // 点击回调函数(必填)
|
|
808
|
+
link?: (row: any) => Boolean // 是否显示为文字链接
|
|
809
|
+
|
|
810
|
+
// 其他属性(会透传到 el-button)
|
|
811
|
+
[key: string]: any
|
|
812
|
+
}
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
#### 5.5 表格事件(通过 $attrs 透传)
|
|
816
|
+
|
|
817
|
+
| 事件名 | 参数 | 说明 |
|
|
818
|
+
| ---------------- | ------------------------ | -------------------- |
|
|
819
|
+
| select | selection, row | 用户手动勾选时触发 |
|
|
820
|
+
| select-all | selection | 用户点击全选时触发 |
|
|
821
|
+
| selection-change | selection | 选择项发生变化时触发 |
|
|
822
|
+
| cell-click | row, column, cell, event | 单元格点击时触发 |
|
|
823
|
+
| cell-dblclick | row, column, cell, event | 单元格双击时触发 |
|
|
824
|
+
| row-click | row, column, event | 行点击时触发 |
|
|
825
|
+
| row-dblclick | row, column, event | 行双击时触发 |
|
|
826
|
+
| header-click | column, event | 表头点击时触发 |
|
|
827
|
+
| sort-change | { column, prop, order } | 排序发生变化时触发 |
|
|
828
|
+
| filter-change | filters | 筛选发生变化时触发 |
|
|
829
|
+
|
|
830
|
+
#### 5.6 Slots(模板插槽)
|
|
831
|
+
|
|
832
|
+
EasyTable 支持通过模板自定义列内容,插槽名为列的 `prop` 属性:
|
|
833
|
+
|
|
834
|
+
| 插槽名 | 作用域参数 | 说明 |
|
|
835
|
+
| ------ | --------------- | ----------------------------------- |
|
|
836
|
+
| {prop} | { row, $index } | 自定义列内容(prop 为列的 prop 值) |
|
|
837
|
+
|
|
838
|
+
```vue
|
|
839
|
+
<template>
|
|
840
|
+
<EasyTable :data="tableData" :table-columns="tableColumns">
|
|
841
|
+
<!-- 自定义 username 列 -->
|
|
842
|
+
<template #username="{ row }">
|
|
843
|
+
<el-tag>{{ row.username }}</el-tag>
|
|
844
|
+
</template>
|
|
845
|
+
|
|
846
|
+
<!-- 自定义操作列 -->
|
|
847
|
+
<template #operate="{ row }">
|
|
848
|
+
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
|
|
849
|
+
<el-button link type="danger" @click="handleDelete(row)">删除</el-button>
|
|
850
|
+
</template>
|
|
851
|
+
</EasyTable>
|
|
852
|
+
</template>
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
#### 5.7 嵌套表头
|
|
856
|
+
|
|
857
|
+
```typescript
|
|
858
|
+
const tableColumns = ref<TableColumn[]>([
|
|
859
|
+
{
|
|
860
|
+
label: '用户信息',
|
|
861
|
+
children: [
|
|
862
|
+
{
|
|
863
|
+
label: '姓名',
|
|
864
|
+
prop: 'name',
|
|
865
|
+
width: 120,
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
label: '联系方式',
|
|
869
|
+
children: [
|
|
870
|
+
{ label: '电话', prop: 'phone', width: 120 },
|
|
871
|
+
{ label: '邮箱', prop: 'email', width: 180 },
|
|
872
|
+
],
|
|
873
|
+
},
|
|
874
|
+
],
|
|
875
|
+
},
|
|
876
|
+
{
|
|
877
|
+
label: '操作',
|
|
878
|
+
fixed: 'right',
|
|
879
|
+
width: 150,
|
|
880
|
+
buttons: [
|
|
881
|
+
{ label: '编辑', type: 'edit', click: (row) => {} },
|
|
882
|
+
{ label: '删除', type: 'del', click: (row) => {} },
|
|
883
|
+
],
|
|
884
|
+
},
|
|
885
|
+
])
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
#### 5.8 特性
|
|
889
|
+
|
|
890
|
+
- **自动计算高度**:当父容器 class 包含 `content-wrap` 时,自动计算表格最大高度
|
|
891
|
+
- **响应式**:监听窗口 resize 事件自动调整表格高度
|
|
892
|
+
- **操作按钮**:支持配置多个操作按钮,自动处理删除按钮为 danger 类型
|
|
893
|
+
- **插槽优先级**:配置 slots > 模板插槽 > 默认渲染
|
|
894
|
+
|
|
895
|
+
---
|
|
896
|
+
|
|
897
|
+
### 6. MenuTree 菜单树组件
|
|
898
|
+
|
|
899
|
+
基于 Element Plus 的 `el-menu` 封装的菜单导航组件。
|
|
900
|
+
|
|
901
|
+
**源码位置**: [src/components/MenuTree/index.vue](file:///Users/max/Desktop/学习项目/mwl-components/src/components/MenuTree/index.vue)
|
|
902
|
+
|
|
903
|
+
#### 6.1 基础用法
|
|
904
|
+
|
|
905
|
+
```vue
|
|
906
|
+
<template>
|
|
907
|
+
<MenuTree :menu-list="menuList" @handleMenuItemClick="handleMenuItemClick" />
|
|
908
|
+
</template>
|
|
909
|
+
|
|
910
|
+
<script setup>
|
|
911
|
+
import { MenuTree } from 'mwl-components'
|
|
912
|
+
|
|
913
|
+
const menuList = ref([
|
|
914
|
+
{
|
|
915
|
+
path: '/home',
|
|
916
|
+
name: 'Home',
|
|
917
|
+
meta: { title: '首页', icon: 'HomeFilled' },
|
|
918
|
+
children: [],
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
path: '/user',
|
|
922
|
+
name: 'User',
|
|
923
|
+
meta: { title: '用户管理', icon: 'User' },
|
|
924
|
+
children: [
|
|
925
|
+
{ path: '/user/list', meta: { title: '用户列表', icon: 'List' } },
|
|
926
|
+
{ path: '/user/add', meta: { title: '新增用户', icon: 'Plus' } },
|
|
927
|
+
],
|
|
928
|
+
},
|
|
929
|
+
])
|
|
930
|
+
|
|
931
|
+
const handleMenuItemClick = (item) => {
|
|
932
|
+
console.log('点击菜单:', item)
|
|
933
|
+
}
|
|
934
|
+
</script>
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
#### 6.2 Props
|
|
938
|
+
|
|
939
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
940
|
+
| -------- | ----- | ------ | ------------ |
|
|
941
|
+
| menuList | Array | [] | 菜单数据列表 |
|
|
942
|
+
|
|
943
|
+
支持 Element Plus `el-menu` 的所有属性,通过 `v-bind="$attrs"` 透传:
|
|
944
|
+
|
|
945
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
946
|
+
| ----------------- | ------- | ---------- | ------------------------------ |
|
|
947
|
+
| default-active | String | - | 当前激活菜单的 index |
|
|
948
|
+
| default-openeds | Array | - | 当前打开的菜单 |
|
|
949
|
+
| mode | String | 'vertical' | 菜单模式 vertical / horizontal |
|
|
950
|
+
| collapse | Boolean | false | 是否折叠 |
|
|
951
|
+
| background-color | String | - | 背景色 |
|
|
952
|
+
| text-color | String | - | 文字颜色 |
|
|
953
|
+
| active-text-color | String | - | 激活菜单文字颜色 |
|
|
954
|
+
| unique-opened | Boolean | false | 是否只保持一个子菜单展开 |
|
|
955
|
+
| menu-trigger | String | 'hover' | 触发子菜单的方式 hover / click |
|
|
956
|
+
|
|
957
|
+
#### 6.3 Events
|
|
958
|
+
|
|
959
|
+
| 事件名 | 参数 | 说明 |
|
|
960
|
+
| ------------------- | ---- | -------------- |
|
|
961
|
+
| handleMenuItemClick | item | 菜单项点击事件 |
|
|
962
|
+
|
|
963
|
+
#### 6.4 菜单数据格式
|
|
964
|
+
|
|
965
|
+
```typescript
|
|
966
|
+
interface MenuItem {
|
|
967
|
+
path: string // 路由路径
|
|
968
|
+
name?: string // 路由名称
|
|
969
|
+
meta?: {
|
|
970
|
+
title: string // 菜单标题
|
|
971
|
+
icon?: string // 图标名称
|
|
972
|
+
[key: string]: any // 其他元信息
|
|
973
|
+
}
|
|
974
|
+
children?: MenuItem[] // 子菜单
|
|
975
|
+
[key: string]: any // 其他属性
|
|
976
|
+
}
|
|
977
|
+
```
|
|
978
|
+
|
|
979
|
+
#### 6.5 特性
|
|
980
|
+
|
|
981
|
+
- 支持无限级嵌套
|
|
982
|
+
- 自动渲染有子菜单的为 SubMenu,无子菜单的为 MenuItem
|
|
983
|
+
- 支持图标配置(需配合 el-icon 使用)
|
|
984
|
+
|
|
985
|
+
---
|
|
986
|
+
|
|
987
|
+
### 7. Pagination 分页组件
|
|
988
|
+
|
|
989
|
+
基于 Element Plus 的 `el-pagination` 封装的分页组件。
|
|
990
|
+
|
|
991
|
+
**源码位置**: [src/components/Pagination/index.vue](file:///Users/max/Desktop/学习项目/mwl-components/src/components/Pagination/index.vue)
|
|
992
|
+
|
|
993
|
+
#### 7.1 基础用法
|
|
994
|
+
|
|
995
|
+
```vue
|
|
996
|
+
<template>
|
|
997
|
+
<Pagination
|
|
998
|
+
v-model:page="pageData.page"
|
|
999
|
+
v-model:limit="pageData.pageSize"
|
|
1000
|
+
:total="total"
|
|
1001
|
+
@pagination="handlePagination"
|
|
1002
|
+
/>
|
|
1003
|
+
</template>
|
|
1004
|
+
|
|
1005
|
+
<script setup>
|
|
1006
|
+
import { ref, reactive } from 'vue'
|
|
1007
|
+
import { Pagination } from 'mwl-components'
|
|
1008
|
+
|
|
1009
|
+
const total = ref(100)
|
|
1010
|
+
const pageData = reactive({
|
|
1011
|
+
page: 1,
|
|
1012
|
+
pageSize: 20,
|
|
1013
|
+
})
|
|
1014
|
+
|
|
1015
|
+
const handlePagination = ({ page, limit }) => {
|
|
1016
|
+
console.log(`当前页: ${page}, 每页条数: ${limit}`)
|
|
1017
|
+
// 重新获取数据
|
|
1018
|
+
}
|
|
1019
|
+
</script>
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
#### 7.2 Props
|
|
1023
|
+
|
|
1024
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
1025
|
+
| ---------- | ------ | -------- | -------------------------------- |
|
|
1026
|
+
| total | Number | required | 总条目数 |
|
|
1027
|
+
| page | Number | 1 | 当前页数(v-model:page) |
|
|
1028
|
+
| limit | Number | 20 | 每页显示条数(v-model:limit) |
|
|
1029
|
+
| pagerCount | Number | 5/7 | 最大页码按钮数(移动端5,PC端7) |
|
|
1030
|
+
|
|
1031
|
+
支持 Element Plus `el-pagination` 的所有属性,以下是常用属性:
|
|
1032
|
+
|
|
1033
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
1034
|
+
| ---------- | ------- | ----------------------------------------- | ------------------- |
|
|
1035
|
+
| background | Boolean | true | 是否为背景色按钮 |
|
|
1036
|
+
| page-size | Number | - | 每页条数(默认 20) |
|
|
1037
|
+
| page-sizes | Array | [10, 20, 30, 50, 100] | 每页条数选择器 |
|
|
1038
|
+
| layout | String | 'total, sizes, prev, pager, next, jumper' | 组件布局 |
|
|
1039
|
+
| prev-text | String | - | 替代上一页图标文字 |
|
|
1040
|
+
| next-text | String | - | 替代下一页图标文字 |
|
|
1041
|
+
| small | Boolean | false | 是否使用小型分页 |
|
|
1042
|
+
|
|
1043
|
+
#### 7.3 Events
|
|
1044
|
+
|
|
1045
|
+
| 事件名 | 参数 | 说明 |
|
|
1046
|
+
| ------------ | --------------- | ------------------ |
|
|
1047
|
+
| pagination | { page, limit } | 分页变化时触发 |
|
|
1048
|
+
| update:page | page | 页码变化时触发 |
|
|
1049
|
+
| update:limit | limit | 每页条数变化时触发 |
|
|
1050
|
+
|
|
1051
|
+
---
|
|
1052
|
+
|
|
1053
|
+
### 8. EasyContextMenu 右键菜单组件(Vue 组件)
|
|
1054
|
+
|
|
1055
|
+
基于 Vue 实现的右键上下文菜单组件。
|
|
1056
|
+
|
|
1057
|
+
**源码位置**: [src/components/EasyContextMenu/index.vue](file:///Users/max/Desktop/学习项目/mwl-components/src/components/EasyContextMenu/index.vue)
|
|
1058
|
+
|
|
1059
|
+
#### 8.1 基础用法
|
|
1060
|
+
|
|
1061
|
+
```vue
|
|
1062
|
+
<template>
|
|
1063
|
+
<div>
|
|
1064
|
+
<div class="target-area">右键此区域</div>
|
|
1065
|
+
<EasyContextMenu :menu-list="menuList" :max-height="200" background-color="#fff" />
|
|
1066
|
+
</div>
|
|
1067
|
+
</template>
|
|
1068
|
+
|
|
1069
|
+
<script setup>
|
|
1070
|
+
import { ref } from 'vue'
|
|
1071
|
+
import { EasyContextMenu } from 'mwl-components'
|
|
1072
|
+
|
|
1073
|
+
const menuList = ref([
|
|
1074
|
+
{ label: '刷新', onClick: () => console.log('刷新') },
|
|
1075
|
+
{ label: '导出', onClick: () => console.log('导出') },
|
|
1076
|
+
{ label: '设置', onClick: () => console.log('设置') },
|
|
1077
|
+
])
|
|
1078
|
+
</script>
|
|
1079
|
+
```
|
|
1080
|
+
|
|
1081
|
+
#### 8.2 Props
|
|
1082
|
+
|
|
1083
|
+
| 属性名 | 类型 | 默认值 | 说明 |
|
|
1084
|
+
| --------------- | --------------- | --------------------------- | ---------------- |
|
|
1085
|
+
| menuList | Array | [] | 菜单列表 |
|
|
1086
|
+
| maxHeight | String / Number | 200 | 菜单最大高度 |
|
|
1087
|
+
| backgroundColor | String | '#fff' | 菜单背景颜色 |
|
|
1088
|
+
| hoverItemStyle | Object | { backgroundColor: '#ddd' } | hover 时的样式 |
|
|
1089
|
+
| animationCurve | String | 'linear' | 菜单显示动画曲线 |
|
|
1090
|
+
|
|
1091
|
+
#### 8.3 MenuItem 类型
|
|
1092
|
+
|
|
1093
|
+
```typescript
|
|
1094
|
+
interface MenuItem {
|
|
1095
|
+
label?: string // 菜单文本
|
|
1096
|
+
onClick?: (e: MouseEvent) => void // 点击回调
|
|
1097
|
+
disabled?: boolean // 是否禁用
|
|
1098
|
+
divider?: boolean // 是否为分隔线
|
|
1099
|
+
}
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
#### 8.4 特性
|
|
1103
|
+
|
|
1104
|
+
- 监听父元素的 contextmenu 事件显示菜单
|
|
1105
|
+
- 点击其他区域自动隐藏
|
|
1106
|
+
- 支持自定义背景色和 hover 样式
|
|
1107
|
+
- 菜单显示时有动画效果
|
|
1108
|
+
|
|
1109
|
+
---
|
|
1110
|
+
|
|
1111
|
+
### 9. ContextMenu 右键菜单类
|
|
1112
|
+
|
|
1113
|
+
通过面向对象方式创建右键菜单的类,适用于需要更灵活控制的场景。
|
|
1114
|
+
|
|
1115
|
+
**源码位置**: [src/components/ContextMenu/index.ts](file:///Users/max/Desktop/学习项目/mwl-components/src/components/ContextMenu/index.ts)
|
|
1116
|
+
|
|
1117
|
+
#### 9.1 基础用法
|
|
1118
|
+
|
|
1119
|
+
```vue
|
|
1120
|
+
<script setup>
|
|
1121
|
+
import { onMounted, onUnmounted } from 'vue'
|
|
1122
|
+
import ContextMenu, { contextMenu } from '@/components/ContextMenu/index.ts'
|
|
1123
|
+
|
|
1124
|
+
const menuList = [
|
|
1125
|
+
{ label: '刷新', onClick: () => location.reload() },
|
|
1126
|
+
{ label: '导出', onClick: () => console.log('导出') },
|
|
1127
|
+
{ divider: true },
|
|
1128
|
+
{ label: '帮助', onClick: () => console.log('帮助'), disabled: true },
|
|
1129
|
+
]
|
|
1130
|
+
|
|
1131
|
+
onMounted(() => {
|
|
1132
|
+
// 创建右键菜单
|
|
1133
|
+
new ContextMenu().create({
|
|
1134
|
+
target: document.getElementById('target'),
|
|
1135
|
+
menuList,
|
|
1136
|
+
event: 'contextmenu',
|
|
1137
|
+
})
|
|
1138
|
+
})
|
|
1139
|
+
|
|
1140
|
+
onUnmounted(() => {
|
|
1141
|
+
contextMenu.destroy()
|
|
1142
|
+
})
|
|
1143
|
+
</script>
|
|
1144
|
+
```
|
|
1145
|
+
|
|
1146
|
+
#### 9.2 MenuOptions 配置
|
|
1147
|
+
|
|
1148
|
+
```typescript
|
|
1149
|
+
interface MenuOptions {
|
|
1150
|
+
target?: HTMLElement // 绑定目标元素(必填)
|
|
1151
|
+
menuList: Array<MenuItem> // 菜单列表(必填)
|
|
1152
|
+
style?: Partial<CSSStyleDeclaration> // 自定义样式
|
|
1153
|
+
hoverStyle?: { [key: string]: string } // hover 样式
|
|
1154
|
+
event?: 'contextmenu' | 'click' | 'dblclick' // 触发事件类型
|
|
1155
|
+
appendToBody?: boolean // 是否添加到 body
|
|
1156
|
+
bindEvent?: boolean // 是否自动绑定事件
|
|
1157
|
+
classNames?: string // 自定义类名
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
interface MenuItem {
|
|
1161
|
+
label?: string // 菜单文本
|
|
1162
|
+
onClick?: (e: Event) => void // 点击回调
|
|
1163
|
+
divider?: boolean // 是否为分隔线
|
|
1164
|
+
disabled?: boolean // 是否禁用
|
|
1165
|
+
}
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
#### 9.3 实例方法
|
|
1169
|
+
|
|
1170
|
+
| 方法 | 参数 | 说明 |
|
|
1171
|
+
| --------------------------------- | -------- | ---------------- |
|
|
1172
|
+
| create(options: MenuOptions) | 配置对象 | 创建右键菜单 |
|
|
1173
|
+
| destroy() | - | 销毁右键菜单 |
|
|
1174
|
+
| setMenuList(menuList: MenuItem[]) | 菜单数组 | 动态设置菜单列表 |
|
|
1175
|
+
| showMenu(e: MouseEvent) | 事件对象 | 手动显示菜单 |
|
|
1176
|
+
| hideMenu() | - | 手动隐藏菜单 |
|
|
1177
|
+
|
|
1178
|
+
#### 9.4 默认样式
|
|
1179
|
+
|
|
1180
|
+
```typescript
|
|
1181
|
+
const defaultStyle = {
|
|
1182
|
+
position: 'fixed',
|
|
1183
|
+
'z-index': 1000,
|
|
1184
|
+
'border-radius': '4px',
|
|
1185
|
+
color: '#666',
|
|
1186
|
+
'font-size': '14px',
|
|
1187
|
+
'min-width': '100px',
|
|
1188
|
+
'box-shadow': '1px 1px 11px 0px #a6b5ba',
|
|
1189
|
+
'background-color': '#fff',
|
|
1190
|
+
padding: '4px',
|
|
1191
|
+
overflow: 'hidden',
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
const hoverStyle = {
|
|
1195
|
+
'background-color': '#8f9f80ff',
|
|
1196
|
+
}
|
|
1197
|
+
```
|
|
1198
|
+
|
|
1199
|
+
#### 9.5 导出对象
|
|
1200
|
+
|
|
1201
|
+
组件库导出了两种右键菜单使用方式:
|
|
1202
|
+
|
|
1203
|
+
1. **ContextMenu 类**:每次创建都是新实例
|
|
1204
|
+
|
|
1205
|
+
```typescript
|
|
1206
|
+
import { ContextMenu } from 'mwl-components'
|
|
1207
|
+
new ContextMenu().create({ ... })
|
|
1208
|
+
```
|
|
1209
|
+
|
|
1210
|
+
2. **contextMenu 单例**:全局共享实例
|
|
1211
|
+
|
|
1212
|
+
```typescript
|
|
1213
|
+
import { contextMenu } from 'mwl-components'
|
|
1214
|
+
contextMenu.create({ ... })
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
---
|
|
1218
|
+
|
|
1219
|
+
## 四、类型导出
|
|
1220
|
+
|
|
1221
|
+
组件库导出了以下类型定义:
|
|
1222
|
+
|
|
1223
|
+
```typescript
|
|
1224
|
+
import type {
|
|
1225
|
+
// 通用类型
|
|
1226
|
+
Options, // 下拉选项类型:Array<{ label: string; value: string | number; [key: string]: any }>
|
|
1227
|
+
Placement, // 弹出位置:'auto' | 'top' | 'bottom' | 'left' | 'right' | ...
|
|
1228
|
+
|
|
1229
|
+
// 表单相关
|
|
1230
|
+
FormItem, // 表单项配置
|
|
1231
|
+
Rule, // 表单校验规则:{ required?, message, pattern?, validator?, trigger? }
|
|
1232
|
+
ComponentMapType, // 组件映射配置
|
|
1233
|
+
|
|
1234
|
+
// 表格相关
|
|
1235
|
+
TableColumn, // 表格列配置
|
|
1236
|
+
buttonType, // 表格操作按钮配置
|
|
1237
|
+
Slots, // 插槽配置类型
|
|
1238
|
+
TableColumnSlots, // 表格列插槽类型
|
|
1239
|
+
|
|
1240
|
+
// 右键菜单
|
|
1241
|
+
MenuOptions, // 右键菜单配置
|
|
1242
|
+
MenuItem, // 右键菜单项
|
|
1243
|
+
} from 'mwl-components'
|
|
1244
|
+
```
|
|
1245
|
+
|
|
1246
|
+
---
|
|
1247
|
+
|
|
1248
|
+
## 五、主题定制
|
|
1249
|
+
|
|
1250
|
+
组件库使用 Element Plus 的主题系统,可以通过以下方式进行定制:
|
|
1251
|
+
|
|
1252
|
+
### 方式一:SCSS 变量覆盖
|
|
1253
|
+
|
|
1254
|
+
```scss
|
|
1255
|
+
// src/assets/styles/element/index.scss
|
|
1256
|
+
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
|
|
1257
|
+
$colors: (
|
|
1258
|
+
'primary': (
|
|
1259
|
+
'base': #0f9c11,
|
|
1260
|
+
),
|
|
1261
|
+
)
|
|
1262
|
+
);
|
|
1263
|
+
```
|
|
1264
|
+
|
|
1265
|
+
### 方式二:CSS 变量覆盖
|
|
1266
|
+
|
|
1267
|
+
```css
|
|
1268
|
+
:root {
|
|
1269
|
+
--el-color-primary: #0f9c11;
|
|
1270
|
+
}
|
|
1271
|
+
```
|
|
1272
|
+
|
|
1273
|
+
---
|
|
1274
|
+
|
|
1275
|
+
## 六、注意事项
|
|
1276
|
+
|
|
1277
|
+
1. **v-model 使用**:
|
|
1278
|
+
|
|
1279
|
+
- EasyForm 使用 `v-model` 双向绑定表单数据
|
|
1280
|
+
- Dialog 使用 `v-model` 控制显示隐藏
|
|
1281
|
+
- Pagination 使用 `v-model:page` 和 `v-model:limit`
|
|
1282
|
+
|
|
1283
|
+
2. **TypeScript 支持**:组件库完全使用 TypeScript 编写,提供完整的类型提示
|
|
1284
|
+
|
|
1285
|
+
3. **Tree-shaking 支持**:支持按需引入,可配合自动导入插件使用
|
|
1286
|
+
|
|
1287
|
+
4. **Element Plus 依赖**:组件库基于 Element Plus,需要全局或按需引入相关组件
|
|
1288
|
+
|
|
1289
|
+
5. **样式透传**:大部分组件支持通过 `$attrs` 透传属性到底层 Element Plus 组件
|
|
1290
|
+
|
|
1291
|
+
---
|
|
1292
|
+
|
|
1293
|
+
## 七、版本信息
|
|
1294
|
+
|
|
1295
|
+
- 当前版本:0.1.6
|
|
1296
|
+
- 构建输出:ES Module / CommonJS / UMD
|
|
1297
|
+
|
|
1298
|
+
## 八 打包配置问题
|
|
165
1299
|
|
|
166
1300
|
如果想让组件库 在主项目使 el-config-provider 的配置生效,在组件库中的组件中不要单独引入 element-plus 的组件,并且 在vite.config.ts 中配置如下
|
|
167
1301
|
自动导入方法AutoImport resolvers: [ElementPlusResolver()] 一定要注销掉 ,否则打包也会把element-plus 的组件打包进去
|