rayyy-vue-table-components 1.2.9 → 1.2.11
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 +669 -458
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,85 +1,160 @@
|
|
|
1
1
|
# Vue Table Components
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://img.shields.io/npm/v/rayyy-vue-table-components.svg" alt="npm version">
|
|
5
|
+
<img src="https://img.shields.io/npm/dm/rayyy-vue-table-components.svg" alt="npm downloads">
|
|
6
|
+
<img src="https://img.shields.io/github/license/rayshao/vue-table-components.svg" alt="license">
|
|
7
|
+
<img src="https://img.shields.io/badge/vue-3.x-brightgreen.svg" alt="vue">
|
|
8
|
+
</p>
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
基於 Vue 3 + Element Plus 的現代化表格組件庫,提供豐富的表格功能和靈活的自定義選項。
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
- 📦 基於 Element Plus
|
|
9
|
-
- 🎯 完整的 TypeScript 類型支持
|
|
10
|
-
- 📱 響應式設計
|
|
11
|
-
- 🔧 高度可配置
|
|
12
|
-
- 🎨 靈活的樣式系統 - 支援多種導入方式
|
|
13
|
-
- 🛠️ 現代化的 Sass 模組系統
|
|
14
|
-
- 💡 TypeScript 樣式工具函數
|
|
12
|
+
## ✨ 特性
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
- 🚀 **現代化技術棧** - 基於 Vue 3 + TypeScript + Element Plus
|
|
15
|
+
- 📦 **開箱即用** - 提供完整的表格解決方案
|
|
16
|
+
- 🎯 **類型安全** - 完整的 TypeScript 類型定義
|
|
17
|
+
- 📱 **響應式設計** - 適配各種設備尺寸
|
|
18
|
+
- 🔧 **高度可配置** - 靈活的配置選項
|
|
19
|
+
- 🎨 **樣式系統** - 多種樣式導入方式,支援自定義主題
|
|
20
|
+
- 🛠️ **現代化工具** - Sass 模組化 + TypeScript 樣式工具
|
|
21
|
+
- 💡 **豐富組件** - 表格、按鈕、對話框、穿梭框等
|
|
22
|
+
|
|
23
|
+
## 📦 安裝
|
|
24
|
+
|
|
25
|
+
使用您喜歡的包管理器安裝:
|
|
17
26
|
|
|
18
27
|
```bash
|
|
28
|
+
# npm
|
|
19
29
|
npm install rayyy-vue-table-components
|
|
20
|
-
|
|
30
|
+
|
|
31
|
+
# yarn
|
|
21
32
|
yarn add rayyy-vue-table-components
|
|
22
|
-
|
|
33
|
+
|
|
34
|
+
# pnpm
|
|
23
35
|
pnpm add rayyy-vue-table-components
|
|
24
36
|
```
|
|
25
37
|
|
|
26
|
-
|
|
38
|
+
> **注意**: 本組件庫需要 Vue 3.0+ 和 Element Plus 作為對等依賴。
|
|
27
39
|
|
|
28
|
-
|
|
40
|
+
## 🚀 快速開始
|
|
41
|
+
|
|
42
|
+
### 完整引入
|
|
29
43
|
|
|
30
|
-
|
|
44
|
+
在 `main.ts` 中完整引入所有組件:
|
|
31
45
|
|
|
32
46
|
```typescript
|
|
33
|
-
|
|
47
|
+
import { createApp } from 'vue'
|
|
48
|
+
import ElementPlus from 'element-plus'
|
|
34
49
|
import 'element-plus/dist/index.css'
|
|
35
|
-
import 'rayyy-vue-table-components
|
|
50
|
+
import VueTableComponents from 'rayyy-vue-table-components'
|
|
51
|
+
import 'rayyy-vue-table-components/styles'
|
|
52
|
+
|
|
53
|
+
import App from './App.vue'
|
|
54
|
+
|
|
55
|
+
const app = createApp(App)
|
|
56
|
+
|
|
57
|
+
app.use(ElementPlus)
|
|
58
|
+
app.use(VueTableComponents)
|
|
59
|
+
app.mount('#app')
|
|
36
60
|
```
|
|
37
61
|
|
|
38
|
-
|
|
62
|
+
### 按需引入
|
|
39
63
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
如果您只想使用部分組件,可以按需引入:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { createApp } from 'vue'
|
|
68
|
+
import { BaseTable, BaseBtn } from 'rayyy-vue-table-components'
|
|
69
|
+
import 'rayyy-vue-table-components/styles'
|
|
70
|
+
|
|
71
|
+
import App from './App.vue'
|
|
72
|
+
|
|
73
|
+
const app = createApp(App)
|
|
74
|
+
|
|
75
|
+
app.component('BaseTable', BaseTable)
|
|
76
|
+
app.component('BaseBtn', BaseBtn)
|
|
77
|
+
app.mount('#app')
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Hello World
|
|
81
|
+
|
|
82
|
+
創建您的第一個表格:
|
|
83
|
+
|
|
84
|
+
```vue
|
|
85
|
+
<template>
|
|
86
|
+
<BaseTable
|
|
87
|
+
:data="tableData"
|
|
88
|
+
:columns="columns"
|
|
89
|
+
:loading="loading"
|
|
90
|
+
/>
|
|
91
|
+
</template>
|
|
92
|
+
|
|
93
|
+
<script setup lang="ts">
|
|
94
|
+
import { ref } from 'vue'
|
|
95
|
+
import { BaseTable } from 'rayyy-vue-table-components'
|
|
96
|
+
import type { TableColumn } from 'rayyy-vue-table-components'
|
|
97
|
+
|
|
98
|
+
interface User {
|
|
99
|
+
id: number
|
|
100
|
+
name: string
|
|
101
|
+
email: string
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const loading = ref(false)
|
|
105
|
+
const tableData = ref<User[]>([
|
|
106
|
+
{ id: 1, name: '張三', email: 'zhangsan@example.com' },
|
|
107
|
+
{ id: 2, name: '李四', email: 'lisi@example.com' }
|
|
108
|
+
])
|
|
109
|
+
|
|
110
|
+
const columns: TableColumn<User>[] = [
|
|
111
|
+
{ prop: 'id', label: 'ID', width: 80 },
|
|
112
|
+
{ prop: 'name', label: '姓名' },
|
|
113
|
+
{ prop: 'email', label: '郵箱' }
|
|
114
|
+
]
|
|
115
|
+
</script>
|
|
44
116
|
```
|
|
45
117
|
|
|
46
|
-
|
|
118
|
+
## 🎨 樣式配置
|
|
119
|
+
|
|
120
|
+
本組件庫提供多種靈活的樣式導入方式:
|
|
121
|
+
|
|
122
|
+
### 完整樣式導入(推薦)
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// main.ts
|
|
126
|
+
import 'element-plus/dist/index.css'
|
|
127
|
+
import 'rayyy-vue-table-components/styles'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 自定義主題
|
|
47
131
|
|
|
48
132
|
```scss
|
|
49
133
|
// styles.scss
|
|
50
134
|
@import 'element-plus/dist/index.css';
|
|
51
|
-
@import 'rayyy-vue-table-components/styles/element';
|
|
135
|
+
@import 'rayyy-vue-table-components/styles/element';
|
|
52
136
|
```
|
|
53
137
|
|
|
54
|
-
###
|
|
138
|
+
### TypeScript 樣式工具
|
|
55
139
|
|
|
56
140
|
```typescript
|
|
57
|
-
// 導入樣式工具函數
|
|
58
141
|
import { tableStyles, createTableCellClass } from 'rayyy-vue-table-components/utils/styles'
|
|
59
142
|
|
|
60
|
-
//
|
|
143
|
+
// 動態生成樣式類
|
|
61
144
|
const cellClass = createTableCellClass({
|
|
62
145
|
isDismissed: true,
|
|
63
146
|
isHeader: false
|
|
64
147
|
})
|
|
65
148
|
```
|
|
66
149
|
|
|
67
|
-
##
|
|
68
|
-
|
|
69
|
-
### 全局註冊
|
|
150
|
+
## 📚 組件示例
|
|
70
151
|
|
|
71
|
-
|
|
72
|
-
import { createApp } from 'vue'
|
|
73
|
-
import VueTableComponents from 'rayyy-vue-table-components'
|
|
74
|
-
|
|
75
|
-
// 導入樣式(選擇上述任一方式)
|
|
76
|
-
import 'rayyy-vue-table-components/styles'
|
|
152
|
+
### BaseTable - 數據表格
|
|
77
153
|
|
|
78
|
-
|
|
79
|
-
app.use(VueTableComponents)
|
|
80
|
-
```
|
|
154
|
+
基礎的數據表格組件,支援排序、選擇、自定義列等功能。
|
|
81
155
|
|
|
82
|
-
|
|
156
|
+
<details>
|
|
157
|
+
<summary>基本用法</summary>
|
|
83
158
|
|
|
84
159
|
```vue
|
|
85
160
|
<template>
|
|
@@ -89,60 +164,13 @@ app.use(VueTableComponents)
|
|
|
89
164
|
:loading="loading"
|
|
90
165
|
@column-sort-change="handleSortChange"
|
|
91
166
|
/>
|
|
92
|
-
|
|
93
|
-
<BaseBtn type="primary" @click="showDialog = true">
|
|
94
|
-
打開對話框
|
|
95
|
-
</BaseBtn>
|
|
96
|
-
|
|
97
|
-
<BaseDialog v-model="showDialog" title="確認操作">
|
|
98
|
-
<p>您確定要執行此操作嗎?</p>
|
|
99
|
-
</BaseDialog>
|
|
100
|
-
|
|
101
|
-
<!-- TransferDialog 示例 -->
|
|
102
|
-
<TransferDialog
|
|
103
|
-
v-model="showTransferDialog"
|
|
104
|
-
:columns-value="tableColumns"
|
|
105
|
-
transfer-title="配置表格列"
|
|
106
|
-
@update:submit="handleColumnSubmit"
|
|
107
|
-
>
|
|
108
|
-
<template #list-container="{ columns, clickItemProp, handleItemEvents, handleMousedown }">
|
|
109
|
-
<draggable :list="columns" item-key="prop" delay="200">
|
|
110
|
-
<template #item="{ element, index }">
|
|
111
|
-
<transfer-item
|
|
112
|
-
:columns-value="element"
|
|
113
|
-
:columns-index="index"
|
|
114
|
-
:columns-len="columns.length"
|
|
115
|
-
:class="{
|
|
116
|
-
'transfer-active-bg': element.checkActive,
|
|
117
|
-
'transfer-active-border': clickItemProp === element.prop,
|
|
118
|
-
}"
|
|
119
|
-
@mousedown="handleMousedown(element.prop || '')"
|
|
120
|
-
@update:toTop="handleItemEvents.toTop(index)"
|
|
121
|
-
@update:toBottom="handleItemEvents.toBottom(index)"
|
|
122
|
-
@update:toPre="handleItemEvents.toPre(index)"
|
|
123
|
-
@update:toNext="handleItemEvents.toNext(index)"
|
|
124
|
-
/>
|
|
125
|
-
</template>
|
|
126
|
-
</draggable>
|
|
127
|
-
</template>
|
|
128
|
-
</TransferDialog>
|
|
129
167
|
</template>
|
|
130
168
|
|
|
131
169
|
<script setup lang="ts">
|
|
132
|
-
|
|
133
|
-
import { BaseTable
|
|
170
|
+
import { ref } from 'vue'
|
|
171
|
+
import { BaseTable } from 'rayyy-vue-table-components'
|
|
134
172
|
import type { TableColumn, SortChangValue } from 'rayyy-vue-table-components'
|
|
135
173
|
|
|
136
|
-
// 方式二:單獨導入組件
|
|
137
|
-
import { BaseTable } from 'rayyy-vue-table-components/components'
|
|
138
|
-
import type { TableColumn } from 'rayyy-vue-table-components/types'
|
|
139
|
-
|
|
140
|
-
// 方式三:單獨導入類型
|
|
141
|
-
import type { SortChangValue } from 'rayyy-vue-table-components/types'
|
|
142
|
-
|
|
143
|
-
// 方式四:導入樣式工具函數
|
|
144
|
-
import { tableStyles, createTableCellClass } from 'rayyy-vue-table-components/utils/styles'
|
|
145
|
-
|
|
146
174
|
interface User {
|
|
147
175
|
id: number
|
|
148
176
|
name: string
|
|
@@ -150,10 +178,11 @@ interface User {
|
|
|
150
178
|
age: number
|
|
151
179
|
}
|
|
152
180
|
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
{ id:
|
|
156
|
-
|
|
181
|
+
const loading = ref(false)
|
|
182
|
+
const tableData = ref<User[]>([
|
|
183
|
+
{ id: 1, name: '張三', email: 'zhangsan@example.com', age: 30 },
|
|
184
|
+
{ id: 2, name: '李四', email: 'lisi@example.com', age: 25 }
|
|
185
|
+
])
|
|
157
186
|
|
|
158
187
|
const columns: TableColumn<User>[] = [
|
|
159
188
|
{ prop: 'id', label: 'ID', width: 80 },
|
|
@@ -162,329 +191,406 @@ const columns: TableColumn<User>[] = [
|
|
|
162
191
|
{ prop: 'age', label: '年齡', sortable: true }
|
|
163
192
|
]
|
|
164
193
|
|
|
165
|
-
const loading = ref(false)
|
|
166
|
-
|
|
167
194
|
const handleSortChange = (sortInfo: SortChangValue<User>) => {
|
|
168
195
|
console.log('排序變更:', sortInfo)
|
|
169
196
|
}
|
|
197
|
+
</script>
|
|
198
|
+
```
|
|
199
|
+
</details>
|
|
170
200
|
|
|
171
|
-
|
|
172
|
-
|
|
201
|
+
<details>
|
|
202
|
+
<summary>帶選擇和合計的表格</summary>
|
|
173
203
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
204
|
+
```vue
|
|
205
|
+
<template>
|
|
206
|
+
<BaseTable
|
|
207
|
+
:data="tableData"
|
|
208
|
+
:columns="columns"
|
|
209
|
+
:show-selection="true"
|
|
210
|
+
:show-summary="true"
|
|
211
|
+
:summary-method="summaryMethod"
|
|
212
|
+
@selection-change="handleSelectionChange"
|
|
213
|
+
/>
|
|
214
|
+
</template>
|
|
215
|
+
|
|
216
|
+
<script setup lang="ts">
|
|
217
|
+
import { ref } from 'vue'
|
|
218
|
+
import { BaseTable } from 'rayyy-vue-table-components'
|
|
219
|
+
import type { TableColumn } from 'rayyy-vue-table-components'
|
|
220
|
+
|
|
221
|
+
interface Product {
|
|
222
|
+
id: number
|
|
223
|
+
name: string
|
|
224
|
+
price: number
|
|
225
|
+
quantity: number
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const tableData = ref<Product[]>([
|
|
229
|
+
{ id: 1, name: '產品A', price: 100, quantity: 5 },
|
|
230
|
+
{ id: 2, name: '產品B', price: 200, quantity: 3 }
|
|
231
|
+
])
|
|
232
|
+
|
|
233
|
+
const columns: TableColumn<Product>[] = [
|
|
234
|
+
{ prop: 'id', label: 'ID', width: 80 },
|
|
235
|
+
{ prop: 'name', label: '產品名稱' },
|
|
236
|
+
{ prop: 'price', label: '單價' },
|
|
237
|
+
{ prop: 'quantity', label: '數量' }
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
const summaryMethod = ({ columns, data }: any) => {
|
|
241
|
+
const sums: string[] = []
|
|
242
|
+
columns.forEach((column: any, index: number) => {
|
|
243
|
+
if (index === 0) {
|
|
244
|
+
sums[index] = '總計'
|
|
245
|
+
} else if (column.property === 'price') {
|
|
246
|
+
const values = data.map((item: Product) => Number(item.price))
|
|
247
|
+
sums[index] = values.reduce((prev, curr) => prev + curr, 0).toString()
|
|
248
|
+
} else if (column.property === 'quantity') {
|
|
249
|
+
const values = data.map((item: Product) => Number(item.quantity))
|
|
250
|
+
sums[index] = values.reduce((prev, curr) => prev + curr, 0).toString()
|
|
251
|
+
} else {
|
|
252
|
+
sums[index] = ''
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
return sums
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const handleSelectionChange = (selection: Product[]) => {
|
|
259
|
+
console.log('選中項:', selection)
|
|
177
260
|
}
|
|
178
261
|
</script>
|
|
179
262
|
```
|
|
263
|
+
</details>
|
|
180
264
|
|
|
181
|
-
|
|
265
|
+
### BaseBtn - 按鈕組件
|
|
182
266
|
|
|
183
|
-
|
|
267
|
+
增強的按鈕組件,支援多種樣式和狀態。
|
|
184
268
|
|
|
185
|
-
|
|
269
|
+
<details>
|
|
270
|
+
<summary>基本用法</summary>
|
|
186
271
|
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
BaseBtnInstance,
|
|
198
|
-
|
|
199
|
-
// BaseDialog 組件類型
|
|
200
|
-
BaseDialogProps,
|
|
201
|
-
BaseDialogEmits,
|
|
202
|
-
BaseDialogInstance,
|
|
203
|
-
|
|
204
|
-
// 插件類型
|
|
205
|
-
PluginOptions,
|
|
206
|
-
VueTableComponentsPlugin
|
|
207
|
-
} from 'rayyy-vue-table-components/types/components'
|
|
208
|
-
```
|
|
272
|
+
```vue
|
|
273
|
+
<template>
|
|
274
|
+
<div class="button-group">
|
|
275
|
+
<BaseBtn type="primary" @click="handleClick">主要按鈕</BaseBtn>
|
|
276
|
+
<BaseBtn type="success" :loading="loading">成功按鈕</BaseBtn>
|
|
277
|
+
<BaseBtn type="warning" plain>樸素按鈕</BaseBtn>
|
|
278
|
+
<BaseBtn type="danger" disabled>禁用按鈕</BaseBtn>
|
|
279
|
+
<BaseBtn type="info" link>文字按鈕</BaseBtn>
|
|
280
|
+
</div>
|
|
281
|
+
</template>
|
|
209
282
|
|
|
210
|
-
|
|
283
|
+
<script setup lang="ts">
|
|
284
|
+
import { ref } from 'vue'
|
|
285
|
+
import { BaseBtn } from 'rayyy-vue-table-components'
|
|
211
286
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
287
|
+
const loading = ref(false)
|
|
288
|
+
|
|
289
|
+
const handleClick = () => {
|
|
290
|
+
loading.value = true
|
|
291
|
+
setTimeout(() => {
|
|
292
|
+
loading.value = false
|
|
293
|
+
}, 2000)
|
|
294
|
+
}
|
|
295
|
+
</script>
|
|
296
|
+
|
|
297
|
+
<style scoped>
|
|
298
|
+
.button-group {
|
|
299
|
+
display: flex;
|
|
300
|
+
gap: 12px;
|
|
301
|
+
flex-wrap: wrap;
|
|
302
|
+
}
|
|
303
|
+
</style>
|
|
221
304
|
```
|
|
305
|
+
</details>
|
|
222
306
|
|
|
223
|
-
###
|
|
307
|
+
### BaseDialog - 對話框組件
|
|
224
308
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
309
|
+
靈活的對話框組件,支援多種配置選項。
|
|
310
|
+
|
|
311
|
+
<details>
|
|
312
|
+
<summary>基本用法</summary>
|
|
313
|
+
|
|
314
|
+
```vue
|
|
315
|
+
<template>
|
|
316
|
+
<div>
|
|
317
|
+
<BaseBtn type="primary" @click="showDialog = true">
|
|
318
|
+
打開對話框
|
|
319
|
+
</BaseBtn>
|
|
320
|
+
|
|
321
|
+
<BaseDialog
|
|
322
|
+
v-model="showDialog"
|
|
323
|
+
title="確認操作"
|
|
324
|
+
sub-title="此操作將永久刪除該文件,是否繼續?"
|
|
325
|
+
:is-warning="true"
|
|
326
|
+
@confirm="handleConfirm"
|
|
327
|
+
@cancel="handleCancel"
|
|
328
|
+
>
|
|
329
|
+
<p>這是對話框的內容區域,您可以放置任何內容。</p>
|
|
330
|
+
</BaseDialog>
|
|
331
|
+
</div>
|
|
332
|
+
</template>
|
|
333
|
+
|
|
334
|
+
<script setup lang="ts">
|
|
335
|
+
import { ref } from 'vue'
|
|
336
|
+
import { BaseBtn, BaseDialog } from 'rayyy-vue-table-components'
|
|
337
|
+
|
|
338
|
+
const showDialog = ref(false)
|
|
339
|
+
|
|
340
|
+
const handleConfirm = () => {
|
|
341
|
+
console.log('確認操作')
|
|
342
|
+
showDialog.value = false
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const handleCancel = () => {
|
|
346
|
+
console.log('取消操作')
|
|
347
|
+
showDialog.value = false
|
|
348
|
+
}
|
|
349
|
+
</script>
|
|
240
350
|
```
|
|
351
|
+
</details>
|
|
241
352
|
|
|
242
|
-
###
|
|
353
|
+
### TransferDialog - 穿梭框對話框
|
|
243
354
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
355
|
+
用於表格列配置的穿梭框組件,支援拖拽排序。
|
|
356
|
+
|
|
357
|
+
<details>
|
|
358
|
+
<summary>基本用法</summary>
|
|
359
|
+
|
|
360
|
+
```vue
|
|
361
|
+
<template>
|
|
362
|
+
<div>
|
|
363
|
+
<BaseBtn @click="showTransferDialog = true">配置表格列</BaseBtn>
|
|
364
|
+
|
|
365
|
+
<TransferDialog
|
|
366
|
+
v-model="showTransferDialog"
|
|
367
|
+
:columns-value="tableColumns"
|
|
368
|
+
transfer-title="配置表格列"
|
|
369
|
+
@update:submit="handleColumnSubmit"
|
|
370
|
+
>
|
|
371
|
+
<template #list-container="{ columns, clickItemProp, handleItemEvents, handleMousedown }">
|
|
372
|
+
<draggable :list="columns" item-key="prop" delay="200">
|
|
373
|
+
<template #item="{ element, index }">
|
|
374
|
+
<TransferItem
|
|
375
|
+
:columns-value="element"
|
|
376
|
+
:columns-index="index"
|
|
377
|
+
:columns-len="columns.length"
|
|
378
|
+
:class="{
|
|
379
|
+
'transfer-active-bg': element.checkActive,
|
|
380
|
+
'transfer-active-border': clickItemProp === element.prop,
|
|
381
|
+
}"
|
|
382
|
+
@mousedown="handleMousedown(element.prop || '')"
|
|
383
|
+
@update:toTop="handleItemEvents.toTop(index)"
|
|
384
|
+
@update:toBottom="handleItemEvents.toBottom(index)"
|
|
385
|
+
@update:toPre="handleItemEvents.toPre(index)"
|
|
386
|
+
@update:toNext="handleItemEvents.toNext(index)"
|
|
387
|
+
/>
|
|
388
|
+
</template>
|
|
389
|
+
</draggable>
|
|
390
|
+
</template>
|
|
391
|
+
</TransferDialog>
|
|
392
|
+
|
|
393
|
+
<!-- 使用配置後的表格 -->
|
|
394
|
+
<BaseTable
|
|
395
|
+
:data="tableData"
|
|
396
|
+
:columns="visibleColumns"
|
|
397
|
+
style="margin-top: 20px"
|
|
398
|
+
/>
|
|
399
|
+
</div>
|
|
400
|
+
</template>
|
|
401
|
+
|
|
402
|
+
<script setup lang="ts">
|
|
403
|
+
import { ref, computed } from 'vue'
|
|
404
|
+
import draggable from 'vuedraggable'
|
|
405
|
+
import { BaseBtn, BaseTable, TransferDialog, TransferItem } from 'rayyy-vue-table-components'
|
|
406
|
+
import type { TableColumn } from 'rayyy-vue-table-components'
|
|
407
|
+
|
|
408
|
+
interface User {
|
|
247
409
|
id: number
|
|
248
410
|
name: string
|
|
249
411
|
email: string
|
|
250
412
|
age: number
|
|
251
|
-
status: 'active' | 'inactive'
|
|
252
413
|
}
|
|
253
414
|
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
{
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
width: 80,
|
|
260
|
-
align: 'center'
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
prop: 'name',
|
|
264
|
-
label: '姓名',
|
|
265
|
-
width: 120
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
prop: 'email',
|
|
269
|
-
label: '郵箱',
|
|
270
|
-
width: 200
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
prop: 'age',
|
|
274
|
-
label: '年齡',
|
|
275
|
-
width: 80,
|
|
276
|
-
align: 'center',
|
|
277
|
-
sortable: true
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
prop: 'status',
|
|
281
|
-
label: '狀態',
|
|
282
|
-
width: 100,
|
|
283
|
-
align: 'center',
|
|
284
|
-
formatter: (row: User) => row.status === 'active' ? '啟用' : '停用'
|
|
285
|
-
}
|
|
286
|
-
]
|
|
415
|
+
const showTransferDialog = ref(false)
|
|
416
|
+
const tableData = ref<User[]>([
|
|
417
|
+
{ id: 1, name: '張三', email: 'zhangsan@example.com', age: 30 },
|
|
418
|
+
{ id: 2, name: '李四', email: 'lisi@example.com', age: 25 }
|
|
419
|
+
])
|
|
287
420
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
{
|
|
291
|
-
{
|
|
292
|
-
|
|
421
|
+
const tableColumns = ref<TableColumn<User>[]>([
|
|
422
|
+
{ prop: 'id', label: 'ID', width: 80, checkActive: true },
|
|
423
|
+
{ prop: 'name', label: '姓名', checkActive: true },
|
|
424
|
+
{ prop: 'email', label: '郵箱', checkActive: true },
|
|
425
|
+
{ prop: 'age', label: '年齡', checkActive: false }
|
|
426
|
+
])
|
|
293
427
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
showOverFlowTooltip: true,
|
|
302
|
-
summaryMethod: ({ columns, data }) => {
|
|
303
|
-
return ['總計', '', '', data.reduce((sum, user) => sum + user.age, 0).toString(), '']
|
|
304
|
-
},
|
|
305
|
-
baseTableRowClassName: ({ row, rowIndex }) => {
|
|
306
|
-
return row.status === 'active' ? 'active-row' : 'inactive-row'
|
|
307
|
-
}
|
|
428
|
+
const visibleColumns = computed(() =>
|
|
429
|
+
tableColumns.value.filter(col => col.checkActive)
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
const handleColumnSubmit = (newColumns: TableColumn<User>[]) => {
|
|
433
|
+
tableColumns.value = newColumns
|
|
434
|
+
showTransferDialog.value = false
|
|
308
435
|
}
|
|
436
|
+
</script>
|
|
437
|
+
```
|
|
438
|
+
</details>
|
|
309
439
|
|
|
310
|
-
|
|
311
|
-
const dynamicCellClass = createTableCellClass({
|
|
312
|
-
isDismissed: user.status === 'inactive',
|
|
313
|
-
isHeader: false
|
|
314
|
-
})
|
|
440
|
+
## 🔧 API 參考
|
|
315
441
|
|
|
316
|
-
|
|
442
|
+
### BaseTable
|
|
317
443
|
|
|
318
|
-
|
|
319
|
-
const cellClasses = [
|
|
320
|
-
tableStyles.cell, // 基礎單元格樣式
|
|
321
|
-
tableStyles.content, // 內容樣式
|
|
322
|
-
user.status === 'inactive' ? tableStyles.dismissed : ''
|
|
323
|
-
].filter(Boolean).join(' ')
|
|
324
|
-
```
|
|
444
|
+
基礎表格組件,提供完整的數據展示和交互功能。
|
|
325
445
|
|
|
326
|
-
|
|
446
|
+
#### Props
|
|
327
447
|
|
|
328
|
-
|
|
448
|
+
| 屬性 | 類型 | 默認值 | 說明 |
|
|
449
|
+
|------|------|--------|------|
|
|
450
|
+
| `data` | `T[]` | `[]` | 表格數據 |
|
|
451
|
+
| `columns` | `TableColumn<T>[]` | `[]` | 表格列配置 |
|
|
452
|
+
| `loading` | `boolean` | `false` | 加載狀態 |
|
|
453
|
+
| `showSelection` | `boolean` | `false` | 是否顯示選擇列 |
|
|
454
|
+
| `showSummary` | `boolean` | `false` | 是否顯示合計行 |
|
|
455
|
+
| `showOverFlowTooltip` | `boolean` | `false` | 是否顯示溢出提示 |
|
|
456
|
+
| `summaryMethod` | `SummaryMethod<T>` | - | 合計行計算方法 |
|
|
457
|
+
| `baseTableRowClassName` | `RowClassNameGetter<T>` | - | 行樣式類名函數 |
|
|
329
458
|
|
|
330
|
-
|
|
331
|
-
// 直接使用預定義樣式
|
|
332
|
-
import { tableStyles, componentStyles } from 'rayyy-vue-table-components/utils/styles'
|
|
459
|
+
#### Events
|
|
333
460
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
tableStyles.blueText // 藍色文字: 'text-blue-10'
|
|
341
|
-
tableStyles.redText // 紅色文字: 'text-redText'
|
|
342
|
-
|
|
343
|
-
// 組件樣式
|
|
344
|
-
componentStyles.sortTableContainer // SortTable 容器: 'w-full mb-4'
|
|
345
|
-
componentStyles.sortTableFunctionBar // SortTable 功能欄
|
|
346
|
-
componentStyles.filterBtn // FilterBtn 按鈕樣式
|
|
347
|
-
componentStyles.transferActiveBg // Transfer 啟用背景
|
|
348
|
-
componentStyles.baseDialogTitle // Dialog 標題樣式
|
|
349
|
-
componentStyles.cursorGrab // 抓取游標
|
|
350
|
-
```
|
|
461
|
+
| 事件名 | 參數 | 說明 |
|
|
462
|
+
|--------|------|------|
|
|
463
|
+
| `selection-change` | `selection: T[]` | 選擇項變更時觸發 |
|
|
464
|
+
| `current-change` | `currentRow: T \| null` | 當前行變更時觸發 |
|
|
465
|
+
| `cell-click` | `column: TableColumn<T>, row: T` | 單元格點擊時觸發 |
|
|
466
|
+
| `column-sort-change` | `value: SortChangValue<T>` | 列排序變更時觸發 |
|
|
351
467
|
|
|
352
|
-
|
|
468
|
+
#### Slots
|
|
353
469
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
isHeader?: boolean
|
|
359
|
-
}) => string
|
|
470
|
+
| 插槽名 | 參數 | 說明 |
|
|
471
|
+
|--------|------|------|
|
|
472
|
+
| `empty` | - | 空數據時的內容 |
|
|
473
|
+
| `append` | - | 插入至表格最後一行之後的內容 |
|
|
360
474
|
|
|
361
|
-
|
|
362
|
-
createTextClass(type: 'blue' | 'red' | 'normal' = 'normal') => string
|
|
475
|
+
---
|
|
363
476
|
|
|
364
|
-
|
|
365
|
-
const cellClass = createTableCellClass({
|
|
366
|
-
isDismissed: true, // 添加被駁回樣式
|
|
367
|
-
isHeader: false // 不是標題行
|
|
368
|
-
})
|
|
369
|
-
// 結果: 'p-0 h-10 bg-blue-20'
|
|
477
|
+
### BaseBtn
|
|
370
478
|
|
|
371
|
-
|
|
372
|
-
// 結果: 'text-blue-10'
|
|
373
|
-
```
|
|
479
|
+
增強的按鈕組件,基於 Element Plus Button 擴展。
|
|
374
480
|
|
|
375
|
-
|
|
481
|
+
#### Props
|
|
376
482
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
483
|
+
| 屬性 | 類型 | 默認值 | 說明 |
|
|
484
|
+
|------|------|--------|------|
|
|
485
|
+
| `text` | `string` | - | 按鈕文字 |
|
|
486
|
+
| `type` | `ButtonType` | `'default'` | 按鈕類型 |
|
|
487
|
+
| `size` | `ComponentSize` | `'default'` | 按鈕尺寸 |
|
|
488
|
+
| `plain` | `boolean` | `false` | 是否為樸素按鈕 |
|
|
489
|
+
| `disabled` | `boolean` | `false` | 是否禁用 |
|
|
490
|
+
| `loading` | `boolean` | `false` | 是否顯示加載狀態 |
|
|
491
|
+
| `icon` | `Component` | - | 圖標組件 |
|
|
492
|
+
| `link` | `boolean` | `false` | 是否為文字按鈕 |
|
|
493
|
+
| `isFill` | `boolean` | `false` | 是否為填充樣式 |
|
|
494
|
+
|
|
495
|
+
#### Events
|
|
380
496
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
497
|
+
| 事件名 | 參數 | 說明 |
|
|
498
|
+
|--------|------|------|
|
|
499
|
+
| `click` | `event: MouseEvent` | 點擊按鈕時觸發 |
|
|
500
|
+
|
|
501
|
+
#### 類型定義
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
type ButtonType = 'default' | 'primary' | 'success' | 'warning' | 'info' | 'danger'
|
|
505
|
+
type ComponentSize = 'default' | 'small' | 'large'
|
|
387
506
|
```
|
|
388
507
|
|
|
389
|
-
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
### BaseDialog
|
|
390
511
|
|
|
391
|
-
|
|
512
|
+
靈活的對話框組件,支援多種配置選項。
|
|
513
|
+
|
|
514
|
+
#### Props
|
|
392
515
|
|
|
393
516
|
| 屬性 | 類型 | 默認值 | 說明 |
|
|
394
517
|
|------|------|--------|------|
|
|
395
|
-
|
|
|
396
|
-
|
|
|
397
|
-
|
|
|
398
|
-
|
|
|
399
|
-
|
|
|
400
|
-
|
|
|
401
|
-
|
|
|
402
|
-
|
|
|
518
|
+
| `modelValue` | `boolean` | - | 對話框顯示狀態 |
|
|
519
|
+
| `title` | `string` | - | 對話框標題 |
|
|
520
|
+
| `subTitle` | `string` | - | 副標題 |
|
|
521
|
+
| `customWidth` | `string` | - | 自定義寬度 |
|
|
522
|
+
| `isWarning` | `boolean` | `false` | 是否為警告對話框 |
|
|
523
|
+
| `isPrimary` | `boolean` | `false` | 是否為主要對話框 |
|
|
524
|
+
| `bodyLoading` | `boolean` | `false` | 內容區域加載狀態 |
|
|
525
|
+
| `submitLoading` | `boolean` | `false` | 提交按鈕加載狀態 |
|
|
403
526
|
|
|
404
|
-
|
|
527
|
+
#### Events
|
|
405
528
|
|
|
406
529
|
| 事件名 | 參數 | 說明 |
|
|
407
530
|
|--------|------|------|
|
|
408
|
-
|
|
|
409
|
-
|
|
|
410
|
-
|
|
|
411
|
-
| column-sort-change | `value: SortChangValue<T>` | 列排序變更 |
|
|
531
|
+
| `update:modelValue` | `value: boolean` | 對話框顯示狀態變更 |
|
|
532
|
+
| `confirm` | - | 確認按鈕點擊時觸發 |
|
|
533
|
+
| `cancel` | - | 取消按鈕點擊時觸發 |
|
|
412
534
|
|
|
413
|
-
|
|
535
|
+
#### Slots
|
|
414
536
|
|
|
415
|
-
|
|
|
416
|
-
|
|
417
|
-
|
|
|
418
|
-
|
|
|
419
|
-
| loading | `boolean` | `false` | 加載狀態 |
|
|
420
|
-
| showSelection | `boolean` | `false` | 是否顯示選擇列 |
|
|
421
|
-
| showSummary | `boolean` | `false` | 是否顯示合計行 |
|
|
422
|
-
| showOverFlowTooltip | `boolean` | `false` | 是否顯示溢出提示 |
|
|
423
|
-
| summaryMethod | `Function` | - | 合計行計算方法 |
|
|
424
|
-
| baseTableRowClassName | `Function` | - | 行樣式類名函數 |
|
|
537
|
+
| 插槽名 | 參數 | 說明 |
|
|
538
|
+
|--------|------|------|
|
|
539
|
+
| `default` | - | 對話框內容 |
|
|
540
|
+
| `footer` | - | 自定義底部按鈕區域 |
|
|
425
541
|
|
|
426
|
-
|
|
542
|
+
---
|
|
427
543
|
|
|
428
|
-
|
|
429
|
-
|------|------|--------|------|
|
|
430
|
-
| text | `string` | - | 按鈕文字 |
|
|
431
|
-
| type | `'default' \| 'primary' \| 'success' \| 'warning' \| 'info' \| 'danger'` | `'default'` | 按鈕類型 |
|
|
432
|
-
| size | `'default' \| 'small' \| 'large'` | `'default'` | 按鈕尺寸 |
|
|
433
|
-
| plain | `boolean` | `false` | 是否為樸素按鈕 |
|
|
434
|
-
| disabled | `boolean` | `false` | 是否禁用 |
|
|
435
|
-
| loading | `boolean` | `false` | 是否顯示加載狀態 |
|
|
436
|
-
| icon | `object` | - | 圖標 |
|
|
437
|
-
| link | `boolean` | `false` | 是否為文字按鈕 |
|
|
438
|
-
| isFill | `boolean` | `false` | 是否為填充樣式 |
|
|
439
|
-
|
|
440
|
-
### BaseDialog Props
|
|
544
|
+
### TransferDialog
|
|
441
545
|
|
|
442
|
-
|
|
443
|
-
|------|------|--------|------|
|
|
444
|
-
| modelValue | `boolean` | - | 對話框顯示狀態 |
|
|
445
|
-
| title | `string` | - | 對話框標題 |
|
|
446
|
-
| subTitle | `string` | - | 副標題 |
|
|
447
|
-
| customWidth | `string` | - | 自定義寬度 |
|
|
448
|
-
| isWaring | `boolean` | `false` | 是否為警告對話框 |
|
|
449
|
-
| isPrimary | `boolean` | `false` | 是否為主要對話框 |
|
|
450
|
-
| bodyLoading | `boolean` | `false` | 內容區域加載狀態 |
|
|
451
|
-
| submitLoading | `boolean` | `false` | 提交按鈕加載狀態 |
|
|
546
|
+
用於表格列配置的穿梭框組件。
|
|
452
547
|
|
|
453
|
-
|
|
548
|
+
#### Props
|
|
454
549
|
|
|
455
550
|
| 屬性 | 類型 | 默認值 | 說明 |
|
|
456
551
|
|------|------|--------|------|
|
|
457
|
-
| modelValue | `boolean` | - | 對話框顯示狀態 |
|
|
458
|
-
| columnsValue | `TableColumn<T>[]` | `[]` | 表格列配置 |
|
|
459
|
-
| transferTitle | `string` | - | 對話框標題 |
|
|
552
|
+
| `modelValue` | `boolean` | - | 對話框顯示狀態 |
|
|
553
|
+
| `columnsValue` | `TableColumn<T>[]` | `[]` | 表格列配置 |
|
|
554
|
+
| `transferTitle` | `string` | - | 對話框標題 |
|
|
460
555
|
|
|
461
|
-
|
|
556
|
+
#### Events
|
|
462
557
|
|
|
463
558
|
| 事件名 | 參數 | 說明 |
|
|
464
559
|
|--------|------|------|
|
|
465
|
-
| update:modelValue | `value: boolean` | 對話框顯示狀態變更 |
|
|
466
|
-
| update:submit | `columns: TableColumn<T>[]` |
|
|
560
|
+
| `update:modelValue` | `value: boolean` | 對話框顯示狀態變更 |
|
|
561
|
+
| `update:submit` | `columns: TableColumn<T>[]` | 提交列配置時觸發 |
|
|
467
562
|
|
|
468
|
-
|
|
563
|
+
#### Slots
|
|
469
564
|
|
|
470
565
|
| 插槽名 | 參數 | 說明 |
|
|
471
566
|
|--------|------|------|
|
|
472
|
-
| list-container | `
|
|
567
|
+
| `list-container` | `ListContainerSlotProps` | 自定義列表容器 |
|
|
473
568
|
|
|
474
|
-
|
|
569
|
+
#### 類型定義
|
|
475
570
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
571
|
+
```typescript
|
|
572
|
+
interface ListContainerSlotProps<T = any> {
|
|
573
|
+
columns: TableColumn<T>[]
|
|
574
|
+
clickItemProp: string
|
|
575
|
+
handleItemEvents: {
|
|
576
|
+
toTop: (index: number) => void
|
|
577
|
+
toBottom: (index: number) => void
|
|
578
|
+
toPre: (index: number) => void
|
|
579
|
+
toNext: (index: number) => void
|
|
580
|
+
}
|
|
581
|
+
handleMousedown: (prop: string) => void
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
---
|
|
482
586
|
|
|
483
|
-
###
|
|
587
|
+
### 通用類型定義
|
|
588
|
+
|
|
589
|
+
#### TableColumn
|
|
484
590
|
|
|
485
591
|
```typescript
|
|
486
592
|
interface TableColumn<T = Record<string, unknown>> {
|
|
487
|
-
prop?: string
|
|
593
|
+
prop?: keyof T | string
|
|
488
594
|
label: string
|
|
489
595
|
width?: number | string
|
|
490
596
|
type?: 'selection' | 'index' | 'expand'
|
|
@@ -499,133 +605,213 @@ interface TableColumn<T = Record<string, unknown>> {
|
|
|
499
605
|
}
|
|
500
606
|
```
|
|
501
607
|
|
|
502
|
-
|
|
608
|
+
#### SortChangValue
|
|
503
609
|
|
|
504
|
-
|
|
610
|
+
```typescript
|
|
611
|
+
interface SortChangValue<T = any> {
|
|
612
|
+
column: TableColumn<T>
|
|
613
|
+
prop: keyof T | string
|
|
614
|
+
order: 'ascending' | 'descending' | null
|
|
615
|
+
}
|
|
616
|
+
```
|
|
505
617
|
|
|
506
|
-
|
|
618
|
+
## 🎨 樣式系統
|
|
507
619
|
|
|
508
|
-
|
|
509
|
-
<template>
|
|
510
|
-
<TransferDialog
|
|
511
|
-
v-model="showDialog"
|
|
512
|
-
:columns-value="columns"
|
|
513
|
-
transfer-title="配置表格列"
|
|
514
|
-
@update:submit="handleSubmit"
|
|
515
|
-
/>
|
|
516
|
-
</template>
|
|
620
|
+
### 樣式導入方式
|
|
517
621
|
|
|
518
|
-
|
|
519
|
-
import { TransferDialog } from 'rayyy-vue-table-components'
|
|
622
|
+
本組件庫提供多種靈活的樣式導入方式,您可以根據項目需求選擇:
|
|
520
623
|
|
|
521
|
-
|
|
522
|
-
const columns = ref<TableColumn<User>[]>([
|
|
523
|
-
{ prop: 'id', label: 'ID', checkActive: true },
|
|
524
|
-
{ prop: 'name', label: '姓名', checkActive: true },
|
|
525
|
-
{ prop: 'email', label: '郵箱', checkActive: false }
|
|
526
|
-
])
|
|
624
|
+
#### 1. 完整樣式導入(推薦)
|
|
527
625
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
626
|
+
適用於大多數項目,一次性導入所有樣式:
|
|
627
|
+
|
|
628
|
+
```typescript
|
|
629
|
+
// main.ts
|
|
630
|
+
import 'element-plus/dist/index.css'
|
|
631
|
+
import 'rayyy-vue-table-components/styles'
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
或在 CSS/SCSS 文件中:
|
|
635
|
+
|
|
636
|
+
```scss
|
|
637
|
+
// styles.scss
|
|
638
|
+
@import 'element-plus/dist/index.css';
|
|
639
|
+
@import 'rayyy-vue-table-components/styles';
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
#### 2. 模組化導入
|
|
643
|
+
|
|
644
|
+
按需導入特定模組的樣式:
|
|
645
|
+
|
|
646
|
+
```scss
|
|
647
|
+
// 只導入表格相關樣式
|
|
648
|
+
@import 'rayyy-vue-table-components/styles/table';
|
|
649
|
+
|
|
650
|
+
// 只導入對話框相關樣式
|
|
651
|
+
@import 'rayyy-vue-table-components/styles/dialog';
|
|
652
|
+
|
|
653
|
+
// 只導入組件樣式
|
|
654
|
+
@import 'rayyy-vue-table-components/styles/components';
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
#### 3. Element Plus 主題自定義
|
|
658
|
+
|
|
659
|
+
如果您需要自定義 Element Plus 主題:
|
|
660
|
+
|
|
661
|
+
```scss
|
|
662
|
+
// styles.scss
|
|
663
|
+
@import 'element-plus/dist/index.css';
|
|
664
|
+
@import 'rayyy-vue-table-components/styles/element';
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### TypeScript 樣式工具
|
|
668
|
+
|
|
669
|
+
提供類型安全的樣式工具函數:
|
|
670
|
+
|
|
671
|
+
#### 預定義樣式
|
|
672
|
+
|
|
673
|
+
```typescript
|
|
674
|
+
import { tableStyles, componentStyles } from 'rayyy-vue-table-components/utils/styles'
|
|
675
|
+
|
|
676
|
+
// 表格樣式常量
|
|
677
|
+
const styles = {
|
|
678
|
+
cell: tableStyles.cell, // 'p-0 h-10'
|
|
679
|
+
header: tableStyles.header, // 'bg-primary-15 font-bold text-text text-sm leading-4'
|
|
680
|
+
content: tableStyles.content, // 'truncate'
|
|
681
|
+
dismissed: tableStyles.dismissed, // 'bg-blue-20'
|
|
682
|
+
footer: tableStyles.footer, // 'font-bold'
|
|
683
|
+
blueText: tableStyles.blueText, // 'text-blue-10'
|
|
684
|
+
redText: tableStyles.redText, // 'text-redText'
|
|
531
685
|
}
|
|
532
|
-
|
|
686
|
+
|
|
687
|
+
// 組件樣式常量
|
|
688
|
+
const componentClasses = {
|
|
689
|
+
sortTableContainer: componentStyles.sortTableContainer,
|
|
690
|
+
filterBtn: componentStyles.filterBtn,
|
|
691
|
+
transferActiveBg: componentStyles.transferActiveBg,
|
|
692
|
+
baseDialogTitle: componentStyles.baseDialogTitle,
|
|
693
|
+
cursorGrab: componentStyles.cursorGrab,
|
|
694
|
+
}
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
#### 動態樣式生成器
|
|
698
|
+
|
|
699
|
+
```typescript
|
|
700
|
+
import { createTableCellClass, createTextClass } from 'rayyy-vue-table-components/utils/styles'
|
|
701
|
+
|
|
702
|
+
// 動態生成表格單元格樣式
|
|
703
|
+
const cellClass = createTableCellClass({
|
|
704
|
+
isDismissed: true, // 是否被駁回
|
|
705
|
+
isHeader: false // 是否為標題行
|
|
706
|
+
})
|
|
707
|
+
// 輸出: 'p-0 h-10 bg-blue-20'
|
|
708
|
+
|
|
709
|
+
// 動態生成文字顏色樣式
|
|
710
|
+
const textClass = createTextClass('blue') // 'blue' | 'red' | 'normal'
|
|
711
|
+
// 輸出: 'text-blue-10'
|
|
533
712
|
```
|
|
534
713
|
|
|
535
|
-
|
|
714
|
+
#### Element Plus 表格配置
|
|
715
|
+
|
|
716
|
+
```typescript
|
|
717
|
+
import { dataTableConfig } from 'rayyy-vue-table-components/utils/styles'
|
|
718
|
+
|
|
719
|
+
// 在 Element Plus 原生表格中使用
|
|
720
|
+
<el-table
|
|
721
|
+
:cell-class-name="dataTableConfig.cellClass"
|
|
722
|
+
:header-cell-class-name="dataTableConfig.headerClass"
|
|
723
|
+
:data="tableData"
|
|
724
|
+
>
|
|
725
|
+
<el-table-column prop="name" label="姓名" />
|
|
726
|
+
</el-table>
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
### 自定義主題
|
|
730
|
+
|
|
731
|
+
您可以通過 CSS 變量來自定義組件主題:
|
|
732
|
+
|
|
733
|
+
```scss
|
|
734
|
+
:root {
|
|
735
|
+
// 主色調
|
|
736
|
+
--primary-color: #409eff;
|
|
737
|
+
--primary-light: #ecf5ff;
|
|
738
|
+
|
|
739
|
+
// 文字顏色
|
|
740
|
+
--text-primary: #303133;
|
|
741
|
+
--text-regular: #606266;
|
|
742
|
+
--text-secondary: #909399;
|
|
743
|
+
|
|
744
|
+
// 邊框顏色
|
|
745
|
+
--border-color: #dcdfe6;
|
|
746
|
+
--border-light: #e4e7ed;
|
|
747
|
+
|
|
748
|
+
// 背景顏色
|
|
749
|
+
--bg-color: #ffffff;
|
|
750
|
+
--bg-light: #f5f7fa;
|
|
751
|
+
}
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
### Tailwind CSS 集成
|
|
755
|
+
|
|
756
|
+
如果您的項目使用 Tailwind CSS,可以直接使用工具類:
|
|
536
757
|
|
|
537
758
|
```vue
|
|
538
759
|
<template>
|
|
539
|
-
<
|
|
540
|
-
|
|
541
|
-
:columns
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
<template #list-container="{ columns, clickItemProp, handleItemEvents, handleMousedown }">
|
|
546
|
-
<!-- 使用 vuedraggable 實現拖拽 -->
|
|
547
|
-
<draggable :list="columns" item-key="prop" delay="200">
|
|
548
|
-
<template #item="{ element, index }">
|
|
549
|
-
<transfer-item
|
|
550
|
-
:columns-value="element"
|
|
551
|
-
:columns-index="index"
|
|
552
|
-
:columns-len="columns.length"
|
|
553
|
-
:class="{
|
|
554
|
-
'transfer-active-bg': element.checkActive,
|
|
555
|
-
'transfer-active-border': clickItemProp === element.prop,
|
|
556
|
-
}"
|
|
557
|
-
@mousedown="handleMousedown(element.prop || '')"
|
|
558
|
-
@update:toTop="handleItemEvents.toTop(index)"
|
|
559
|
-
@update:toBottom="handleItemEvents.toBottom(index)"
|
|
560
|
-
@update:toPre="handleItemEvents.toPre(index)"
|
|
561
|
-
@update:toNext="handleItemEvents.toNext(index)"
|
|
562
|
-
/>
|
|
563
|
-
</template>
|
|
564
|
-
</draggable>
|
|
565
|
-
</template>
|
|
566
|
-
</TransferDialog>
|
|
760
|
+
<BaseTable
|
|
761
|
+
:data="tableData"
|
|
762
|
+
:columns="columns"
|
|
763
|
+
class="shadow-lg rounded-lg"
|
|
764
|
+
:base-table-row-class-name="getRowClass"
|
|
765
|
+
/>
|
|
567
766
|
</template>
|
|
568
767
|
|
|
569
768
|
<script setup lang="ts">
|
|
570
|
-
|
|
571
|
-
|
|
769
|
+
const getRowClass = ({ row, rowIndex }: any) => {
|
|
770
|
+
return [
|
|
771
|
+
'hover:bg-gray-50',
|
|
772
|
+
'transition-colors',
|
|
773
|
+
rowIndex % 2 === 0 ? 'bg-white' : 'bg-gray-25'
|
|
774
|
+
].join(' ')
|
|
775
|
+
}
|
|
572
776
|
</script>
|
|
573
777
|
```
|
|
574
778
|
|
|
575
|
-
###
|
|
779
|
+
### 響應式設計
|
|
780
|
+
|
|
781
|
+
組件內建響應式支援,您也可以使用響應式工具類:
|
|
576
782
|
|
|
577
783
|
```vue
|
|
578
784
|
<template>
|
|
579
|
-
<
|
|
580
|
-
|
|
581
|
-
:columns
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
>
|
|
585
|
-
<template #list-container="{ columns, clickItemProp, handleItemEvents, handleMousedown }">
|
|
586
|
-
<!-- 使用靜態列表 -->
|
|
587
|
-
<div class="transfer-list">
|
|
588
|
-
<template v-for="(element, index) in columns" :key="element.prop">
|
|
589
|
-
<transfer-item
|
|
590
|
-
:columns-value="element"
|
|
591
|
-
:columns-index="index"
|
|
592
|
-
:columns-len="columns.length"
|
|
593
|
-
:class="{
|
|
594
|
-
'transfer-active-bg': element.checkActive,
|
|
595
|
-
'transfer-active-border': clickItemProp === element.prop,
|
|
596
|
-
}"
|
|
597
|
-
@mousedown="handleMousedown(element.prop || '')"
|
|
598
|
-
@update:toTop="handleItemEvents.toTop(index)"
|
|
599
|
-
@update:toBottom="handleItemEvents.toBottom(index)"
|
|
600
|
-
@update:toPre="handleItemEvents.toPre(index)"
|
|
601
|
-
@update:toNext="handleItemEvents.toNext(index)"
|
|
602
|
-
/>
|
|
603
|
-
</template>
|
|
604
|
-
</div>
|
|
605
|
-
</template>
|
|
606
|
-
</TransferDialog>
|
|
785
|
+
<BaseTable
|
|
786
|
+
:data="tableData"
|
|
787
|
+
:columns="columns"
|
|
788
|
+
class="w-full sm:w-auto lg:w-full"
|
|
789
|
+
/>
|
|
607
790
|
</template>
|
|
608
791
|
```
|
|
609
792
|
|
|
610
|
-
|
|
793
|
+
## 🛠️ 開發指南
|
|
794
|
+
|
|
795
|
+
### 環境要求
|
|
611
796
|
|
|
612
|
-
-
|
|
613
|
-
-
|
|
614
|
-
-
|
|
615
|
-
- ✅ **搜尋過濾**:按列名快速定位
|
|
616
|
-
- ✅ **批量選擇**:全選/取消全選功能
|
|
617
|
-
- ✅ **狀態保持**:記住列的顯示/隱藏狀態
|
|
797
|
+
- Node.js 16.0+
|
|
798
|
+
- Vue 3.0+
|
|
799
|
+
- Element Plus 2.0+
|
|
618
800
|
|
|
619
|
-
|
|
801
|
+
### 本地開發
|
|
620
802
|
|
|
621
803
|
```bash
|
|
804
|
+
# 克隆項目
|
|
805
|
+
git clone https://github.com/your-username/vue-table-components.git
|
|
806
|
+
cd vue-table-components
|
|
807
|
+
|
|
622
808
|
# 安裝依賴
|
|
623
809
|
npm install
|
|
624
810
|
|
|
625
811
|
# 開發模式
|
|
626
812
|
npm run dev
|
|
627
813
|
|
|
628
|
-
#
|
|
814
|
+
# 構建庫
|
|
629
815
|
npm run build-lib
|
|
630
816
|
|
|
631
817
|
# 運行測試
|
|
@@ -635,36 +821,61 @@ npm run test:unit
|
|
|
635
821
|
npm run lint
|
|
636
822
|
```
|
|
637
823
|
|
|
638
|
-
###
|
|
824
|
+
### 項目結構
|
|
825
|
+
|
|
826
|
+
```
|
|
827
|
+
src/
|
|
828
|
+
├── components/ # 組件源碼
|
|
829
|
+
│ ├── BaseTable.vue # 基礎表格組件
|
|
830
|
+
│ ├── BaseBtn.vue # 按鈕組件
|
|
831
|
+
│ ├── BaseDialog.vue # 對話框組件
|
|
832
|
+
│ └── transfer/ # 穿梭框組件
|
|
833
|
+
├── assets/styles/ # 樣式文件
|
|
834
|
+
│ ├── tailwind.scss # 主樣式入口
|
|
835
|
+
│ ├── _table.scss # 表格樣式
|
|
836
|
+
│ ├── _dialog.scss # 對話框樣式
|
|
837
|
+
│ └── element/ # Element Plus 主題
|
|
838
|
+
├── types/ # 類型定義
|
|
839
|
+
├── utils/ # 工具函數
|
|
840
|
+
└── index.ts # 主入口文件
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
### 貢獻指南
|
|
639
844
|
|
|
640
|
-
|
|
845
|
+
歡迎貢獻代碼!請遵循以下步驟:
|
|
641
846
|
|
|
642
|
-
1.
|
|
643
|
-
2.
|
|
644
|
-
3.
|
|
645
|
-
4.
|
|
847
|
+
1. Fork 本項目
|
|
848
|
+
2. 創建功能分支:`git checkout -b feature/amazing-feature`
|
|
849
|
+
3. 提交更改:`git commit -m 'Add some amazing feature'`
|
|
850
|
+
4. 推送分支:`git push origin feature/amazing-feature`
|
|
851
|
+
5. 提交 Pull Request
|
|
646
852
|
|
|
647
|
-
|
|
853
|
+
## 🤝 社區與支持
|
|
648
854
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
855
|
+
### 問題反饋
|
|
856
|
+
|
|
857
|
+
如果您遇到問題或有功能建議,請通過以下方式聯繫我們:
|
|
858
|
+
|
|
859
|
+
- [GitHub Issues](https://github.com/your-username/vue-table-components/issues)
|
|
860
|
+
- [討論區](https://github.com/your-username/vue-table-components/discussions)
|
|
861
|
+
|
|
862
|
+
### 版本更新
|
|
863
|
+
|
|
864
|
+
查看 [CHANGELOG.md](./CHANGELOG.md) 了解詳細的版本更新記錄。
|
|
865
|
+
|
|
866
|
+
### 相關鏈接
|
|
867
|
+
|
|
868
|
+
- [Vue 3 官方文檔](https://vuejs.org/)
|
|
869
|
+
- [Element Plus 官方文檔](https://element-plus.org/)
|
|
870
|
+
- [TypeScript 官方文檔](https://www.typescriptlang.org/)
|
|
871
|
+
- [Tailwind CSS 官方文檔](https://tailwindcss.com/)
|
|
661
872
|
|
|
662
|
-
|
|
873
|
+
## 📄 許可證
|
|
663
874
|
|
|
664
|
-
|
|
665
|
-
2. **TypeScript 工具**:在 `tableStyles.ts` 中添加新的工具函數
|
|
666
|
-
3. **導出配置**:在 `package.json` 的 `exports` 中添加新的導出路徑
|
|
875
|
+
本項目基於 [MIT License](./LICENSE) 開源協議。
|
|
667
876
|
|
|
668
|
-
|
|
877
|
+
---
|
|
669
878
|
|
|
670
|
-
|
|
879
|
+
<p align="center">
|
|
880
|
+
Made with ❤️ by the Vue Table Components Team
|
|
881
|
+
</p>
|