stk-table-vue 0.0.2 → 0.2.0

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.
@@ -8,6 +8,7 @@
8
8
  .stk-table {
9
9
  /* contain: strict;*/
10
10
  --row-height: 28px;
11
+ --header-row-height: var(--row-height);
11
12
  --cell-padding-x: 8px;
12
13
  --resize-handle-width: 4px;
13
14
  --border-color: #e8e8f4;
@@ -32,10 +33,16 @@
32
33
  /** 列宽拖动指示器颜色 */
33
34
  --col-resize-indicator-color: #87879c;
34
35
 
36
+ /** 固定列阴影颜色 */
37
+ --fixed-col-shadow-color-from: rgba(0, 0, 0, 0.1);
38
+ --fixed-col-shadow-color-to: rgba(0, 0, 0, 0);
39
+
35
40
  position: relative;
36
41
  overflow: auto;
37
42
  display: flex;
38
43
  flex-direction: column;
44
+ /* border-left: 此方案用于减少cell 中border-left 的css选择。同时利于多级表头border-left问题。利于横向滚动border-left*/
45
+ border-left: 1px solid var(--border-color);
39
46
 
40
47
  /**深色模式 */
41
48
  &.dark {
@@ -58,20 +65,14 @@
58
65
 
59
66
  --col-resize-indicator-color: #5d6064;
60
67
 
68
+ --fixed-col-shadow-color-from: rgba(135, 135, 156, 0.1);
69
+ --fixed-col-shadow-color-to: rgba(135, 135, 156, 0);
70
+
61
71
  /* background-color: var(--table-bgc); */
62
72
  /* ⭐这里加background-color会导致表格出滚动白屏*/
63
73
  color: #d1d1e0;
64
74
  }
65
75
 
66
- /*.stk-table-fixed-left-col-box-shadow {
67
- position: sticky;
68
- left: 0;
69
- top: 0;
70
- height: 100%;
71
- box-shadow: 0 0 10px;
72
- z-index: 1;
73
- pointer-events: none;
74
- }*/
75
76
  &.headless {
76
77
  border-top: 1px solid var(--border-color);
77
78
  }
@@ -101,83 +102,50 @@
101
102
  }
102
103
 
