stk-table-vue 0.3.1 → 0.3.2

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.
@@ -14,6 +14,7 @@
14
14
  --border-color: #e8e8f4;
15
15
  --border-width: 1px;
16
16
  --td-bgc: #fff;
17
+ --td-hover-color: #71a2fd;
17
18
  --th-bgc: #fafafc;
18
19
  --th-color: #272841;
19
20
  --tr-active-bgc: rgb(230, 247, 255);
@@ -48,11 +49,13 @@
48
49
  border-left: 1px solid var(--border-color);
49
50
  /* 下面border用于表格内容不满高度时,绘制表格边界线 */
50
51
  background-image: var(--bg-border-top), var(--bg-border-right), var(--bg-border-bottom);
52
+
51
53
  /**深色模式 */
52
54
  &.dark {
53
55
  --th-bgc: #202029;
54
56
  --th-color: #C0C0D1;
55
57
  --td-bgc: #1b1b24;
58
+ --td-hover-color: #70a6ff;
56
59
  --border-color: #292933;
57
60
  --tr-active-bgc: #283f63;
58
61
  --tr-hover-bgc: #1a2b46;
@@ -144,240 +147,270 @@
144
147
  }
145
148
  }
146
149
 
150
+ /* 斑马纹*/
147
151
  &.stripe {
148
152
 
149
- /* 斑马纹*/
150
- tbody {
151
- tr:nth-child(odd) {
152
- background-color: var(--stripe-bgc);
153
- }
153
+ tbody tr:nth-child(odd) {
154
+ background-color: var(--stripe-bgc);
154
155
  }
155
156
  }
156
157
 
157
- /** 列宽调整指示器 */
158
- .column-resize-indicator {
159
- width: 0;
160
- height: 100%;
161
- border-left: 2px solid var(--col-resize-indicator-color);
162
- position: absolute;
163
- z-index: 10;
164
- display: none;
165
- pointer-events: none;
158
+ /* 单元格悬浮 */
159
+ &.cell-hover tbody td:hover {
160
+ box-shadow: inset 0 0 0 2px var(--td-hover-color);
166
161
  }
167
162
 
168
- .stk-table-main {
169
- border-spacing: 0;
170
- border-collapse: separate;
171
- width: fit-content;
172
- /* 不加会导致width 超过100%时为100%,行hover高亮会断开*/
173
- min-width: 100%;
174
-
175
- &.fixed-mode {
176
- table-layout: fixed;
177
- min-width: min-content;
163
+ /* td 溢出*/
164
+ &.text-overflow {
165
+ .table-cell-wrapper {
166
+ white-space: nowrap;
167
+ overflow: hidden;
168
+ text-overflow: ellipsis;
178
169
  }
170
+ }
179
171
 
180
- th,
181
- td {
182
- z-index: 1;
183
- font-size: 14px;
184
- box-sizing: border-box;
185
- padding: 0 var(--cell-padding-x);
172
+ /* th 溢出*/
173
+ &.header-text-overflow {
174
+ .table-header-cell-wrapper {
175
+ white-space: nowrap;
176
+ overflow: hidden;
186
177
  }
187
178
 
188
- th {
189
- color: var(--th-color);
190
- background-color: var(--th-bgc);
191
-
192
- &.sortable {
193
- cursor: pointer;
194
- }
179
+ .table-header-title {
180
+ text-overflow: ellipsis;
181
+ overflow: hidden;
182
+ }
183
+ }
195
184
 
196
- &.text-overflow {
197
- .table-header-cell-wrapper {
198
- white-space: nowrap;
199
- overflow: hidden;
200
- }
185
+ /**虚拟滚动模式 */
186
+ &.virtual {
201
187
 
202
- .table-header-title {
203
- text-overflow: ellipsis;
204
- overflow: hidden;
205
- }
206
- }
188
+ /* 为不影响布局,表头行高要定死*/
189
+ .table-header-cell-wrapper {
190
+ overflow: hidden;
191
+ max-height: var(--header-row-height);
207
192
  }
208
193
 
209
- td {
210
- &.fixed-cell {
211
- background-color: inherit;
212
- /* 防止横向滚动后透明*/
213
- }
214
-
215
- &.highlight-cell {
216
- animation: stk-table-dim var(--highlight-duration);
217
- animation-timing-function: var(--highlight-timing-function); /* 必须分开些,否则var(step(x))不兼容旧浏览器*/
218
- }
194
+ tbody {
195
+ td {
196
+ height: var(--row-height);
197
+ line-height: 1;
219
198
 
220
- &.text-overflow {
221
199
  .table-cell-wrapper {
222
- white-space: nowrap;
200
+ max-height: var(--row-height);
223
201
  overflow: hidden;
224
- text-overflow: ellipsis;
225
202
  }
226
203
  }
227
-
228
- &.seq-column{
229
- text-align: center;
230
- }
231
204
  }
232
205
 
233
- /*固定列阴影-左*/
234
- .fixed-cell--left {
235
- --shadow-rotate: 90deg;
206
+ .padding-top-tr td {
207
+ height: 0;
208
+ }
209
+ }
236
210
 
237
- &.fixed-cell--shadow::after {
238
- right: -10px;
239
- }
211
+ &.virtual-x {
212
+ .virtual-x-left {
213
+ padding: 0;
240
214
  }
215
+ }
241
216
 
242
- /*固定列阴影-右*/
243
- .fixed-cell--right {
244
- --shadow-rotate: -90deg;
217
+ th,
218
+ td {
219
+ z-index: 1;
220
+ font-size: 14px;
221
+ box-sizing: border-box;
222
+ padding: 0 var(--cell-padding-x);
223
+ }
245
224
 
246
- &.fixed-cell--shadow::after {
247
- left: -10px;
248
- }
249
- }
225
+ th {
226
+ color: var(--th-color);
227
+ background-color: inherit;
250
228
 
251
- /*固定列阴影*/
252
- .fixed-cell--shadow::after {
253
- content: '';
254
- width: 10px;
255
- height: 100%;
256
- top: 0px;
257
- position: absolute;
258
- pointer-events: none;
259
- background-image: linear-gradient(var(--shadow-rotate), var(--fixed-col-shadow-color-from), var(--fixed-col-shadow-color-to)),
229
+ &.sortable {
230
+ cursor: pointer;
260
231
  }
261
232
 
262
- thead {
263
- tr {
264
- height: var(--header-row-height);
233
+ &:not(.sorter-desc):not(.sorter-asc):hover .table-header-sorter {
234
+ .arrow-up {
235
+ fill: var(--sort-arrow-hover-color);
236
+ }
265
237
 
266
- &:first-child th {
267
- position: sticky;
268
- top: 0;
269
- }
238
+ .arrow-down {
239
+ fill: var(--sort-arrow-hover-color);
270
240
  }
271
241
  }
272
242
 
273
- th {
243
+ &.sorter-desc .table-header-sorter {
244
+ display: initial;
274
245
 
275
- &:not(.sorter-desc):not(.sorter-asc):hover .table-header-sorter {
276
- .arrow-up {
277
- fill: var(--sort-arrow-hover-color);
278
- }
246
+ .arrow-up {
247
+ fill: var(--sort-arrow-active-sub-color);
248
+ }
279
249
 
280
- .arrow-down {
281
- fill: var(--sort-arrow-hover-color);
282
- }
250
+ .arrow-down {
251
+ fill: var(--sort-arrow-active-color);
283
252
  }
253
+ }
284
254
 
285
- &.sorter-desc .table-header-sorter {
286
- display: initial;
255
+ &.sorter-asc .table-header-sorter {
256
+ display: initial;
287
257
 
288
- .arrow-up {
289
- fill: var(--sort-arrow-active-sub-color);
290
- }
258
+ .arrow-up {
259
+ fill: var(--sort-arrow-active-color);
260
+ }
291
261
 
292
- .arrow-down {
293
- fill: var(--sort-arrow-active-color);
294
- }
262
+ .arrow-down {
263
+ fill: var(--sort-arrow-active-sub-color);
295
264
  }
265
+ }
296
266
 
297
- &.sorter-asc .table-header-sorter {
298
- display: initial;
267
+ }
299
268
 
300
- .arrow-up {
301
- fill: var(--sort-arrow-active-color);
302
- }
269
+ thead {
270
+ tr {
271
+ background-color: var(--th-bgc);
272
+ height: var(--header-row-height);
303
273
 
304
- .arrow-down {
305
- fill: var(--sort-arrow-active-sub-color);
306
- }
274
+ &:first-child th {
275
+ position: sticky;
276
+ top: 0;
307
277
  }
278
+ }
279
+ }
308
280
 
281
+ /* stk-table-main 这层为了增加选择器优先级,防止被斑马纹颜色覆盖*/
282
+ .stk-table-main tbody tr {
283
+ background-color: var(--td-bgc);
284
+ height: var(--row-height);
285
+ /** 一行分层,有利于高亮行重绘
286
+ transform: translateZ(0);*/
309
287
 
288
+ &:hover {
289
+ background-color: var(--tr-hover-bgc);
310
290
  }
311
291
 
312
- .table-header-cell-wrapper {
313
- max-width: 100%;
314
- /*最大宽度不超过列宽*/
315
- display: inline-flex;
316
- align-items: center;
292
+ &.active {
293
+ background-color: var(--tr-active-bgc);
317
294
  }
295
+ }
318
296
 
319
- .table-header-title {
320
- overflow: hidden;
321
- align-self: flex-start;
322
- }
323
297
 
324
- .table-header-sorter {
325
- flex-shrink: 0;
326
- margin-left: 4px;
327
- width: 16px;
328
- height: 16px;
329
- display: none;
298
+ /** 列宽调整指示器 */
299
+ .column-resize-indicator {
300
+ width: 0;
301
+ height: 100%;
302
+ border-left: 2px solid var(--col-resize-indicator-color);
303
+ position: absolute;
304
+ z-index: 10;
305
+ display: none;
306
+ pointer-events: none;
307
+ }
330
308
 
331
- .arrow-up,
332
- .arrow-down {
333
- fill: var(--sort-arrow-color);
334
- }
309
+ .stk-table-main {
310
+ border-spacing: 0;
311
+ border-collapse: separate;
312
+ width: fit-content;
313
+ /* 不加会导致width 超过100%时为100%,行hover高亮会断开*/
314
+ min-width: 100%;
315
+
316
+ &.fixed-mode {
317
+ table-layout: fixed;
318
+ min-width: min-content;
335
319
  }
320
+ }
336
321
 
337
- .table-header-resizer {
338
- position: absolute;
339
- top: 0;
340
- bottom: 0;
341
- cursor: col-resize;
342
- width: var(--resize-handle-width);
322
+ .fixed-cell {
323
+ background-color: inherit;
324
+ /* 防止横向滚动后透明*/
325
+ }
343
326
 
344
- &.left {
345
- left: 0;
346
- }
327
+ .highlight-cell {
328
+ animation: stk-table-dim var(--highlight-duration);
329
+ animation-timing-function: var(--highlight-timing-function);
330
+ /* 必须分开些,否则var(step(x))不兼容旧浏览器*/
331
+ }
347
332
 
348
- &.right {
349
- right: 0;
350
- }
333
+ .seq-column {
334
+ text-align: center;
335
+ }
336
+
337
+ /*固定列阴影-左*/
338
+ .fixed-cell--left {
339
+ --shadow-rotate: 90deg;
340
+
341
+ &.fixed-cell--shadow::after {
342
+ right: -10px;
351
343
  }
344
+ }
352
345
 
353
- tbody {
346
+ /*固定列阴影-右*/
347
+ .fixed-cell--right {
348
+ --shadow-rotate: -90deg;
354
349
 
355
- tr {
356
- background-color: var(--td-bgc);
357
- height: var(--row-height);
358
- /** 一行分层,有利于高亮行重绘*/
359
- transform: translateZ(0);
350
+ &.fixed-cell--shadow::after {
351
+ left: -10px;
352
+ }
353
+ }
360
354
 
361
- /* td inherit tr bgc*/
362
- &.highlight-row {
363
- animation: stk-table-dim var(--highlight-duration);
364
- animation-timing-function: var(--highlight-timing-function); /* 必须分开些,否则var(step(x))不兼容旧浏览器*/
365
- }
366
-
355
+ /*固定列阴影*/
356
+ .fixed-cell--shadow::after {
357
+ content: '';
358
+ width: 10px;
359
+ height: 100%;
360
+ top: 0px;
361
+ position: absolute;
362
+ pointer-events: none;
363
+ background-image: linear-gradient(var(--shadow-rotate), var(--fixed-col-shadow-color-from), var(--fixed-col-shadow-color-to)),
364
+ }
367
365
 
368
- &.hover,
369
- &:hover {
370
- background-color: var(--tr-hover-bgc);
371
- }
366
+ .table-header-cell-wrapper {
367
+ max-width: 100%;
368
+ /*最大宽度不超过列宽*/
369
+ display: inline-flex;
370
+ align-items: center;
371
+ }
372
372
 
373
- &.active {
374
- background-color: var(--tr-active-bgc);
375
- }
376
- }
373
+ .table-header-title {
374
+ overflow: hidden;
375
+ align-self: flex-start;
376
+ }
377
377
 
378
+ .table-header-sorter {
379
+ flex-shrink: 0;
380
+ margin-left: 4px;
381
+ width: 16px;
382
+ height: 16px;
383
+ display: none;
384
+
385
+ .arrow-up,
386
+ .arrow-down {
387
+ fill: var(--sort-arrow-color);
378
388
  }
379
389
  }
380
390
 
391
+ .table-header-resizer {
392
+ position: absolute;
393
+ top: 0;
394
+ bottom: 0;
395
+ cursor: col-resize;
396
+ width: var(--resize-handle-width);
397
+
398
+ &.left {
399
+ left: 0;
400
+ }
401
+
402
+ &.right {
403
+ right: 0;
404
+ }
405
+ }
406
+
407
+ /* td inherit tr bgc*/
408
+ .highlight-row {
409
+ animation: stk-table-dim var(--highlight-duration);
410
+ /* 必须分开写,否则var(step(x))不兼容旧浏览器*/
411
+ animation-timing-function: var(--highlight-timing-function);
412
+ }
413
+
381
414
  .stk-table-no-data {
382
415
  background-color: var(--table-bgc);
383
416
  line-height: var(--row-height);
@@ -397,40 +430,4 @@
397
430
  }
398
431
  }
399
432
 
400
- /**虚拟滚动模式 */
401
- &.virtual {
402
-
403
- /* 为不影响布局,表头行高要定死*/
404
- .table-header-cell-wrapper {
405
- overflow: hidden;
406
- max-height: var(--header-row-height);
407
- }
408
-
409
- tbody {
410
- position: relative;
411
-
412
- tr {
413
-
414
- td {
415
- height: var(--row-height);
416
- line-height: 1;
417
-
418
- .table-cell-wrapper {
419
- max-height: var(--row-height);
420
- overflow: hidden;
421
- }
422
- }
423
- }
424
- }
425
-
426
- .padding-top-tr td {
427
- height: 0;
428
- }
429
- }
430
-
431
- &.virtual-x {
432
- .virtual-x-left {
433
- padding: 0;
434
- }
435
- }
436
433
  }
@@ -88,7 +88,7 @@ export function useFixedStyle<DT extends Record<string, any>>({
88
88
  if (tagType === TagType.TH) {
89
89
  // TH
90
90
  if (IS_LEGACY_MODE) {
91
- style.top = virtualScroll.value.scrollTop + depth * props.rowHeight + 'px';
91
+ style.top = virtualScroll.value.scrollTop + 'px';
92
92
  } else {
93
93
  style.top = depth * props.rowHeight + 'px';
94
94
  }
@@ -1,6 +1,6 @@
1
1
  import { interpolateRgb } from 'd3-interpolate';
2
2
  import { Ref, computed } from 'vue';
3
- import { HIGHLIGHT_CELL_CLASS, HIGHLIGHT_COLOR, HIGHLIGHT_DURATION, HIGHLIGHT_FREQ, HIGHLIGHT_ROW_CLASS, IS_LEGACY_MODE } from './const';
3
+ import { HIGHLIGHT_CELL_CLASS, HIGHLIGHT_COLOR, HIGHLIGHT_DURATION, HIGHLIGHT_FREQ, HIGHLIGHT_ROW_CLASS } from './const';
4
4
  import { HighlightConfig, UniqKey } from './types';
5
5
 
6
6
  type Params = {
@@ -114,7 +114,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
114
114
  /** 经过的时间 ÷ 高亮持续时间 计算出 颜色过渡进度 (0-1) */
115
115
  const progress = (nowTs - highlightStart) / highlightDuration;
116
116
  let bgc = '';
117
- if (0 < progress && progress < 1) {
117
+ if (0 <= progress && progress <= 1) {
118
118
  bgc = highlightInter.value(progress);
119
119
  } else {
120
120
  highlightDimRowsJs.delete(rowKeyValue);
@@ -128,7 +128,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
128
128
  } else {
129
129
  // 没有则停止循环
130
130
  calcHighlightDimLoopJs = false;
131
- highlightDimRowsJs.clear();
131
+ highlightDimRowsJs.clear(); // TODO: 是否需要 清除
132
132
  }
133
133
  }, highlightFrequency);
134
134
  };
@@ -198,13 +198,13 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
198
198
  ...option,
199
199
  };
200
200
 
201
- const nowTs = Date.now();
202
201
  if (method === 'css' || useCss) {
203
202
  // -------- use css keyframe
204
203
  highlightRowsInCssKeyframe(rowKeyValues, className, duration);
205
204
  } else if (method === 'animation') {
206
205
  if (props.virtual) {
207
206
  // -------- 用animation 接口实现动画
207
+ const nowTs = Date.now();
208
208
  for (let i = 0; i < rowKeyValues.length; i++) {
209
209
  const rowKeyValue = rowKeyValues[i];
210
210
  const store: HighlightDimRowStore = { ts: nowTs, visible: false, keyframe, duration };
@@ -222,6 +222,7 @@ export function useHighlight({ props, stkTableId, tableContainerRef }: Params) {
222
222
  }
223
223
  } else if (method === 'js') {
224
224
  // -------- 用js计算颜色渐变的高亮方案
225
+ const nowTs = Date.now();
225
226
  for (let i = 0; i < rowKeyValues.length; i++) {
226
227
  const rowKeyValue = rowKeyValues[i];
227
228
  highlightDimRowsJs.set(rowKeyValue, nowTs);
@@ -83,7 +83,7 @@ export function useVirtualScroll<DT extends Record<string, any>>({
83
83
  const virtual_dataSourcePart = computed(() => {
84
84
  if (!virtual_on.value) return dataSourceCopy.value;
85
85
  const { startIndex, endIndex } = virtualScroll.value;
86
- return dataSourceCopy.value.slice(startIndex, endIndex);
86
+ return dataSourceCopy.value.slice(startIndex, endIndex + 1);
87
87
  });
88
88
 
89
89
  const virtual_offsetBottom = computed(() => {
@@ -184,6 +184,10 @@ export function useVirtualScroll<DT extends Record<string, any>>({
184
184
  const { rowHeight, pageSize, scrollTop, startIndex: oldStartIndex } = virtualScroll.value;
185
185
  // 先更新滚动条位置记录,其他地方可能有依赖。(stripe 时ArrowUp/Down滚动依赖)
186
186
  virtualScroll.value.scrollTop = sTop;
187
+
188
+ // 非虚拟滚动不往下执行
189
+ if (!virtual_on.value) return;
190
+
187
191
  let startIndex = Math.floor(sTop / rowHeight);
188
192
  if (props.stripe) {
189
193
  startIndex -= 1; //预渲染1行
@@ -200,15 +204,13 @@ export function useVirtualScroll<DT extends Record<string, any>>({
200
204
  startIndex -= 1; // 奇数-1变成偶数
201
205
  }
202
206
  }
203
- let endIndex = startIndex + pageSize + 1; //预渲染一行 TODO: 是否需要预渲染一行
207
+ let endIndex = startIndex + pageSize;
204
208
  if (props.stripe) {
205
209
  // 由于stripe上方预渲染-1行,这里也要预渲染1+1行
206
- endIndex += 2;
210
+ endIndex += 1;
207
211
  }
208
212
  const offsetTop = startIndex * rowHeight; // startIndex之前的高度
209
- if (endIndex > dataSourceCopy.value.length) {
210
- endIndex = dataSourceCopy.value.length; // 溢出index修正
211
- }
213
+ endIndex = Math.min(endIndex, dataSourceCopy.value.length); // 溢出index修正
212
214
  if (vue2ScrollYTimeout) {
213
215
  window.clearTimeout(vue2ScrollYTimeout);
214
216
  }
@@ -269,13 +271,12 @@ export function useVirtualScroll<DT extends Record<string, any>>({
269
271
  colWidthSum += getCalculatedColWidth(col);
270
272
  // 列宽大于容器宽度则停止
271
273
  if (colWidthSum >= containerWidth) {
272
- endIndex = colIndex + 1; // 由于slice[start,end),要加1
274
+ endIndex = colIndex + 1; // slice endIndex + 1
273
275
  break;
274
276
  }
275
277
  }
276
- if (endIndex > headerLength) {
277
- endIndex = headerLength;
278
- }
278
+
279
+ endIndex = Math.min(endIndex, headerLength);
279
280
 
280
281
  if (vue2ScrollXTimeout) {
281
282
  window.clearTimeout(vue2ScrollXTimeout);
@@ -5,7 +5,7 @@ import { Order, SortConfig, SortOption, SortState, StkTableColumn } from './type
5
5
  function isEmptyValue(val: any, isNumber?: boolean) {
6
6
  let isEmpty = val === null || val === '';
7
7
  if (isNumber) {
8
- isEmpty ||= typeof val === 'boolean' || Number.isNaN(+val);
8
+ isEmpty = isEmpty || typeof val === 'boolean' || Number.isNaN(+val);
9
9
  }
10
10
  return isEmpty;
11
11
  }