103
104
  &.border {
104
- .stk-table-main {
105
-
106
- th,
107
- td {
108
- background-image: var(--bg-border-right), var(--bg-border-bottom);
109
- }
110
105
 
111
- thead {
112
- tr {
113
- &:first-child th {
114
- background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
106
+ th,
107
+ td {
108
+ background-image: var(--bg-border-right), var(--bg-border-bottom);
109
+ }
115
110
 
116
- &:first-child {
117
- background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
118
- }
119
- }
111
+ thead {
112
+ tr {
113
+ &:first-child th {
114
+ background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
120
115
 
121
- th {
122
- &:first-child {
123
- background-image: var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
124
- }
125
- }
126
116
  }
127
- }
128
117
 
129
- tbody {
130
- td {
131
- &:first-child {
132
- background-image: var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
133
- }
134
- }
135
118
  }
136
119
  }
137
120
 
121
+
138
122
  &.virtual-x {
139
- .stk-table-main {
140
- .virtual-x-left {
141
- background: none;
142
- pointer-events: none;;
143
- }
144
- .virtual-x-right {
145
- padding: 0;
146
- background: none;
147
- pointer-events: none;;
148
- }
149
- thead tr:first-child .virtual-x-left+th {
150
- /* 横向虚拟滚动时,左侧第一个单元格加上border-left*/
151
- background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
152
- }
123
+ .virtual-x-left {
124
+ background: none;
125
+ pointer-events: none;
126
+ }
153
127
 
154
- tr .virtual-x-left+th {
155
- background-image: var(--bg-border-right), var(--bg-border-bottom), var(--bg-border-left);
156
- }
128
+ .virtual-x-right {
129
+ padding: 0;
130
+ background: none;
131
+ pointer-events: none;
157
132
  }
133
+
158
134
  }
159
135
  }
160
136
 
161
137
  &.border-body-v {
162
- .stk-table-main {
163
- tbody {
164
- --bg-border-bottom: linear-gradient(transparent, transparent);
165
- }
138
+ tbody {
139
+ --bg-border-bottom: linear-gradient(transparent, transparent);
166
140
  }
167
141
  }
168
142
 
169
143
  &.stripe {
170
- .stk-table-main {
171
144
 
172
- /* 斑马纹*/
173
- tbody {
174
- tr:nth-child(odd) {
175
- background-color: var(--stripe-bgc);
176
- }
177
-
178
- tr:hover {
179
- background-color: var(--tr-hover-bgc);
180
- }
145
+ /* 斑马纹*/
146
+ tbody {
147
+ tr:nth-child(odd) {
148
+ background-color: var(--stripe-bgc);
181
149
  }
182
150
  }
183
151
  }
@@ -208,7 +176,6 @@
208
176
  th,
209
177
  td {
210
178
  z-index: 1;
211
- height: var(--row-height);
212
179
  font-size: 14px;
213
180
  box-sizing: border-box;
214
181
  padding: 0 var(--cell-padding-x);
@@ -216,109 +183,161 @@
216
183
 
217
184
  th {
218
185
  color: var(--th-color);
186
+ background-color: var(--th-bgc);
187
+
188
+ &.sortable {
189
+ cursor: pointer;
190
+ }
191
+
192
+ &.text-overflow {
193
+ .table-header-cell-wrapper {
194
+ white-space: nowrap;
195
+ overflow: hidden;
196
+ }
197
+
198
+ .table-header-title {
199
+ text-overflow: ellipsis;
200
+ overflow: hidden;
201
+ }
202
+ }
203
+ }
204
+
205
+ td {
206
+ &.fixed-cell {
207
+ background-color: inherit;
208
+ /* 防止横向滚动后透明*/
209
+ }
210
+
211
+ &.highlight-cell {
212
+ animation: stkTableDim 2s linear;
213
+ }
214
+
215
+ &.text-overflow {
216
+ .table-cell-wrapper {
217
+ white-space: nowrap;
218
+ overflow: hidden;
219
+ text-overflow: ellipsis;
220
+ }
221
+ }
222
+ }
223
+
224
+ /*固定列阴影-左*/
225
+ .fixed-cell--left {
226
+ --shadow-rotate: 90deg;
227
+
228
+ &.fixed-cell--shadow::after {
229
+ right: -10px;
230
+ }
231
+ }
232
+
233
+ /*固定列阴影-右*/
234
+ .fixed-cell--right {
235
+ --shadow-rotate: -90deg;
236
+
237
+ &.fixed-cell--shadow::after {
238
+ left: -10px;
239
+ }
240
+ }
241
+
242
+ /*固定列阴影*/
243
+ .fixed-cell--shadow::after {
244
+ content: '';
245
+ width: 10px;
246
+ height: 100%;
247
+ top: 0px;
248
+ position: absolute;
249
+ pointer-events: none;
250
+ background-image: linear-gradient(var(--shadow-rotate), var(--fixed-col-shadow-color-from), var(--fixed-col-shadow-color-to)),
219
251
  }
220
252
 
221
253
  thead {
222
254
  tr {
255
+ height: var(--header-row-height);
256
+
223
257
  &:first-child th {
224
258
  position: sticky;
225
259
  top: 0;
226
260
  }
261
+ }
262
+ }
227
263
 
228
- th {
229
- background-color: var(--th-bgc);
264
+ th {
230
265
 
231
- &.sortable {
232
- cursor: pointer;
233
- }
266
+ &:not(.sorter-desc):not(.sorter-asc):hover .table-header-sorter {
267
+ .arrow-up {
268
+ fill: var(--sort-arrow-hover-color);
269
+ }
234
270
 
235
- &.text-overflow {
236
- .table-header-cell-wrapper {
237
- white-space: nowrap;
238
- overflow: hidden;
271
+ .arrow-down {
272
+ fill: var(--sort-arrow-hover-color);
273
+ }
274
+ }
239
275
 
240
- .table-header-title {
241
- text-overflow: ellipsis;
242
- overflow: hidden;
243
- }
244
- }
245
- }
276
+ &.sorter-desc .table-header-sorter {
277
+ display: initial;
246
278
 
247
- &:not(.sorter-desc):not(.sorter-asc):hover .table-header-cell-wrapper .table-header-sorter {
248
- #arrow-up {
249
- fill: var(--sort-arrow-hover-color);
250
- }
279
+ .arrow-up {
280
+ fill: var(--sort-arrow-active-sub-color);
281
+ }
251
282
 
252
- #arrow-down {
253
- fill: var(--sort-arrow-hover-color);
254
- }
255
- }
283
+ .arrow-down {
284
+ fill: var(--sort-arrow-active-color);
285
+ }
286
+ }
256
287
 
257
- &.sorter-desc .table-header-cell-wrapper .table-header-sorter {
258
- display: initial;
288
+ &.sorter-asc .table-header-sorter {
289
+ display: initial;
259
290
 
260
- #arrow-up {
261
- fill: var(--sort-arrow-active-sub-color);
262
- }
291
+ .arrow-up {
292
+ fill: var(--sort-arrow-active-color);
293
+ }
263
294
 
264
- #arrow-down {
265
- fill: var(--sort-arrow-active-color);
266
- }
267
- }
295
+ .arrow-down {
296
+ fill: var(--sort-arrow-active-sub-color);
297
+ }
298
+ }
268
299
 
269
- &.sorter-asc .table-header-cell-wrapper .table-header-sorter {
270
- display: initial;
271
300
 
272
- #arrow-up {
273
- fill: var(--sort-arrow-active-color);
274
- }
301
+ }
275
302
 
276
- #arrow-down {
277
- fill: var(--sort-arrow-active-sub-color);
278
- }
279
- }
303
+ .table-header-cell-wrapper {
304
+ max-width: 100%;
305
+ /*最大宽度不超过列宽*/
306
+ display: inline-flex;
307
+ align-items: center;
308
+ }
280
309
 
281
- .table-header-cell-wrapper {
282
- max-width: 100%;
283
- /*最大宽度不超过列宽*/
284
- display: inline-flex;
285
- align-items: center;
286
-
287
- .table-header-title {
288
- overflow: hidden;
289
- align-self: flex-start;
290
- }
291
-
292
- .table-header-sorter {
293
- flex-shrink: 0;
294
- margin-left: 4px;
295
- width: 16px;
296
- height: 16px;
297
- display: none;
298
-
299
- #arrow-up,
300
- #arrow-down {
301
- fill: var(--sort-arrow-color);
302
- }
303
- }
304
-
305
- .table-header-resizer {
306
- position: absolute;
307
- top: 0;
308
- bottom: 0;
309
- cursor: col-resize;
310
- width: var(--resize-handle-width);
311
-
312
- &.left {
313
- left: 0;
314
- }
315
-
316
- &.right {
317
- right: 0;
318
- }
319
- }
320
- }
321
- }
310
+ .table-header-title {
311
+ overflow: hidden;
312
+ align-self: flex-start;
313
+ }
314
+
315
+ .table-header-sorter {
316
+ flex-shrink: 0;
317
+ margin-left: 4px;
318
+ width: 16px;
319
+ height: 16px;
320
+ display: none;
321
+
322
+ .arrow-up,
323
+ .arrow-down {
324
+ fill: var(--sort-arrow-color);
325
+ }
326
+ }
327
+
328
+ .table-header-resizer {
329
+ position: absolute;
330
+ top: 0;
331
+ bottom: 0;
332
+ cursor: col-resize;
333
+ width: var(--resize-handle-width);
334
+
335
+ &.left {
336
+ left: 0;
337
+ }
338
+
339
+ &.right {
340
+ right: 0;
322
341
  }
323
342
  }
324
343
 
@@ -326,8 +345,9 @@
326
345
 
327
346
  tr {
328
347
  background-color: var(--td-bgc);
329
- /* td inherit tr bgc*/
348
+ height: var(--row-height);
330
349
 
350
+ /* td inherit tr bgc*/
331
351
  &.highlight-row {
332
352
  animation: stkTableDim 2s linear;
333
353
  }
@@ -344,65 +364,9 @@
344
364
  &.active {
345
365
  background-color: var(--tr-active-bgc);
346
366
  }
347
-
348
- td {
349
- &.fixed-cell {
350
- background-color: inherit;
351
- /* 防止横向滚动后透明*/
352
- }
353
-
354
- &.highlight-cell {
355
- animation: stkTableDim 2s linear;
356
- }
357
-
358
- &.text-overflow {
359
- .table-cell-wrapper {
360
- white-space: nowrap;
361
- overflow: hidden;
362
- text-overflow: ellipsis;
363
- }
364
- }
365
-
366
- /* &.perch-td {
367
- padding: 0;
368
- height: 0;
369
- &.top {
370
- background-image: repeating-linear-gradient(
371
- 180deg,
372
- transparent 0,
373
- transparent var(--row-height),
374
- var(--border-color) var(--row-height),
375
- var(--border-color) calc(var(--row-height) + 1px)
376
- ),
377
- var(--bg-border-right);
378
- }
379
- &.bottom {
380
- background-image: repeating-linear-gradient(
381
- 0deg,
382
- transparent 0,
383
- transparent var(--row-height),
384
- var(--border-color) var(--row-height),
385
- var(--border-color) calc(var(--row-height) + 1px)
386
- ),
387
- var(--bg-border-right);
388
- }
389
- }*/
390
- }
391
367
  }
392
368
 
393
369
  }
394
-
395
- /* tr .fixed-cell--left{
396
- border: 1px solid red;
397
- &::after{
398
- content: '';
399
- width: 20px;
400
- position: absolute;
401
- right: -20px;
402
- top: 0px;
403
- background: rgba(255,255,255,0.5);
404
- }
405
- } */
406
370
  }
407
371
 
408
372
  .stk-table-no-data {
@@ -412,7 +376,6 @@
412
376
  font-size: 14px;
413
377
  position: sticky;
414
378
  left: 0px;
415
- border-left: var(--border-width) solid var(--border-color);
416
379
  border-right: var(--border-width) solid var(--border-color);
417
380
  border-bottom: var(--border-width) solid var(--border-color);
418
381
  display: flex;
@@ -427,47 +390,38 @@
427
390
 
428
391
  /**虚拟滚动模式 */
429
392
  &.virtual {
430
- .stk-table-main {
431
- thead {
432
- tr {
433
- th {
434
-
435
- /* 为不影响布局,表头行高要定死*/
436
- .table-header-cell-wrapper {
437
- overflow: hidden;
438
- max-height: var(--row-height);
439
- }
440
- }
441
- }
442
- }
443
393
 
444
- tbody {
445
- position: relative;
394
+ /* 为不影响布局,表头行高要定死*/
395
+ .table-header-cell-wrapper {
396
+ overflow: hidden;
397
+ max-height: var(--header-row-height);
398
+ }
446
399
 
447
- tr {
448
- &.padding-top-tr td {
449
- height: 0;
450
- }
400
+ tbody {
401
+ position: relative;
451
402
 
452
- td {
453
- height: var(--row-height);
454
- line-height: 1;
403
+ tr {
455
404
 
456
- .table-cell-wrapper {
457
- max-height: var(--row-height);
458
- overflow: hidden;
459
- }
405
+ td {
406
+ height: var(--row-height);
407
+ line-height: 1;
408
+
409
+ .table-cell-wrapper {
410
+ max-height: var(--row-height);
411
+ overflow: hidden;
460
412
  }
461
413
  }
462
414
  }
463
415
  }
416
+
417
+ .padding-top-tr td {
418
+ height: 0;
419
+ }
464
420
  }
465
421
 
466
422
  &.virtual-x {
467
- .stk-table-main {
468
- .virtual-x-left {
469
- padding: 0;
470
- }
423
+ .virtual-x-left {
424
+ padding: 0;
471
425
  }
472
426
  }
473
427
  }
@@ -38,12 +38,25 @@ export type StkTableColumn<T extends Record<string, any>> = {
38
38
  fixed?: 'left' | 'right' | null;
39
39
  /** private */ rowSpan?: number;
40
40
  /** private */ colSpan?: number;
41
- /**自定义 td 渲染内容 */
41
+ /**
42
+ * 自定义 td 渲染内容。
43
+ *
44
+ * 组件prop入参:
45
+ * - props.row 一行的记录。
46
+ * - props.col 列配置
47
+ */
42
48
  customCell?: Component | VNode | CustomCellFunc<T>;
43
- /** 自定义 th 渲染内容 */
49
+ /**
50
+ * 自定义 th 渲染内容
51
+ *
52
+ * 组件prop入参:
53
+ * - props.col 列配置
54
+ */
44
55
  customHeaderCell?: Component | VNode | CustomHeaderCellFunc<T>;
45
56
  /** 二级表头 */
46
57
  children?: StkTableColumn<T>[];
58
+ /** 父节点引用 */
59
+ __PARENT__?: StkTableColumn<T> | null;
47
60
  };
48
61
 
49
62
  export type SortOption = Pick<StkTableColumn<any>, 'sorter' | 'dataIndex' | 'sortField' | 'sortType'>;
@@ -0,0 +1,91 @@
1
+ import { ref, Ref } from 'vue';
2
+ import { StkTableColumn } from './types';
3
+
4
+ type Params<T extends Record<string, any>> = {
5
+ props: any;
6
+ tableHeaderLast: Ref<StkTableColumn<T>[]>;
7
+ tableContainer: Ref<HTMLDivElement | undefined>;
8
+ };
9
+
10
+ /**
11
+ * 固定列处理
12
+ * @returns
13
+ */
14
+ export function useFixedCol<DT extends Record<string, any>>({ props, tableHeaderLast, tableContainer }: Params<DT>) {
15
+ /** 固定列阴影 */
16
+ const fixedShadow = ref<{
17
+ /** 是否展示左侧固定列阴影 */
18
+ showL: boolean;
19
+ /** 是否展示右侧固定列阴影 */
20
+ showR: boolean;
21
+ }>({
22
+ showL: false,
23
+ showR: false,
24
+ });
25
+ /** 保存需要出现阴影的列 */
26
+ let fixedShadowCols: StkTableColumn<DT>[] = [];
27
+
28
+ /** 处理固定列阴影 */
29
+ function dealFixedColShadow() {
30
+ if (!props.fixedColShadow) return;
31
+ fixedShadowCols = [];
32
+ // 找到最右边的固定列 findLast
33
+ let lastLeftCol = null;
34
+ for (let i = tableHeaderLast.value.length - 1; i > 0; i--) {
35
+ const col = tableHeaderLast.value[i];
36
+ if (col.fixed === 'left') {
37
+ lastLeftCol = col;
38
+ break;
39
+ }
40
+ }
41
+ // 处理多级表头列阴影
42
+ let node: any = { __PARENT__: lastLeftCol };
43
+ while ((node = node.__PARENT__)) {
44
+ if (node.fixed) {
45
+ fixedShadowCols.push(node);
46
+ }
47
+ }
48
+
49
+ // 找到最左边的固定列
50
+ const lastRightCol = tableHeaderLast.value.find(it => it.fixed === 'right');
51
+ node = { __PARENT__: lastRightCol };
52
+ while ((node = node.__PARENT__)) {
53
+ if (node.fixed) {
54
+ fixedShadowCols.push(node);
55
+ }
56
+ }
57
+ }
58
+
59
+ /** 固定列class */
60
+ function getFixedColClass(col: StkTableColumn<DT>): Record<string, boolean> {
61
+ const { showR, showL } = fixedShadow.value;
62
+ const showShadow =
63
+ props.fixedColShadow &&
64
+ col.fixed &&
65
+ ((showL && col.fixed === 'left') || (showR && col.fixed === 'right')) &&
66
+ fixedShadowCols.includes(col);
67
+ const classObj = {
68
+ 'fixed-cell': col.fixed,
69
+ ['fixed-cell--' + col.fixed]: col.fixed,
70
+ 'fixed-cell--shadow': showShadow,
71
+ };
72
+ return classObj;
73
+ }
74
+
75
+ /** 滚动条变化时,更新需要展示阴影的列 */
76
+ function updateFixedShadow() {
77
+ if (!props.fixedColShadow) return;
78
+ const { clientWidth, scrollWidth, scrollLeft } = tableContainer.value as HTMLDivElement;
79
+ fixedShadow.value.showL = Boolean(scrollLeft);
80
+ fixedShadow.value.showR = Math.abs(scrollWidth - scrollLeft - clientWidth) > 0.5;
81
+ }
82
+
83
+ return {
84
+ /** 固定列class */
85
+ getFixedColClass,
86
+ /** 处理固定列阴影 */
87
+ dealFixedColShadow,
88
+ /** 滚动条变化时,更新需要展示阴影的列 */
89
+ updateFixedShadow,
90
+ };
91
+ }