stk-table-vue 0.6.16 → 0.7.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.
- package/README.md +211 -213
- package/lib/src/StkTable/StkTable.vue.d.ts +43 -24
- package/lib/src/StkTable/components/TriangleIcon.vue.d.ts +2 -0
- package/lib/src/StkTable/const.d.ts +0 -1
- package/lib/src/StkTable/types/highlightDimOptions.d.ts +1 -5
- package/lib/src/StkTable/types/index.d.ts +26 -6
- package/lib/src/StkTable/useHighlight.d.ts +1 -1
- package/lib/src/StkTable/useRowExpand.d.ts +17 -0
- package/lib/src/StkTable/useTree.d.ts +20 -0
- package/lib/stk-table-vue.js +321 -170
- package/lib/style.css +29 -20
- package/package.json +75 -75
- package/src/StkTable/StkTable.vue +1557 -1550
- package/src/StkTable/components/DragHandle.vue +9 -9
- package/src/StkTable/components/SortIcon.vue +6 -6
- package/src/StkTable/components/TriangleIcon.vue +3 -0
- package/src/StkTable/const.ts +37 -37
- package/src/StkTable/index.ts +4 -4
- package/src/StkTable/style.less +567 -553
- package/src/StkTable/types/highlightDimOptions.ts +26 -26
- package/src/StkTable/types/index.ts +260 -239
- package/src/StkTable/useAutoResize.ts +91 -91
- package/src/StkTable/useColResize.ts +216 -216
- package/src/StkTable/useFixedCol.ts +148 -148
- package/src/StkTable/useFixedStyle.ts +75 -75
- package/src/StkTable/useGetFixedColPosition.ts +65 -65
- package/src/StkTable/useHighlight.ts +320 -318
- package/src/StkTable/useKeyboardArrowScroll.ts +112 -112
- package/src/StkTable/useRowExpand.ts +78 -0
- package/src/StkTable/useThDrag.ts +102 -102
- package/src/StkTable/useTrDrag.ts +118 -118
- package/src/StkTable/useTree.ts +158 -0
- package/src/StkTable/useVirtualScroll.ts +462 -462
- package/src/StkTable/utils/constRefUtils.ts +29 -29
- package/src/StkTable/utils/index.ts +213 -212
- package/src/StkTable/utils/useTriggerRef.ts +33 -33
- package/src/VirtualTree.vue +622 -622
- package/src/VirtualTreeSelect.vue +367 -367
- package/src/vite-env.d.ts +10 -10
|
@@ -1,1550 +1,1557 @@
|
|
|
1
|
-
<!-- eslint-disable vue/attribute-hyphenation -->
|
|
2
|
-
<template>
|
|
3
|
-
<div
|
|
4
|
-
ref="tableContainerRef"
|
|
5
|
-
class="stk-table"
|
|
6
|
-
:class="{
|
|
7
|
-
virtual,
|
|
8
|
-
'virtual-x': virtualX,
|
|
9
|
-
'vt-on': virtual_on,
|
|
10
|
-
light: theme === 'light',
|
|
11
|
-
dark: theme === 'dark',
|
|
12
|
-
headless,
|
|
13
|
-
'is-col-resizing': isColResizing,
|
|
14
|
-
'col-resizable': props.colResizable,
|
|
15
|
-
border: props.bordered,
|
|
16
|
-
'border-h': props.bordered === 'h',
|
|
17
|
-
'border-v': props.bordered === 'v',
|
|
18
|
-
'border-body-v': props.bordered === 'body-v',
|
|
19
|
-
stripe: props.stripe,
|
|
20
|
-
'cell-hover': props.cellHover,
|
|
21
|
-
'cell-active': props.cellActive,
|
|
22
|
-
'row-hover': props.rowHover,
|
|
23
|
-
'row-active': props.rowActive,
|
|
24
|
-
'text-overflow': props.showOverflow,
|
|
25
|
-
'header-text-overflow': props.showHeaderOverflow,
|
|
26
|
-
'fixed-relative-mode': isRelativeMode,
|
|
27
|
-
'auto-row-height': props.autoRowHeight,
|
|
28
|
-
'scroll-row-by-row': props.scrollRowByRow,
|
|
29
|
-
}"
|
|
30
|
-
:style="{
|
|
31
|
-
'--row-height': props.autoRowHeight ? void 0 : virtualScroll.rowHeight + 'px',
|
|
32
|
-
'--header-row-height': props.headerRowHeight + 'px',
|
|
33
|
-
'--highlight-duration': props.highlightConfig.duration && props.highlightConfig.duration + 's',
|
|
34
|
-
'--highlight-timing-function': highlightSteps ? `steps(${highlightSteps})` : '',
|
|
35
|
-
}"
|
|
36
|
-
@scroll="onTableScroll"
|
|
37
|
-
@wheel="onTableWheel"
|
|
38
|
-
>
|
|
39
|
-
<!-- 这个元素用于整数行虚拟滚动时,撑开父容器的高度) -->
|
|
40
|
-
<div
|
|
41
|
-
v-if="props.scrollRowByRow && virtual"
|
|
42
|
-
class="row-by-row-table-height"
|
|
43
|
-
:style="{ height: dataSourceCopy.length * virtualScroll.rowHeight + 'px' }"
|
|
44
|
-
></div>
|
|
45
|
-
|
|
46
|
-
<div v-if="colResizable" ref="colResizeIndicatorRef" class="column-resize-indicator"></div>
|
|
47
|
-
<!-- 表格主体 -->
|
|
48
|
-
<table
|
|
49
|
-
class="stk-table-main"
|
|
50
|
-
:style="{ width, minWidth, maxWidth }"
|
|
51
|
-
:class="{
|
|
52
|
-
'fixed-mode': props.fixedMode,
|
|
53
|
-
}"
|
|
54
|
-
>
|
|
55
|
-
<!-- transform: virtualX_on ? `translateX(${virtualScrollX.offsetLeft}px)` : null, 用transform控制虚拟滚动左边距,sticky会有问题 -->
|
|
56
|
-
<thead v-if="!headless" ref="theadRef">
|
|
57
|
-
<tr v-for="(row, rowIndex) in tableHeaders" :key="rowIndex" @contextmenu="
|
|
58
|
-
<!-- 这个th用于横向虚拟滚动表格左边距,width、maxWidth 用于兼容低版本浏览器 -->
|
|
59
|
-
<th
|
|
60
|
-
v-if="virtualX_on"
|
|
61
|
-
class="vt-x-left"
|
|
62
|
-
:style="`min-width:${virtualScrollX.offsetLeft}px;width:${virtualScrollX.offsetLeft}px`"
|
|
63
|
-
></th>
|
|
64
|
-
<!-- v for中最后一行才用 切割。-->
|
|
65
|
-
<th
|
|
66
|
-
v-for="(col, colIndex) in virtualX_on && rowIndex === tableHeaders.length - 1 ? virtualX_columnPart : row"
|
|
67
|
-
:key="colKeyGen(col)"
|
|
68
|
-
:data-col-key="colKeyGen(col)"
|
|
69
|
-
:draggable="isHeaderDraggable(col) ? 'true' : 'false'"
|
|
70
|
-
:rowspan="virtualX_on ? 1 : col.rowSpan"
|
|
71
|
-
:colspan="col.colSpan"
|
|
72
|
-
:style="cellStyleMap[TagType.TH].get(colKeyGen(col))"
|
|
73
|
-
:title="getHeaderTitle(col)"
|
|
74
|
-
:class="[
|
|
75
|
-
col.sorter ? 'sortable' : '',
|
|
76
|
-
colKeyGen(col) === sortCol && sortOrderIndex !== 0 && 'sorter-' + sortSwitchOrder[sortOrderIndex],
|
|
77
|
-
col.headerClassName,
|
|
78
|
-
fixedColClassMap.get(colKeyGen(col)),
|
|
79
|
-
]"
|
|
80
|
-
@click="
|
|
81
|
-
e => {
|
|
82
|
-
onColumnSort(col);
|
|
83
|
-
onHeaderCellClick(e, col);
|
|
84
|
-
}
|
|
85
|
-
"
|
|
86
|
-
@dragstart="onThDragStart"
|
|
87
|
-
@drop="onThDrop"
|
|
88
|
-
@dragover="onThDragOver"
|
|
89
|
-
>
|
|
90
|
-
<!-- 列宽拖动handler -->
|
|
91
|
-
<div
|
|
92
|
-
v-if="colResizeOn(col) && colIndex > 0"
|
|
93
|
-
class="table-header-resizer left"
|
|
94
|
-
@mousedown="
|
|
95
|
-
></div>
|
|
96
|
-
<div class="table-header-cell-wrapper" :style="{ '--row-span': virtualX_on ? 1 : col.rowSpan }">
|
|
97
|
-
<component :is="col.customHeaderCell" v-if="col.customHeaderCell" :col="col" :colIndex="colIndex" :rowIndex="rowIndex" />
|
|
98
|
-
<template v-else>
|
|
99
|
-
<slot name="tableHeader" :col="col">
|
|
100
|
-
<span class="table-header-title">{{ col.title }}</span>
|
|
101
|
-
</slot>
|
|
102
|
-
</template>
|
|
103
|
-
<SortIcon v-if="col.sorter" class="table-header-sorter" />
|
|
104
|
-
</div>
|
|
105
|
-
<!-- 列宽拖动handler -->
|
|
106
|
-
<div v-if="colResizeOn(col)" class="table-header-resizer right" @mousedown="
|
|
107
|
-
</th>
|
|
108
|
-
<!-- 这个th用于横向虚拟滚动表格右边距 width, min-width 用于兼容低版本浏览器-->
|
|
109
|
-
<th v-if="virtualX_on" class="vt-x-right" :style="`min-width:${virtualX_offsetRight}px;width:${virtualX_offsetRight}px`"></th>
|
|
110
|
-
</tr>
|
|
111
|
-
</thead>
|
|
112
|
-
|
|
113
|
-
<!-- 用于虚拟滚动表格内容定位 @deprecated 有兼容问题-->
|
|
114
|
-
<!-- <tbody v-if="virtual_on" :style="{ height: `${virtualScroll.offsetTop}px` }"></tbody> -->
|
|
115
|
-
<!-- <tbody :style="{ transform: `translateY(${virtualScroll.offsetTop}px)` }"> -->
|
|
116
|
-
<tbody class="stk-tbody-main" @dragover="onTrDragOver" @dragenter="onTrDragEnter" @dragend="onTrDragEnd">
|
|
117
|
-
<tr v-if="virtual_on && !props.scrollRowByRow" :style="`height:${virtualScroll.offsetTop}px`" class="padding-top-tr">
|
|
118
|
-
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
119
|
-
<td v-if="virtualX_on && fixedMode && headless" class="vt-x-left"></td>
|
|
120
|
-
<template v-if="fixedMode && headless">
|
|
121
|
-
<td v-for="col in virtualX_columnPart" :key="colKeyGen(col)" :style="cellStyleMap[TagType.TD].get(colKeyGen(col))"></td>
|
|
122
|
-
</template>
|
|
123
|
-
</tr>
|
|
124
|
-
<tr
|
|
125
|
-
v-for="(row, rowIndex) in virtual_dataSourcePart"
|
|
126
|
-
:id="stkTableId + '-' + (rowKey ? rowKeyGen(row) : getRowIndex(rowIndex))"
|
|
127
|
-
ref="trRef"
|
|
128
|
-
:key="rowKey ? rowKeyGen(row) : getRowIndex(rowIndex)"
|
|
129
|
-
:data-row-key="rowKey ? rowKeyGen(row) : getRowIndex(rowIndex)"
|
|
130
|
-
:class="{
|
|
131
|
-
active: rowKey ? rowKeyGen(row) === currentRowKey : row === currentRow,
|
|
132
|
-
hover: props.showTrHoverClass && (rowKey ? rowKeyGen(row) === currentHoverRowKey : row === currentHoverRowKey),
|
|
133
|
-
[rowClassName(row, getRowIndex(rowIndex))]: true,
|
|
134
|
-
expanded: row?.__EXPANDED__,
|
|
135
|
-
'expanded-row': row && row.__EXPANDED_ROW__,
|
|
136
|
-
}"
|
|
137
|
-
:style="{
|
|
138
|
-
'--row-height':
|
|
139
|
-
row && row.__EXPANDED_ROW__ && props.virtual && props.expandConfig?.height && props.expandConfig?.height + 'px',
|
|
140
|
-
}"
|
|
141
|
-
@click="
|
|
142
|
-
@dblclick="
|
|
143
|
-
@contextmenu="
|
|
144
|
-
@mouseover="
|
|
145
|
-
@drop="
|
|
146
|
-
>
|
|
147
|
-
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
148
|
-
<td v-if="virtualX_on" class="vt-x-left"></td>
|
|
149
|
-
<td v-if="row && row.__EXPANDED_ROW__" :colspan="virtualX_columnPart.length">
|
|
150
|
-
<!-- TODO: support wheel -->
|
|
151
|
-
<div class="table-cell-wrapper">
|
|
152
|
-
<slot name="expand" :row="row.__EXPANDED_ROW__" :col="row.__EXPANDED_COL__">
|
|
153
|
-
{{ row.__EXPANDED_ROW__?.[row.__EXPANDED_COL__.dataIndex] ?? '' }}
|
|
154
|
-
</slot>
|
|
155
|
-
</div>
|
|
156
|
-
</td>
|
|
157
|
-
<template v-else>
|
|
158
|
-
<td
|
|
159
|
-
v-for="(col, colIndex) in virtualX_columnPart"
|
|
160
|
-
:key="colKeyGen(col)"
|
|
161
|
-
:data-cell-key="cellKeyGen(row, col)"
|
|
162
|
-
:style="cellStyleMap[TagType.TD].get(colKeyGen(col))"
|
|
163
|
-
:class="[
|
|
164
|
-
col.className,
|
|
165
|
-
fixedColClassMap.get(colKeyGen(col)),
|
|
166
|
-
{
|
|
167
|
-
'seq-column': col.type === 'seq',
|
|
168
|
-
active: currentSelectedCellKey === cellKeyGen(row, col),
|
|
169
|
-
|
|
170
|
-
expanded: col.type === '
|
|
171
|
-
'drag-row-cell': col.type === 'dragRow',
|
|
172
|
-
},
|
|
173
|
-
]"
|
|
174
|
-
@click="
|
|
175
|
-
@mousedown="
|
|
176
|
-
@mouseenter="
|
|
177
|
-
@mouseleave="
|
|
178
|
-
@mouseover="
|
|
179
|
-
>
|
|
180
|
-
<
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
import {
|
|
256
|
-
import
|
|
257
|
-
import
|
|
258
|
-
import
|
|
259
|
-
import {
|
|
260
|
-
import {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
*
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
/**
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
* ```(
|
|
492
|
-
*/
|
|
493
|
-
(e: '
|
|
494
|
-
/**
|
|
495
|
-
*
|
|
496
|
-
*
|
|
497
|
-
* ```(ev: MouseEvent, row: DT, data: { rowIndex: number })```
|
|
498
|
-
*/
|
|
499
|
-
(e: 'row-
|
|
500
|
-
/**
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* ```(ev: MouseEvent, row: DT
|
|
504
|
-
*/
|
|
505
|
-
(e: '
|
|
506
|
-
/**
|
|
507
|
-
*
|
|
508
|
-
*
|
|
509
|
-
* ```(ev: MouseEvent, row: DT
|
|
510
|
-
*/
|
|
511
|
-
(e: 'cell-
|
|
512
|
-
/**
|
|
513
|
-
*
|
|
514
|
-
*
|
|
515
|
-
* ```(ev: MouseEvent, row: DT,
|
|
516
|
-
*/
|
|
517
|
-
(e: '
|
|
518
|
-
/**
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
* ```(ev: MouseEvent
|
|
522
|
-
*/
|
|
523
|
-
(e: '
|
|
524
|
-
/**
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
* ```(ev: MouseEvent, row: DT,
|
|
528
|
-
*/
|
|
529
|
-
(e: '
|
|
530
|
-
/**
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
* ```(ev: MouseEvent, col: StkTableColumn<DT
|
|
534
|
-
*/
|
|
535
|
-
(e: '
|
|
536
|
-
/**
|
|
537
|
-
*
|
|
538
|
-
*
|
|
539
|
-
* ```(ev:
|
|
540
|
-
*/
|
|
541
|
-
(e: '
|
|
542
|
-
/**
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
* ```(ev:
|
|
546
|
-
*/
|
|
547
|
-
(e: '
|
|
548
|
-
/**
|
|
549
|
-
*
|
|
550
|
-
*
|
|
551
|
-
* ```(
|
|
552
|
-
*/
|
|
553
|
-
(e: '
|
|
554
|
-
/**
|
|
555
|
-
*
|
|
556
|
-
*
|
|
557
|
-
* ```(
|
|
558
|
-
*/
|
|
559
|
-
(e: '
|
|
560
|
-
/**
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
* ```(
|
|
564
|
-
*/
|
|
565
|
-
(e: '
|
|
566
|
-
/**
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
* ```(
|
|
570
|
-
*/
|
|
571
|
-
(e: '
|
|
572
|
-
/**
|
|
573
|
-
*
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
*/
|
|
577
|
-
(e: '
|
|
578
|
-
/**
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
* ```(
|
|
582
|
-
*/
|
|
583
|
-
(e: '
|
|
584
|
-
/**
|
|
585
|
-
*
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
/**
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
const
|
|
703
|
-
|
|
704
|
-
const {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
);
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
)
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
function
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
[
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
/**
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
if (
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
//
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
function
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
if (
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
/**
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
/**
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
if (!
|
|
1299
|
-
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
/**
|
|
1366
|
-
*
|
|
1367
|
-
* @
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
*
|
|
1383
|
-
* @param
|
|
1384
|
-
* @param
|
|
1385
|
-
* @param
|
|
1386
|
-
* @param
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
if (
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
defineExpose({
|
|
1438
|
-
/**
|
|
1439
|
-
* 重新计算虚拟列表宽高
|
|
1440
|
-
*
|
|
1441
|
-
* en: calc virtual scroll x & y info
|
|
1442
|
-
* @see {@link initVirtualScroll}
|
|
1443
|
-
*/
|
|
1444
|
-
initVirtualScroll,
|
|
1445
|
-
/**
|
|
1446
|
-
* 重新计算虚拟列表宽度
|
|
1447
|
-
*
|
|
1448
|
-
* en: calc virtual scroll x
|
|
1449
|
-
* @see {@link initVirtualScrollX}
|
|
1450
|
-
*/
|
|
1451
|
-
initVirtualScrollX,
|
|
1452
|
-
/**
|
|
1453
|
-
* 重新计算虚拟列表高度
|
|
1454
|
-
*
|
|
1455
|
-
* en: calc virtual scroll y
|
|
1456
|
-
* @see {@link initVirtualScrollY}
|
|
1457
|
-
*/
|
|
1458
|
-
initVirtualScrollY,
|
|
1459
|
-
/**
|
|
1460
|
-
* 选中一行
|
|
1461
|
-
*
|
|
1462
|
-
* en:select a row
|
|
1463
|
-
* @see {@link setCurrentRow}
|
|
1464
|
-
*/
|
|
1465
|
-
setCurrentRow,
|
|
1466
|
-
/**
|
|
1467
|
-
* 取消选中单元格
|
|
1468
|
-
*
|
|
1469
|
-
* en: set highlight active cell (props.cellActive=true)
|
|
1470
|
-
* @see {@link setSelectedCell}
|
|
1471
|
-
*/
|
|
1472
|
-
setSelectedCell,
|
|
1473
|
-
/**
|
|
1474
|
-
* 设置高亮单元格
|
|
1475
|
-
*
|
|
1476
|
-
* en: Set highlight cell
|
|
1477
|
-
* @see {@link setHighlightDimCell}
|
|
1478
|
-
*/
|
|
1479
|
-
setHighlightDimCell,
|
|
1480
|
-
/**
|
|
1481
|
-
* 设置高亮行
|
|
1482
|
-
*
|
|
1483
|
-
* en: Set highlight row
|
|
1484
|
-
* @see {@link setHighlightDimRow}
|
|
1485
|
-
*/
|
|
1486
|
-
setHighlightDimRow,
|
|
1487
|
-
/**
|
|
1488
|
-
* 表格排序列colKey
|
|
1489
|
-
*
|
|
1490
|
-
* en: Table sort column colKey
|
|
1491
|
-
*/
|
|
1492
|
-
sortCol,
|
|
1493
|
-
/**
|
|
1494
|
-
* 表格排序列顺序
|
|
1495
|
-
*
|
|
1496
|
-
* en: get current sort info
|
|
1497
|
-
* @see {@link getSortColumns}
|
|
1498
|
-
*/
|
|
1499
|
-
getSortColumns,
|
|
1500
|
-
/**
|
|
1501
|
-
* 设置表头排序状态
|
|
1502
|
-
*
|
|
1503
|
-
* en: Set the sort status of the table header
|
|
1504
|
-
* @see {@link setSorter}
|
|
1505
|
-
*/
|
|
1506
|
-
setSorter,
|
|
1507
|
-
/**
|
|
1508
|
-
* 重置sorter状态
|
|
1509
|
-
*
|
|
1510
|
-
* en: Reset the sorter status
|
|
1511
|
-
* @see {@link resetSorter}
|
|
1512
|
-
*/
|
|
1513
|
-
resetSorter,
|
|
1514
|
-
/**
|
|
1515
|
-
* 滚动至
|
|
1516
|
-
*
|
|
1517
|
-
* en: Scroll to
|
|
1518
|
-
* @see {@link scrollTo}
|
|
1519
|
-
*/
|
|
1520
|
-
scrollTo,
|
|
1521
|
-
/**
|
|
1522
|
-
* 获取表格数据
|
|
1523
|
-
*
|
|
1524
|
-
* en: Get table data
|
|
1525
|
-
* @see {@link getTableData}
|
|
1526
|
-
*/
|
|
1527
|
-
getTableData,
|
|
1528
|
-
/**
|
|
1529
|
-
* 设置展开的行
|
|
1530
|
-
*
|
|
1531
|
-
* en: Set expanded rows
|
|
1532
|
-
* @see {@link setRowExpand}
|
|
1533
|
-
*/
|
|
1534
|
-
setRowExpand,
|
|
1535
|
-
/**
|
|
1536
|
-
* 不定行高时,如果行高有变化,则调用此方法更新行高。
|
|
1537
|
-
*
|
|
1538
|
-
* en: When the row height is not fixed, call this method to update the row height if the row height changes.
|
|
1539
|
-
* @see {@link setAutoHeight}
|
|
1540
|
-
*/
|
|
1541
|
-
setAutoHeight,
|
|
1542
|
-
/**
|
|
1543
|
-
* 清除所有行高
|
|
1544
|
-
*
|
|
1545
|
-
* en: Clear all row heights
|
|
1546
|
-
* @see {@link clearAllAutoHeight}
|
|
1547
|
-
*/
|
|
1548
|
-
clearAllAutoHeight,
|
|
1549
|
-
|
|
1550
|
-
|
|
1
|
+
<!-- eslint-disable vue/attribute-hyphenation -->
|
|
2
|
+
<template>
|
|
3
|
+
<div
|
|
4
|
+
ref="tableContainerRef"
|
|
5
|
+
class="stk-table"
|
|
6
|
+
:class="{
|
|
7
|
+
virtual,
|
|
8
|
+
'virtual-x': virtualX,
|
|
9
|
+
'vt-on': virtual_on,
|
|
10
|
+
light: theme === 'light',
|
|
11
|
+
dark: theme === 'dark',
|
|
12
|
+
headless,
|
|
13
|
+
'is-col-resizing': isColResizing,
|
|
14
|
+
'col-resizable': props.colResizable,
|
|
15
|
+
border: props.bordered,
|
|
16
|
+
'border-h': props.bordered === 'h',
|
|
17
|
+
'border-v': props.bordered === 'v',
|
|
18
|
+
'border-body-v': props.bordered === 'body-v',
|
|
19
|
+
stripe: props.stripe,
|
|
20
|
+
'cell-hover': props.cellHover,
|
|
21
|
+
'cell-active': props.cellActive,
|
|
22
|
+
'row-hover': props.rowHover,
|
|
23
|
+
'row-active': props.rowActive,
|
|
24
|
+
'text-overflow': props.showOverflow,
|
|
25
|
+
'header-text-overflow': props.showHeaderOverflow,
|
|
26
|
+
'fixed-relative-mode': isRelativeMode,
|
|
27
|
+
'auto-row-height': props.autoRowHeight,
|
|
28
|
+
'scroll-row-by-row': props.scrollRowByRow,
|
|
29
|
+
}"
|
|
30
|
+
:style="{
|
|
31
|
+
'--row-height': props.autoRowHeight ? void 0 : virtualScroll.rowHeight + 'px',
|
|
32
|
+
'--header-row-height': props.headerRowHeight + 'px',
|
|
33
|
+
'--highlight-duration': props.highlightConfig.duration && props.highlightConfig.duration + 's',
|
|
34
|
+
'--highlight-timing-function': highlightSteps ? `steps(${highlightSteps})` : '',
|
|
35
|
+
}"
|
|
36
|
+
@scroll="onTableScroll"
|
|
37
|
+
@wheel="onTableWheel"
|
|
38
|
+
>
|
|
39
|
+
<!-- 这个元素用于整数行虚拟滚动时,撑开父容器的高度) -->
|
|
40
|
+
<div
|
|
41
|
+
v-if="props.scrollRowByRow && virtual"
|
|
42
|
+
class="row-by-row-table-height"
|
|
43
|
+
:style="{ height: dataSourceCopy.length * virtualScroll.rowHeight + 'px' }"
|
|
44
|
+
></div>
|
|
45
|
+
|
|
46
|
+
<div v-if="colResizable" ref="colResizeIndicatorRef" class="column-resize-indicator"></div>
|
|
47
|
+
<!-- 表格主体 -->
|
|
48
|
+
<table
|
|
49
|
+
class="stk-table-main"
|
|
50
|
+
:style="{ width, minWidth, maxWidth }"
|
|
51
|
+
:class="{
|
|
52
|
+
'fixed-mode': props.fixedMode,
|
|
53
|
+
}"
|
|
54
|
+
>
|
|
55
|
+
<!-- transform: virtualX_on ? `translateX(${virtualScrollX.offsetLeft}px)` : null, 用transform控制虚拟滚动左边距,sticky会有问题 -->
|
|
56
|
+
<thead v-if="!headless" ref="theadRef">
|
|
57
|
+
<tr v-for="(row, rowIndex) in tableHeaders" :key="rowIndex" @contextmenu="onHeaderMenu($event)">
|
|
58
|
+
<!-- 这个th用于横向虚拟滚动表格左边距,width、maxWidth 用于兼容低版本浏览器 -->
|
|
59
|
+
<th
|
|
60
|
+
v-if="virtualX_on"
|
|
61
|
+
class="vt-x-left"
|
|
62
|
+
:style="`min-width:${virtualScrollX.offsetLeft}px;width:${virtualScrollX.offsetLeft}px`"
|
|
63
|
+
></th>
|
|
64
|
+
<!-- v for中最后一行才用 切割。-->
|
|
65
|
+
<th
|
|
66
|
+
v-for="(col, colIndex) in virtualX_on && rowIndex === tableHeaders.length - 1 ? virtualX_columnPart : row"
|
|
67
|
+
:key="colKeyGen(col)"
|
|
68
|
+
:data-col-key="colKeyGen(col)"
|
|
69
|
+
:draggable="isHeaderDraggable(col) ? 'true' : 'false'"
|
|
70
|
+
:rowspan="virtualX_on ? 1 : col.rowSpan"
|
|
71
|
+
:colspan="col.colSpan"
|
|
72
|
+
:style="cellStyleMap[TagType.TH].get(colKeyGen(col))"
|
|
73
|
+
:title="getHeaderTitle(col)"
|
|
74
|
+
:class="[
|
|
75
|
+
col.sorter ? 'sortable' : '',
|
|
76
|
+
colKeyGen(col) === sortCol && sortOrderIndex !== 0 && 'sorter-' + sortSwitchOrder[sortOrderIndex],
|
|
77
|
+
col.headerClassName,
|
|
78
|
+
fixedColClassMap.get(colKeyGen(col)),
|
|
79
|
+
]"
|
|
80
|
+
@click="
|
|
81
|
+
e => {
|
|
82
|
+
onColumnSort(col);
|
|
83
|
+
onHeaderCellClick(e, col);
|
|
84
|
+
}
|
|
85
|
+
"
|
|
86
|
+
@dragstart="onThDragStart"
|
|
87
|
+
@drop="onThDrop"
|
|
88
|
+
@dragover="onThDragOver"
|
|
89
|
+
>
|
|
90
|
+
<!-- 列宽拖动handler -->
|
|
91
|
+
<div
|
|
92
|
+
v-if="colResizeOn(col) && colIndex > 0"
|
|
93
|
+
class="table-header-resizer left"
|
|
94
|
+
@mousedown="onThResizeMouseDown($event, col, true)"
|
|
95
|
+
></div>
|
|
96
|
+
<div class="table-header-cell-wrapper" :style="{ '--row-span': virtualX_on ? 1 : col.rowSpan }">
|
|
97
|
+
<component :is="col.customHeaderCell" v-if="col.customHeaderCell" :col="col" :colIndex="colIndex" :rowIndex="rowIndex" />
|
|
98
|
+
<template v-else>
|
|
99
|
+
<slot name="tableHeader" :col="col">
|
|
100
|
+
<span class="table-header-title">{{ col.title }}</span>
|
|
101
|
+
</slot>
|
|
102
|
+
</template>
|
|
103
|
+
<SortIcon v-if="col.sorter" class="table-header-sorter" />
|
|
104
|
+
</div>
|
|
105
|
+
<!-- 列宽拖动handler -->
|
|
106
|
+
<div v-if="colResizeOn(col)" class="table-header-resizer right" @mousedown="onThResizeMouseDown($event, col)"></div>
|
|
107
|
+
</th>
|
|
108
|
+
<!-- 这个th用于横向虚拟滚动表格右边距 width, min-width 用于兼容低版本浏览器-->
|
|
109
|
+
<th v-if="virtualX_on" class="vt-x-right" :style="`min-width:${virtualX_offsetRight}px;width:${virtualX_offsetRight}px`"></th>
|
|
110
|
+
</tr>
|
|
111
|
+
</thead>
|
|
112
|
+
|
|
113
|
+
<!-- 用于虚拟滚动表格内容定位 @deprecated 有兼容问题-->
|
|
114
|
+
<!-- <tbody v-if="virtual_on" :style="{ height: `${virtualScroll.offsetTop}px` }"></tbody> -->
|
|
115
|
+
<!-- <tbody :style="{ transform: `translateY(${virtualScroll.offsetTop}px)` }"> -->
|
|
116
|
+
<tbody class="stk-tbody-main" @dragover="onTrDragOver" @dragenter="onTrDragEnter" @dragend="onTrDragEnd">
|
|
117
|
+
<tr v-if="virtual_on && !props.scrollRowByRow" :style="`height:${virtualScroll.offsetTop}px`" class="padding-top-tr">
|
|
118
|
+
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
119
|
+
<td v-if="virtualX_on && fixedMode && headless" class="vt-x-left"></td>
|
|
120
|
+
<template v-if="fixedMode && headless">
|
|
121
|
+
<td v-for="col in virtualX_columnPart" :key="colKeyGen(col)" :style="cellStyleMap[TagType.TD].get(colKeyGen(col))"></td>
|
|
122
|
+
</template>
|
|
123
|
+
</tr>
|
|
124
|
+
<tr
|
|
125
|
+
v-for="(row, rowIndex) in virtual_dataSourcePart"
|
|
126
|
+
:id="stkTableId + '-' + (rowKey ? rowKeyGen(row) : getRowIndex(rowIndex))"
|
|
127
|
+
ref="trRef"
|
|
128
|
+
:key="rowKey ? rowKeyGen(row) : getRowIndex(rowIndex)"
|
|
129
|
+
:data-row-key="rowKey ? rowKeyGen(row) : getRowIndex(rowIndex)"
|
|
130
|
+
:class="{
|
|
131
|
+
active: rowKey ? rowKeyGen(row) === currentRowKey : row === currentRow,
|
|
132
|
+
hover: props.showTrHoverClass && (rowKey ? rowKeyGen(row) === currentHoverRowKey : row === currentHoverRowKey),
|
|
133
|
+
[rowClassName(row, getRowIndex(rowIndex))]: true,
|
|
134
|
+
expanded: row?.__EXPANDED__,
|
|
135
|
+
'expanded-row': row && row.__EXPANDED_ROW__,
|
|
136
|
+
}"
|
|
137
|
+
:style="{
|
|
138
|
+
'--row-height':
|
|
139
|
+
row && row.__EXPANDED_ROW__ && props.virtual && props.expandConfig?.height && props.expandConfig?.height + 'px',
|
|
140
|
+
}"
|
|
141
|
+
@click="onRowClick($event, row, getRowIndex(rowIndex))"
|
|
142
|
+
@dblclick="onRowDblclick($event, row, getRowIndex(rowIndex))"
|
|
143
|
+
@contextmenu="onRowMenu($event, row, getRowIndex(rowIndex))"
|
|
144
|
+
@mouseover="onTrMouseOver($event, row)"
|
|
145
|
+
@drop="onTrDrop($event, getRowIndex(rowIndex))"
|
|
146
|
+
>
|
|
147
|
+
<!--这个td用于配合虚拟滚动的th对应,防止列错位-->
|
|
148
|
+
<td v-if="virtualX_on" class="vt-x-left"></td>
|
|
149
|
+
<td v-if="row && row.__EXPANDED_ROW__" :colspan="virtualX_columnPart.length">
|
|
150
|
+
<!-- TODO: support wheel -->
|
|
151
|
+
<div class="table-cell-wrapper">
|
|
152
|
+
<slot name="expand" :row="row.__EXPANDED_ROW__" :col="row.__EXPANDED_COL__">
|
|
153
|
+
{{ row.__EXPANDED_ROW__?.[row.__EXPANDED_COL__.dataIndex] ?? '' }}
|
|
154
|
+
</slot>
|
|
155
|
+
</div>
|
|
156
|
+
</td>
|
|
157
|
+
<template v-else>
|
|
158
|
+
<td
|
|
159
|
+
v-for="(col, colIndex) in virtualX_columnPart"
|
|
160
|
+
:key="colKeyGen(col)"
|
|
161
|
+
:data-cell-key="cellKeyGen(row, col)"
|
|
162
|
+
:style="cellStyleMap[TagType.TD].get(colKeyGen(col))"
|
|
163
|
+
:class="[
|
|
164
|
+
col.className,
|
|
165
|
+
fixedColClassMap.get(colKeyGen(col)),
|
|
166
|
+
{
|
|
167
|
+
'seq-column': col.type === 'seq',
|
|
168
|
+
active: currentSelectedCellKey === cellKeyGen(row, col),
|
|
169
|
+
expanded: col.type === 'expand' && (row.__EXPANDED__ ? colKeyGen(row.__EXPANDED__) === colKeyGen(col) : false),
|
|
170
|
+
'tree-expanded': col.type === 'tree-node' && row.__T_EXPANDED__,
|
|
171
|
+
'drag-row-cell': col.type === 'dragRow',
|
|
172
|
+
},
|
|
173
|
+
]"
|
|
174
|
+
@click="onCellClick($event, row, col, getRowIndex(rowIndex))"
|
|
175
|
+
@mousedown="onCellMouseDown($event, row, col, getRowIndex(rowIndex))"
|
|
176
|
+
@mouseenter="onCellMouseEnter($event, row, col)"
|
|
177
|
+
@mouseleave="onCellMouseLeave($event, row, col)"
|
|
178
|
+
@mouseover="onCellMouseOver($event, row, col)"
|
|
179
|
+
>
|
|
180
|
+
<template v-if="col.type === 'expand' || col.type === 'tree-node'">
|
|
181
|
+
<div
|
|
182
|
+
class="table-cell-wrapper"
|
|
183
|
+
:title="row?.[col.dataIndex]"
|
|
184
|
+
:style="{ paddingLeft: row.__T_LV__ && row.__T_LV__ * 16 + 'px' }"
|
|
185
|
+
>
|
|
186
|
+
<component
|
|
187
|
+
:is="col.customCell"
|
|
188
|
+
v-if="col.customCell"
|
|
189
|
+
:col="col"
|
|
190
|
+
:row="row"
|
|
191
|
+
:rowIndex="getRowIndex(rowIndex)"
|
|
192
|
+
:colIndex="colIndex"
|
|
193
|
+
:cellValue="row && row[col.dataIndex]"
|
|
194
|
+
:expanded="(row && row.__EXPANDED__) || null"
|
|
195
|
+
:tree-expanded="(row && row.__T_EXPANDED__) || null"
|
|
196
|
+
>
|
|
197
|
+
<template #foldIcon>
|
|
198
|
+
<TriangleIcon></TriangleIcon>
|
|
199
|
+
</template>
|
|
200
|
+
</component>
|
|
201
|
+
<template v-else>
|
|
202
|
+
<TriangleIcon
|
|
203
|
+
v-if="col.type === 'expand' || (col.type === 'tree-node' && row.children !== void 0)"
|
|
204
|
+
@click="triangleClick($event, row, col)"
|
|
205
|
+
/>
|
|
206
|
+
<span :style="col.type === 'tree-node' && !row.children ? 'padding-left: 16px;' : ''">
|
|
207
|
+
{{ row?.[col.dataIndex] ?? '' }}
|
|
208
|
+
</span>
|
|
209
|
+
</template>
|
|
210
|
+
</div>
|
|
211
|
+
</template>
|
|
212
|
+
<template v-else>
|
|
213
|
+
<component
|
|
214
|
+
:is="col.customCell"
|
|
215
|
+
v-if="col.customCell"
|
|
216
|
+
class="table-cell-wrapper"
|
|
217
|
+
:col="col"
|
|
218
|
+
:row="row"
|
|
219
|
+
:rowIndex="getRowIndex(rowIndex)"
|
|
220
|
+
:colIndex="colIndex"
|
|
221
|
+
:cellValue="row && row[col.dataIndex]"
|
|
222
|
+
/>
|
|
223
|
+
<div v-else class="table-cell-wrapper" :title="col.type !== 'seq' ? row?.[col.dataIndex] : ''">
|
|
224
|
+
<template v-if="col.type === 'seq'">
|
|
225
|
+
{{ (props.seqConfig.startIndex || 0) + getRowIndex(rowIndex) + 1 }}
|
|
226
|
+
</template>
|
|
227
|
+
<template v-else-if="col.type === 'dragRow'">
|
|
228
|
+
<DragHandle @dragstart="onTrDragStart($event, getRowIndex(rowIndex))" />
|
|
229
|
+
<span>
|
|
230
|
+
{{ row?.[col.dataIndex] ?? '' }}
|
|
231
|
+
</span>
|
|
232
|
+
</template>
|
|
233
|
+
<template v-else>
|
|
234
|
+
{{ row?.[col.dataIndex] ?? getEmptyCellText(col, row) }}
|
|
235
|
+
</template>
|
|
236
|
+
</div>
|
|
237
|
+
</template>
|
|
238
|
+
</td>
|
|
239
|
+
</template>
|
|
240
|
+
</tr>
|
|
241
|
+
<tr v-if="virtual_on && !props.scrollRowByRow" :style="`height: ${virtual_offsetBottom}px`"></tr>
|
|
242
|
+
</tbody>
|
|
243
|
+
</table>
|
|
244
|
+
<div v-if="(!dataSourceCopy || !dataSourceCopy.length) && showNoData" class="stk-table-no-data" :class="{ 'no-data-full': noDataFull }">
|
|
245
|
+
<slot name="empty">暂无数据</slot>
|
|
246
|
+
</div>
|
|
247
|
+
<slot name="customBottom"></slot>
|
|
248
|
+
</div>
|
|
249
|
+
</template>
|
|
250
|
+
|
|
251
|
+
<script setup lang="ts">
|
|
252
|
+
/**
|
|
253
|
+
* @author japlus
|
|
254
|
+
*/
|
|
255
|
+
import { CSSProperties, computed, nextTick, onMounted, ref, shallowRef, toRaw, watch } from 'vue';
|
|
256
|
+
import DragHandle from './components/DragHandle.vue';
|
|
257
|
+
import SortIcon from './components/SortIcon.vue';
|
|
258
|
+
import TriangleIcon from './components/TriangleIcon.vue';
|
|
259
|
+
import { CELL_KEY_SEPARATE, DEFAULT_ROW_HEIGHT, DEFAULT_SMOOTH_SCROLL, IS_LEGACY_MODE } from './const';
|
|
260
|
+
import {
|
|
261
|
+
AutoRowHeightConfig,
|
|
262
|
+
ColResizableConfig,
|
|
263
|
+
DragRowConfig,
|
|
264
|
+
ExpandConfig,
|
|
265
|
+
HeaderDragConfig,
|
|
266
|
+
HighlightConfig,
|
|
267
|
+
Order,
|
|
268
|
+
PrivateRowDT,
|
|
269
|
+
PrivateStkTableColumn,
|
|
270
|
+
SeqConfig,
|
|
271
|
+
SortConfig,
|
|
272
|
+
SortOption,
|
|
273
|
+
StkTableColumn,
|
|
274
|
+
TagType,
|
|
275
|
+
TreeConfig,
|
|
276
|
+
UniqKeyProp,
|
|
277
|
+
} from './types/index';
|
|
278
|
+
import { useAutoResize } from './useAutoResize';
|
|
279
|
+
import { useColResize } from './useColResize';
|
|
280
|
+
import { useFixedCol } from './useFixedCol';
|
|
281
|
+
import { useFixedStyle } from './useFixedStyle';
|
|
282
|
+
import { useGetFixedColPosition } from './useGetFixedColPosition';
|
|
283
|
+
import { useHighlight } from './useHighlight';
|
|
284
|
+
import { useKeyboardArrowScroll } from './useKeyboardArrowScroll';
|
|
285
|
+
import { useRowExpand } from './useRowExpand';
|
|
286
|
+
import { useThDrag } from './useThDrag';
|
|
287
|
+
import { useTrDrag } from './useTrDrag';
|
|
288
|
+
import { useVirtualScroll } from './useVirtualScroll';
|
|
289
|
+
import { createStkTableId, getCalculatedColWidth, getColWidth } from './utils/constRefUtils';
|
|
290
|
+
import { howDeepTheHeader, tableSort, transformWidthToStr } from './utils/index';
|
|
291
|
+
import { useTree } from './useTree';
|
|
292
|
+
|
|
293
|
+
/** Generic stands for DataType */
|
|
294
|
+
type DT = any & PrivateRowDT;
|
|
295
|
+
|
|
296
|
+
/** generate table instance id */
|
|
297
|
+
const stkTableId = createStkTableId();
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* props cannot be placed in a separate file. It will cause compilation errors with vue 2.7 compiler.
|
|
301
|
+
*/
|
|
302
|
+
const props = withDefaults(
|
|
303
|
+
defineProps<{
|
|
304
|
+
width?: string;
|
|
305
|
+
/** 最小表格宽度 */
|
|
306
|
+
minWidth?: string;
|
|
307
|
+
/** 表格最大宽度*/
|
|
308
|
+
maxWidth?: string;
|
|
309
|
+
/** 斑马线条纹 */
|
|
310
|
+
stripe?: boolean;
|
|
311
|
+
/** 是否使用 table-layout:fixed(低版本浏览器需要设置table) */
|
|
312
|
+
fixedMode?: boolean;
|
|
313
|
+
/** 是否隐藏表头 */
|
|
314
|
+
headless?: boolean;
|
|
315
|
+
/** 主题,亮、暗 */
|
|
316
|
+
theme?: 'light' | 'dark';
|
|
317
|
+
/**
|
|
318
|
+
* 行高
|
|
319
|
+
* - `props.autoRowHeight` 为 `true` 时,将表示为期望行高,用于计算。不再影响实际行高。
|
|
320
|
+
*/
|
|
321
|
+
rowHeight?: number;
|
|
322
|
+
/**
|
|
323
|
+
* 是否可变行高
|
|
324
|
+
* - 设置为 `true` 时, `props.rowHeight` 将表示为期望行高,用于计算。不再影响实际行高。
|
|
325
|
+
*/
|
|
326
|
+
autoRowHeight?: boolean | AutoRowHeightConfig<DT>;
|
|
327
|
+
/** 是否高亮鼠标悬浮的行 */
|
|
328
|
+
rowHover?: boolean;
|
|
329
|
+
/** 是否高亮选中的行 */
|
|
330
|
+
rowActive?: boolean;
|
|
331
|
+
/** 当前行再次点击否可以取消 (rowActive=true)*/
|
|
332
|
+
rowCurrentRevokable?: boolean;
|
|
333
|
+
/** 表头行高。default = rowHeight */
|
|
334
|
+
headerRowHeight?: number | null;
|
|
335
|
+
/** 虚拟滚动 */
|
|
336
|
+
virtual?: boolean;
|
|
337
|
+
/** x轴虚拟滚动(必须设置列宽)*/
|
|
338
|
+
virtualX?: boolean;
|
|
339
|
+
/** 表格列配置 */
|
|
340
|
+
columns?: StkTableColumn<DT>[];
|
|
341
|
+
/** 表格数据源 */
|
|
342
|
+
dataSource?: DT[];
|
|
343
|
+
/** 行唯一键 (行唯一值不能为undefined) */
|
|
344
|
+
rowKey?: UniqKeyProp;
|
|
345
|
+
/** 列唯一键 */
|
|
346
|
+
colKey?: UniqKeyProp;
|
|
347
|
+
/** 空值展示文字 */
|
|
348
|
+
emptyCellText?: string | ((option: { row: DT; col: StkTableColumn<DT> }) => string);
|
|
349
|
+
/** 暂无数据兜底高度是否撑满 */
|
|
350
|
+
noDataFull?: boolean;
|
|
351
|
+
/** 是否展示暂无数据 */
|
|
352
|
+
showNoData?: boolean;
|
|
353
|
+
/** 是否服务端排序,true则不排序数据 */
|
|
354
|
+
sortRemote?: boolean;
|
|
355
|
+
/** 表头是否溢出展示... */
|
|
356
|
+
showHeaderOverflow?: boolean;
|
|
357
|
+
/** 表体溢出是否展示... */
|
|
358
|
+
showOverflow?: boolean;
|
|
359
|
+
/** 是否增加行hover class $*$ rename*/
|
|
360
|
+
showTrHoverClass?: boolean;
|
|
361
|
+
/** 是否高亮鼠标悬浮的单元格 */
|
|
362
|
+
cellHover?: boolean;
|
|
363
|
+
/** 是否高亮选中的单元格 */
|
|
364
|
+
cellActive?: boolean;
|
|
365
|
+
/** 单元格再次点击否可以取消选中 (cellActive=true)*/
|
|
366
|
+
selectedCellRevokable?: boolean;
|
|
367
|
+
/** 表头是否可拖动。支持回调函数。 */
|
|
368
|
+
headerDrag?: boolean | HeaderDragConfig;
|
|
369
|
+
/**
|
|
370
|
+
* 给行附加className<br>
|
|
371
|
+
* FIXME: 是否需要优化,因为不传此prop会使表格行一直执行空函数,是否有影响
|
|
372
|
+
*/
|
|
373
|
+
rowClassName?: (row: DT, i: number) => string;
|
|
374
|
+
/**
|
|
375
|
+
* 列宽是否可拖动(需要设置v-model:columns)<br>
|
|
376
|
+
* **不要设置**列minWidth,**必须**设置width<br>
|
|
377
|
+
* 列宽拖动时,每一列都必须要有width,且minWidth/maxWidth不生效。table width会变为"fit-content"。
|
|
378
|
+
* - 会自动更新props.columns中的with属性
|
|
379
|
+
*/
|
|
380
|
+
colResizable?: boolean | ColResizableConfig<DT>;
|
|
381
|
+
/** 可拖动至最小的列宽 */
|
|
382
|
+
colMinWidth?: number;
|
|
383
|
+
/**
|
|
384
|
+
* 单元格分割线。
|
|
385
|
+
* 默认横竖都有
|
|
386
|
+
* "h" - 仅展示横线
|
|
387
|
+
* "v" - 仅展示竖线
|
|
388
|
+
* "body-v" - 仅表体展示竖线
|
|
389
|
+
*/
|
|
390
|
+
bordered?: boolean | 'h' | 'v' | 'body-v';
|
|
391
|
+
/**
|
|
392
|
+
* 自动重新计算虚拟滚动高度宽度。默认true
|
|
393
|
+
* [非响应式]
|
|
394
|
+
* 传入方法表示resize后的回调
|
|
395
|
+
*/
|
|
396
|
+
autoResize?: boolean | (() => void);
|
|
397
|
+
/** 是否展示固定列阴影。为节省性能,默认false。 */
|
|
398
|
+
fixedColShadow?: boolean;
|
|
399
|
+
/** 优化vue2 滚动 */
|
|
400
|
+
optimizeVue2Scroll?: boolean;
|
|
401
|
+
/** 排序配置 */
|
|
402
|
+
sortConfig?: SortConfig<DT>;
|
|
403
|
+
/** 隐藏头部title。可传入colKey数组 */
|
|
404
|
+
hideHeaderTitle?: boolean | string[];
|
|
405
|
+
/** 高亮配置 */
|
|
406
|
+
highlightConfig?: HighlightConfig;
|
|
407
|
+
/** 序号列配置 */
|
|
408
|
+
seqConfig?: SeqConfig;
|
|
409
|
+
/** 展开行配置 */
|
|
410
|
+
expandConfig?: ExpandConfig;
|
|
411
|
+
/** 行拖动配置 */
|
|
412
|
+
dragRowConfig?: DragRowConfig;
|
|
413
|
+
/** 树形配置 */
|
|
414
|
+
treeConfig?: TreeConfig;
|
|
415
|
+
/**
|
|
416
|
+
* 固定头,固定列实现方式。(非响应式)
|
|
417
|
+
*
|
|
418
|
+
* relative:固定列只会放在props.columns的两侧。
|
|
419
|
+
* - 如果列宽会变动则谨慎使用。
|
|
420
|
+
* - 多级表头固定列慎用
|
|
421
|
+
*
|
|
422
|
+
* 低版本浏览器强制为'relative',
|
|
423
|
+
*/
|
|
424
|
+
cellFixedMode?: 'sticky' | 'relative';
|
|
425
|
+
/**
|
|
426
|
+
* 是否平滑滚动。default: chrome < 85 || chrome > 120 ? true : false
|
|
427
|
+
* - false: 使用 onwheel 滚动。为了防止滚动过快导致白屏。
|
|
428
|
+
* - true: 不使用 onwheel 滚动。鼠标滚轮滚动时更加平滑。滚动过快时会白屏。
|
|
429
|
+
*/
|
|
430
|
+
smoothScroll?: boolean;
|
|
431
|
+
/** 按整数行纵向滚动 */
|
|
432
|
+
scrollRowByRow?: boolean;
|
|
433
|
+
}>(),
|
|
434
|
+
{
|
|
435
|
+
width: '',
|
|
436
|
+
fixedMode: false,
|
|
437
|
+
stripe: false,
|
|
438
|
+
minWidth: '',
|
|
439
|
+
maxWidth: '',
|
|
440
|
+
headless: false,
|
|
441
|
+
theme: 'light',
|
|
442
|
+
rowHeight: DEFAULT_ROW_HEIGHT,
|
|
443
|
+
autoRowHeight: false,
|
|
444
|
+
rowHover: true,
|
|
445
|
+
rowActive: true,
|
|
446
|
+
rowCurrentRevokable: true,
|
|
447
|
+
headerRowHeight: DEFAULT_ROW_HEIGHT,
|
|
448
|
+
virtual: false,
|
|
449
|
+
virtualX: false,
|
|
450
|
+
columns: () => [],
|
|
451
|
+
dataSource: () => [],
|
|
452
|
+
rowKey: '',
|
|
453
|
+
emptyCellText: '--',
|
|
454
|
+
noDataFull: false,
|
|
455
|
+
showNoData: true,
|
|
456
|
+
sortRemote: false,
|
|
457
|
+
showHeaderOverflow: false,
|
|
458
|
+
showOverflow: false,
|
|
459
|
+
showTrHoverClass: false,
|
|
460
|
+
cellHover: false,
|
|
461
|
+
cellActive: false,
|
|
462
|
+
selectedCellRevokable: true,
|
|
463
|
+
headerDrag: false,
|
|
464
|
+
rowClassName: () => '',
|
|
465
|
+
colResizable: false,
|
|
466
|
+
colMinWidth: 10,
|
|
467
|
+
bordered: true,
|
|
468
|
+
autoResize: true,
|
|
469
|
+
fixedColShadow: false,
|
|
470
|
+
optimizeVue2Scroll: false,
|
|
471
|
+
sortConfig: () => ({
|
|
472
|
+
emptyToBottom: false,
|
|
473
|
+
stringLocaleCompare: false,
|
|
474
|
+
}),
|
|
475
|
+
hideHeaderTitle: false,
|
|
476
|
+
highlightConfig: () => ({}),
|
|
477
|
+
seqConfig: () => ({}),
|
|
478
|
+
expandConfig: () => ({}),
|
|
479
|
+
dragRowConfig: () => ({}),
|
|
480
|
+
treeConfig: () => ({}),
|
|
481
|
+
cellFixedMode: 'sticky',
|
|
482
|
+
smoothScroll: DEFAULT_SMOOTH_SCROLL,
|
|
483
|
+
scrollRowByRow: false,
|
|
484
|
+
},
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
const emits = defineEmits<{
|
|
488
|
+
/**
|
|
489
|
+
* 排序变更触发。defaultSort.dataIndex 找不到时,col 将返回null。
|
|
490
|
+
*
|
|
491
|
+
* ```(col: StkTableColumn<DT> | null, order: Order, data: DT[], sortConfig: SortConfig<DT>)```
|
|
492
|
+
*/
|
|
493
|
+
(e: 'sort-change', col: StkTableColumn<DT> | null, order: Order, data: DT[], sortConfig: SortConfig<DT>): void;
|
|
494
|
+
/**
|
|
495
|
+
* 一行点击事件
|
|
496
|
+
*
|
|
497
|
+
* ```(ev: MouseEvent, row: DT, data: { rowIndex: number })```
|
|
498
|
+
*/
|
|
499
|
+
(e: 'row-click', ev: MouseEvent, row: DT, data: { rowIndex: number }): void;
|
|
500
|
+
/**
|
|
501
|
+
* 选中一行触发。ev返回null表示不是点击事件触发的
|
|
502
|
+
*
|
|
503
|
+
* ```(ev: MouseEvent | null, row: DT | undefined, data: { select: boolean} })```
|
|
504
|
+
*/
|
|
505
|
+
(e: 'current-change', ev: MouseEvent | null, row: DT | undefined, data: { select: boolean }): void;
|
|
506
|
+
/**
|
|
507
|
+
* 选中单元格触发。ev返回null表示不是点击事件触发的
|
|
508
|
+
*
|
|
509
|
+
* ```(ev: MouseEvent | null, data: { select: boolean; row: DT | undefined; col: StkTableColumn<DT> | null })```
|
|
510
|
+
*/
|
|
511
|
+
(e: 'cell-selected', ev: MouseEvent | null, data: { select: boolean; row: DT | undefined; col: StkTableColumn<DT> | undefined }): void;
|
|
512
|
+
/**
|
|
513
|
+
* 行双击事件
|
|
514
|
+
*
|
|
515
|
+
* ```(ev: MouseEvent, row: DT, data: { rowIndex: number })```
|
|
516
|
+
*/
|
|
517
|
+
(e: 'row-dblclick', ev: MouseEvent, row: DT, data: { rowIndex: number }): void;
|
|
518
|
+
/**
|
|
519
|
+
* 表头右键事件
|
|
520
|
+
*
|
|
521
|
+
* ```(ev: MouseEvent)```
|
|
522
|
+
*/
|
|
523
|
+
(e: 'header-row-menu', ev: MouseEvent): void;
|
|
524
|
+
/**
|
|
525
|
+
* 表体行右键点击事件
|
|
526
|
+
*
|
|
527
|
+
* ```(ev: MouseEvent, row: DT, data: { rowIndex: number })```
|
|
528
|
+
*/
|
|
529
|
+
(e: 'row-menu', ev: MouseEvent, row: DT, data: { rowIndex: number }): void;
|
|
530
|
+
/**
|
|
531
|
+
* 单元格点击事件
|
|
532
|
+
*
|
|
533
|
+
* ```(ev: MouseEvent, row: DT, col: StkTableColumn<DT>, data: { rowIndex: number })```
|
|
534
|
+
*/
|
|
535
|
+
(e: 'cell-click', ev: MouseEvent, row: DT, col: StkTableColumn<DT>, data: { rowIndex: number }): void;
|
|
536
|
+
/**
|
|
537
|
+
* 单元格鼠标进入事件
|
|
538
|
+
*
|
|
539
|
+
* ```(ev: MouseEvent, row: DT, col: StkTableColumn<DT>)```
|
|
540
|
+
*/
|
|
541
|
+
(e: 'cell-mouseenter', ev: MouseEvent, row: DT, col: StkTableColumn<DT>): void;
|
|
542
|
+
/**
|
|
543
|
+
* 单元格鼠标移出事件
|
|
544
|
+
*
|
|
545
|
+
* ```(ev: MouseEvent, row: DT, col: StkTableColumn<DT>)```
|
|
546
|
+
*/
|
|
547
|
+
(e: 'cell-mouseleave', ev: MouseEvent, row: DT, col: StkTableColumn<DT>): void;
|
|
548
|
+
/**
|
|
549
|
+
* 单元格悬浮事件
|
|
550
|
+
*
|
|
551
|
+
* ```(ev: MouseEvent, row: DT, col: StkTableColumn<DT>)```
|
|
552
|
+
*/
|
|
553
|
+
(e: 'cell-mouseover', ev: MouseEvent, row: DT, col: StkTableColumn<DT>): void;
|
|
554
|
+
/**
|
|
555
|
+
* 单元格鼠标按下事件
|
|
556
|
+
*
|
|
557
|
+
* ```(ev: MouseEvent, row: DT, col: StkTableColumn<DT>, data: { rowIndex: number })```
|
|
558
|
+
*/
|
|
559
|
+
(e: 'cell-mousedown', ev: MouseEvent, row: DT, col: StkTableColumn<DT>, data: { rowIndex: number }): void;
|
|
560
|
+
/**
|
|
561
|
+
* 表头单元格点击事件
|
|
562
|
+
*
|
|
563
|
+
* ```(ev: MouseEvent, col: StkTableColumn<DT>)```
|
|
564
|
+
*/
|
|
565
|
+
(e: 'header-cell-click', ev: MouseEvent, col: StkTableColumn<DT>): void;
|
|
566
|
+
/**
|
|
567
|
+
* 表格滚动事件
|
|
568
|
+
*
|
|
569
|
+
* ```(ev: Event, data: { startIndex: number; endIndex: number })```
|
|
570
|
+
*/
|
|
571
|
+
(e: 'scroll', ev: Event, data: { startIndex: number; endIndex: number }): void;
|
|
572
|
+
/**
|
|
573
|
+
* 表格横向滚动事件
|
|
574
|
+
*
|
|
575
|
+
* ```(ev: Event)```
|
|
576
|
+
*/
|
|
577
|
+
(e: 'scroll-x', ev: Event): void;
|
|
578
|
+
/**
|
|
579
|
+
* 表头列拖动事件
|
|
580
|
+
*
|
|
581
|
+
* ```(dragStartKey: string, targetColKey: string)```
|
|
582
|
+
*/
|
|
583
|
+
(e: 'col-order-change', dragStartKey: string, targetColKey: string): void;
|
|
584
|
+
/**
|
|
585
|
+
* 表头列拖动开始
|
|
586
|
+
*
|
|
587
|
+
* ```(dragStartKey: string)```
|
|
588
|
+
*/
|
|
589
|
+
(e: 'th-drag-start', dragStartKey: string): void;
|
|
590
|
+
/**
|
|
591
|
+
* 表头列拖动drop
|
|
592
|
+
*
|
|
593
|
+
* ```(targetColKey: string)```
|
|
594
|
+
*/
|
|
595
|
+
(e: 'th-drop', targetColKey: string): void;
|
|
596
|
+
/**
|
|
597
|
+
* 行拖动事件
|
|
598
|
+
*
|
|
599
|
+
* ```(dragStartKey: string, targetRowKey: string)```
|
|
600
|
+
*/
|
|
601
|
+
(e: 'row-order-change', dragStartKey: string, targetRowKey: string): void;
|
|
602
|
+
/**
|
|
603
|
+
* 列宽变动时触发
|
|
604
|
+
*
|
|
605
|
+
* ```(col: StkTableColumn<DT>)```
|
|
606
|
+
*/
|
|
607
|
+
(e: 'col-resize', col: StkTableColumn<DT>): void;
|
|
608
|
+
/**
|
|
609
|
+
* 展开行触发
|
|
610
|
+
*
|
|
611
|
+
* ```( data: { expanded: boolean; row: DT; col: StkTableColumn<DT> })```
|
|
612
|
+
*/
|
|
613
|
+
(e: 'toggle-row-expand', data: { expanded: boolean; row: DT; col: StkTableColumn<DT> | null }): void;
|
|
614
|
+
/**
|
|
615
|
+
* 点击展开树行触发
|
|
616
|
+
*
|
|
617
|
+
* ```( data: { expanded: boolean; row: DT; col: StkTableColumn<DT> })```
|
|
618
|
+
*/
|
|
619
|
+
(e: 'toggle-tree-expand', data: { expanded: boolean; row: DT; col: StkTableColumn<DT> | null }): void;
|
|
620
|
+
/**
|
|
621
|
+
* v-model:columns col resize 时更新宽度
|
|
622
|
+
*/
|
|
623
|
+
(e: 'update:columns', cols: StkTableColumn<DT>[]): void;
|
|
624
|
+
}>();
|
|
625
|
+
|
|
626
|
+
// 仅支持vue3.3+
|
|
627
|
+
// const slots = defineSlots<{
|
|
628
|
+
// /** 表头插槽 */
|
|
629
|
+
// tableHeader(props: { col: StkTableColumn<DT> }): void;
|
|
630
|
+
// /** 空状态插槽 */
|
|
631
|
+
// empty(): void;
|
|
632
|
+
// }>();
|
|
633
|
+
|
|
634
|
+
const tableContainerRef = ref<HTMLDivElement>();
|
|
635
|
+
const theadRef = ref<HTMLElement>();
|
|
636
|
+
const colResizeIndicatorRef = ref<HTMLDivElement>();
|
|
637
|
+
const trRef = ref<HTMLTableRowElement[]>();
|
|
638
|
+
|
|
639
|
+
/** 是否使用 relative 固定头和列 */
|
|
640
|
+
const isRelativeMode = ref(IS_LEGACY_MODE ? true : props.cellFixedMode === 'relative');
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* 当前选中的一行
|
|
644
|
+
* - shallowRef: 使 currentRow.value === row 地址相同。防止rowKeyGen 的WeakMap key不一致。
|
|
645
|
+
*/
|
|
646
|
+
const currentRow = shallowRef<DT>();
|
|
647
|
+
/**
|
|
648
|
+
* 保存当前选中行的key<br>
|
|
649
|
+
* 原因:vue3 不用ref包dataSource时,row为原始对象,与currentItem(Ref)相比会不相等。
|
|
650
|
+
*/
|
|
651
|
+
const currentRowKey = ref<any>(void 0);
|
|
652
|
+
/** 当前选中的单元格key */
|
|
653
|
+
const currentSelectedCellKey = ref<any>(void 0);
|
|
654
|
+
/** 当前hover行 */
|
|
655
|
+
let currentHoverRow: DT | null = null;
|
|
656
|
+
/** 当前hover的行的key */
|
|
657
|
+
const currentHoverRowKey = ref(null);
|
|
658
|
+
/** 当前hover的列的key */
|
|
659
|
+
// const currentColHoverKey = ref(null);
|
|
660
|
+
|
|
661
|
+
/** sort colKey*/
|
|
662
|
+
let sortCol = ref<keyof DT>();
|
|
663
|
+
let sortOrderIndex = ref(0);
|
|
664
|
+
|
|
665
|
+
/** 排序切换顺序 */
|
|
666
|
+
const sortSwitchOrder: Order[] = [null, 'desc', 'asc'];
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* 表头.内容是 props.columns 的引用集合
|
|
670
|
+
* @eg
|
|
671
|
+
* ```js
|
|
672
|
+
* [
|
|
673
|
+
* [{dataInex:'id',...}], // 第0行列配置
|
|
674
|
+
* [], // 第一行列配置
|
|
675
|
+
* //...
|
|
676
|
+
* ]
|
|
677
|
+
* ```
|
|
678
|
+
*/
|
|
679
|
+
const tableHeaders = shallowRef<StkTableColumn<DT>[][]>([]);
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* 用于计算多级表头的tableHeaders。模拟rowSpan 位置的辅助数组。用于计算固定列。
|
|
683
|
+
* @eg
|
|
684
|
+
* ```
|
|
685
|
+
* | colspan3 |
|
|
686
|
+
* | rowspan2 | colspan2 |
|
|
687
|
+
* | rowspan2 | colspan1 | colspan1 |
|
|
688
|
+
* ```
|
|
689
|
+
* ---
|
|
690
|
+
* expect arr:
|
|
691
|
+
* ```
|
|
692
|
+
* const arr = [
|
|
693
|
+
* [col],
|
|
694
|
+
* [col2, col3],
|
|
695
|
+
* [col2, col4, col5],
|
|
696
|
+
* ]
|
|
697
|
+
* ```
|
|
698
|
+
*/
|
|
699
|
+
const tableHeadersForCalc = shallowRef<PrivateStkTableColumn<DT>[][]>([]);
|
|
700
|
+
|
|
701
|
+
/** 最后一行的tableHeaders.内容是 props.columns 的引用集合 */
|
|
702
|
+
const tableHeaderLast = computed(() => tableHeadersForCalc.value.slice(-1)[0] || []);
|
|
703
|
+
|
|
704
|
+
const isTreeData = computed(() => {
|
|
705
|
+
return props.columns.some(col => col.type === 'tree-node');
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
const dataSourceCopy = shallowRef<DT[]>([]);
|
|
709
|
+
|
|
710
|
+
const rowKeyGenComputed = computed(() => {
|
|
711
|
+
const { rowKey } = props;
|
|
712
|
+
if (typeof rowKey === 'function') {
|
|
713
|
+
return (row: DT) => (rowKey as (row: DT) => string)(row);
|
|
714
|
+
} else {
|
|
715
|
+
return (row: DT) => (row as any)[rowKey];
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
const colKeyGen = computed<(col: StkTableColumn<DT>) => string>(() => {
|
|
720
|
+
const { colKey } = props;
|
|
721
|
+
if (colKey === void 0) {
|
|
722
|
+
return col => col.key || col.dataIndex;
|
|
723
|
+
} else if (typeof colKey === 'function') {
|
|
724
|
+
return col => (colKey as (col: StkTableColumn<DT>) => string)(col);
|
|
725
|
+
} else {
|
|
726
|
+
return col => (col as any)[colKey];
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
const getEmptyCellText = computed(() => {
|
|
731
|
+
const { emptyCellText } = props;
|
|
732
|
+
if (typeof emptyCellText === 'string') {
|
|
733
|
+
return () => emptyCellText;
|
|
734
|
+
} else {
|
|
735
|
+
return (col: StkTableColumn<DT>, row: DT) => emptyCellText({ row, col });
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
const rowKeyGenCache = new WeakMap();
|
|
740
|
+
|
|
741
|
+
const { onThDragStart, onThDragOver, onThDrop, isHeaderDraggable } = useThDrag({ props, emits, colKeyGen });
|
|
742
|
+
|
|
743
|
+
const { onTrDragStart, onTrDrop, onTrDragOver, onTrDragEnd, onTrDragEnter } = useTrDrag({ props, emits, dataSourceCopy });
|
|
744
|
+
|
|
745
|
+
const {
|
|
746
|
+
virtualScroll,
|
|
747
|
+
virtualScrollX,
|
|
748
|
+
virtual_on,
|
|
749
|
+
virtual_dataSourcePart,
|
|
750
|
+
virtual_offsetBottom,
|
|
751
|
+
virtualX_on,
|
|
752
|
+
virtualX_columnPart,
|
|
753
|
+
virtualX_offsetRight,
|
|
754
|
+
initVirtualScroll,
|
|
755
|
+
initVirtualScrollY,
|
|
756
|
+
initVirtualScrollX,
|
|
757
|
+
updateVirtualScrollY,
|
|
758
|
+
updateVirtualScrollX,
|
|
759
|
+
setAutoHeight,
|
|
760
|
+
clearAllAutoHeight,
|
|
761
|
+
} = useVirtualScroll({ tableContainerRef, trRef, props, dataSourceCopy, tableHeaderLast, tableHeaders, rowKeyGen });
|
|
762
|
+
|
|
763
|
+
const getFixedColPosition = useGetFixedColPosition({ colKeyGen, tableHeadersForCalc });
|
|
764
|
+
|
|
765
|
+
const getFixedStyle = useFixedStyle<DT>({
|
|
766
|
+
props,
|
|
767
|
+
isRelativeMode,
|
|
768
|
+
getFixedColPosition,
|
|
769
|
+
virtualScroll,
|
|
770
|
+
virtualScrollX,
|
|
771
|
+
virtualX_on,
|
|
772
|
+
virtualX_offsetRight,
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
const { highlightSteps, setHighlightDimCell, setHighlightDimRow } = useHighlight({ props, stkTableId, tableContainerRef });
|
|
776
|
+
|
|
777
|
+
if (props.autoResize) {
|
|
778
|
+
useAutoResize({ tableContainerRef, initVirtualScroll, props, debounceMs: 200 });
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/** 键盘箭头滚动 */
|
|
782
|
+
useKeyboardArrowScroll(tableContainerRef, {
|
|
783
|
+
props,
|
|
784
|
+
scrollTo,
|
|
785
|
+
virtualScroll,
|
|
786
|
+
virtualScrollX,
|
|
787
|
+
tableHeaders,
|
|
788
|
+
virtual_on,
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
/** 固定列处理 */
|
|
792
|
+
const { fixedCols, fixedColClassMap, updateFixedShadow } = useFixedCol({
|
|
793
|
+
props,
|
|
794
|
+
colKeyGen,
|
|
795
|
+
getFixedColPosition,
|
|
796
|
+
tableContainerRef,
|
|
797
|
+
tableHeaders,
|
|
798
|
+
tableHeadersForCalc,
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
const { isColResizing, onThResizeMouseDown, colResizeOn } = useColResize({
|
|
802
|
+
props,
|
|
803
|
+
emits,
|
|
804
|
+
colKeyGen,
|
|
805
|
+
colResizeIndicatorRef,
|
|
806
|
+
tableContainerRef,
|
|
807
|
+
tableHeaderLast,
|
|
808
|
+
fixedCols,
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
const { toggleExpandRow, setRowExpand } = useRowExpand({ dataSourceCopy, rowKeyGen, emits });
|
|
812
|
+
|
|
813
|
+
const { toggleTreeNode, setTreeExpand, flatTreeData } = useTree({ props, dataSourceCopy, rowKeyGen, emits });
|
|
814
|
+
|
|
815
|
+
watch(
|
|
816
|
+
() => props.columns,
|
|
817
|
+
() => {
|
|
818
|
+
dealColumns();
|
|
819
|
+
// initVirtualScrollX 需要获取容器滚动宽度等。必须等渲染完成后再调用。因此使用nextTick。
|
|
820
|
+
nextTick(() => {
|
|
821
|
+
initVirtualScrollX();
|
|
822
|
+
updateFixedShadow();
|
|
823
|
+
});
|
|
824
|
+
},
|
|
825
|
+
);
|
|
826
|
+
watch(
|
|
827
|
+
() => props.virtual,
|
|
828
|
+
() => {
|
|
829
|
+
nextTick(() => {
|
|
830
|
+
initVirtualScrollY();
|
|
831
|
+
});
|
|
832
|
+
},
|
|
833
|
+
);
|
|
834
|
+
|
|
835
|
+
watch(
|
|
836
|
+
() => props.rowHeight,
|
|
837
|
+
() => {
|
|
838
|
+
initVirtualScrollY();
|
|
839
|
+
},
|
|
840
|
+
);
|
|
841
|
+
|
|
842
|
+
watch(
|
|
843
|
+
() => props.virtualX,
|
|
844
|
+
() => {
|
|
845
|
+
dealColumns();
|
|
846
|
+
// initVirtualScrollX 需要获取容器滚动宽度等。必须等渲染完成后再调用。因此使用nextTick。
|
|
847
|
+
nextTick(() => {
|
|
848
|
+
initVirtualScrollX();
|
|
849
|
+
updateFixedShadow();
|
|
850
|
+
});
|
|
851
|
+
},
|
|
852
|
+
);
|
|
853
|
+
|
|
854
|
+
watch(
|
|
855
|
+
() => props.dataSource,
|
|
856
|
+
val => {
|
|
857
|
+
if (!Array.isArray(val)) {
|
|
858
|
+
console.warn('invalid dataSource');
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
/** 是否需要更新ScrollY,这里由于watch newValue与oldValue 的长度一样,因此需要这样使用 */
|
|
862
|
+
let needInitVirtualScrollY = false;
|
|
863
|
+
if (dataSourceCopy.value.length !== val.length) {
|
|
864
|
+
needInitVirtualScrollY = true;
|
|
865
|
+
}
|
|
866
|
+
initDataSource(val);
|
|
867
|
+
// if data length is not change, not init virtual scroll
|
|
868
|
+
if (needInitVirtualScrollY) {
|
|
869
|
+
// wait for table render,initVirtualScrollY has get `dom` operation.
|
|
870
|
+
nextTick(() => initVirtualScrollY());
|
|
871
|
+
}
|
|
872
|
+
const sortColValue = sortCol.value;
|
|
873
|
+
if (sortColValue) {
|
|
874
|
+
// sort
|
|
875
|
+
const colKey = colKeyGen.value;
|
|
876
|
+
const column = tableHeaderLast.value.find(it => colKey(it) === sortColValue);
|
|
877
|
+
onColumnSort(column, false);
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
);
|
|
881
|
+
|
|
882
|
+
watch(
|
|
883
|
+
() => props.fixedColShadow,
|
|
884
|
+
() => updateFixedShadow(),
|
|
885
|
+
);
|
|
886
|
+
|
|
887
|
+
dealColumns();
|
|
888
|
+
initDataSource();
|
|
889
|
+
|
|
890
|
+
onMounted(() => {
|
|
891
|
+
initVirtualScroll();
|
|
892
|
+
updateFixedShadow();
|
|
893
|
+
dealDefaultSorter();
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
function initDataSource(v = props.dataSource) {
|
|
897
|
+
let dataSourceTemp = v.slice(); // shallow copy
|
|
898
|
+
if (isTreeData.value) {
|
|
899
|
+
// only tree data need flat
|
|
900
|
+
dataSourceTemp = flatTreeData(dataSourceTemp);
|
|
901
|
+
}
|
|
902
|
+
dataSourceCopy.value = dataSourceTemp;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
function dealDefaultSorter() {
|
|
906
|
+
if (!props.sortConfig.defaultSort) return;
|
|
907
|
+
const { key, dataIndex, order, silent } = { silent: false, ...props.sortConfig.defaultSort };
|
|
908
|
+
setSorter((key || dataIndex) as string, order, { force: false, silent });
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* deal multi-level header
|
|
913
|
+
*/
|
|
914
|
+
function dealColumns() {
|
|
915
|
+
// reset
|
|
916
|
+
const tableHeadersTemp: StkTableColumn<DT>[][] = [];
|
|
917
|
+
const tableHeadersForCalcTemp: StkTableColumn<DT>[][] = [];
|
|
918
|
+
let copyColumn = props.columns; // do not deep clone
|
|
919
|
+
// relative 模式下不支持sticky列。因此就放在左右两侧。
|
|
920
|
+
if (isRelativeMode.value) {
|
|
921
|
+
let leftCol: StkTableColumn<DT>[] = [];
|
|
922
|
+
let centerCol: StkTableColumn<DT>[] = [];
|
|
923
|
+
let rightCol: StkTableColumn<DT>[] = [];
|
|
924
|
+
copyColumn.forEach(col => {
|
|
925
|
+
if (col.fixed === 'left') {
|
|
926
|
+
leftCol.push(col);
|
|
927
|
+
} else if (col.fixed === 'right') {
|
|
928
|
+
rightCol.push(col);
|
|
929
|
+
} else {
|
|
930
|
+
centerCol.push(col);
|
|
931
|
+
}
|
|
932
|
+
});
|
|
933
|
+
copyColumn = leftCol.concat(centerCol).concat(rightCol);
|
|
934
|
+
}
|
|
935
|
+
const maxDeep = howDeepTheHeader(copyColumn);
|
|
936
|
+
|
|
937
|
+
if (maxDeep > 0 && props.virtualX) {
|
|
938
|
+
console.error('StkTableVue:多级表头不支持横向虚拟滚动!');
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
for (let i = 0; i <= maxDeep; i++) {
|
|
942
|
+
tableHeadersTemp[i] = [];
|
|
943
|
+
tableHeadersForCalcTemp[i] = [];
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* flat columns
|
|
948
|
+
* @param arr
|
|
949
|
+
* @param depth 深度
|
|
950
|
+
* @param parent 父节点引用,用于构建双向链表。
|
|
951
|
+
* @param parentFixed 父节点固定列继承。
|
|
952
|
+
*/
|
|
953
|
+
function flat(
|
|
954
|
+
arr: PrivateStkTableColumn<DT>[],
|
|
955
|
+
parent: PrivateStkTableColumn<DT> | null,
|
|
956
|
+
depth = 0 /* , parentFixed: 'left' | 'right' | null = null */,
|
|
957
|
+
) {
|
|
958
|
+
/** 所有子节点数量 */
|
|
959
|
+
let allChildrenLen = 0;
|
|
960
|
+
let allChildrenWidthSum = 0;
|
|
961
|
+
arr.forEach(col => {
|
|
962
|
+
// TODO: 继承父节点固定列配置
|
|
963
|
+
// if (parentFixed) {
|
|
964
|
+
// col.fixed = parentFixed;
|
|
965
|
+
// }
|
|
966
|
+
col.__PARENT__ = parent;
|
|
967
|
+
/** 一列中的子节点数量 */
|
|
968
|
+
let colChildrenLen = 1;
|
|
969
|
+
/** 多级表头的父节点宽度,通过叶子节点宽度计算得到 */
|
|
970
|
+
let colWidth = 0;
|
|
971
|
+
if (col.children) {
|
|
972
|
+
// DFS
|
|
973
|
+
const [len, widthSum] = flat(col.children, col, depth + 1 /* , col.fixed */);
|
|
974
|
+
colChildrenLen = len;
|
|
975
|
+
colWidth = widthSum;
|
|
976
|
+
tableHeadersForCalcTemp[depth].push(col);
|
|
977
|
+
} else {
|
|
978
|
+
colWidth = getColWidth(col);
|
|
979
|
+
for (let i = depth; i <= maxDeep; i++) {
|
|
980
|
+
// 如有rowSpan 向下复制一个表头col,用于计算固定列
|
|
981
|
+
tableHeadersForCalcTemp[i].push(col);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
// 回溯
|
|
985
|
+
col.__WIDTH__ = colWidth; //记录计算的列宽
|
|
986
|
+
tableHeadersTemp[depth].push(col);
|
|
987
|
+
const rowSpan = col.children ? 1 : maxDeep - depth + 1;
|
|
988
|
+
const colSpan = colChildrenLen;
|
|
989
|
+
if (rowSpan > 1) {
|
|
990
|
+
col.rowSpan = rowSpan;
|
|
991
|
+
}
|
|
992
|
+
if (colSpan > 1) {
|
|
993
|
+
col.colSpan = colSpan;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
allChildrenLen += colChildrenLen;
|
|
997
|
+
allChildrenWidthSum += colWidth;
|
|
998
|
+
});
|
|
999
|
+
return [allChildrenLen, allChildrenWidthSum];
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
flat(copyColumn, null);
|
|
1003
|
+
tableHeaders.value = tableHeadersTemp;
|
|
1004
|
+
tableHeadersForCalc.value = tableHeadersForCalcTemp;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
/**
|
|
1008
|
+
* 行唯一值生成
|
|
1009
|
+
*/
|
|
1010
|
+
function rowKeyGen(row: DT | null | undefined) {
|
|
1011
|
+
if (!row) return row;
|
|
1012
|
+
let key = rowKeyGenCache.get(row) || (row as PrivateRowDT).__ROW_KEY__;
|
|
1013
|
+
if (!key) {
|
|
1014
|
+
key = rowKeyGenComputed.value(row);
|
|
1015
|
+
|
|
1016
|
+
if (key === void 0) {
|
|
1017
|
+
// key为undefined时,不应该高亮行。因此重新生成key
|
|
1018
|
+
key = Math.random().toString();
|
|
1019
|
+
}
|
|
1020
|
+
rowKeyGenCache.set(row, key);
|
|
1021
|
+
}
|
|
1022
|
+
return key;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/** 单元格唯一值 */
|
|
1026
|
+
function cellKeyGen(row: DT | null | undefined, col: StkTableColumn<DT>) {
|
|
1027
|
+
return rowKeyGen(row) + CELL_KEY_SEPARATE + colKeyGen.value(col);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
/** 单元格样式 */
|
|
1031
|
+
const cellStyleMap = computed(() => {
|
|
1032
|
+
const thMap = new Map();
|
|
1033
|
+
const tdMap = new Map();
|
|
1034
|
+
const { virtualX, colResizable } = props;
|
|
1035
|
+
tableHeaders.value.forEach((cols, depth) => {
|
|
1036
|
+
cols.forEach(col => {
|
|
1037
|
+
const width = virtualX ? getCalculatedColWidth(col) + 'px' : transformWidthToStr(col.width);
|
|
1038
|
+
const style: CSSProperties = {
|
|
1039
|
+
width,
|
|
1040
|
+
};
|
|
1041
|
+
if (colResizable) {
|
|
1042
|
+
// 如果要调整列宽,列宽必须固定。
|
|
1043
|
+
style.minWidth = width;
|
|
1044
|
+
style.maxWidth = width;
|
|
1045
|
+
} else {
|
|
1046
|
+
style.minWidth = transformWidthToStr(col.minWidth) ?? width;
|
|
1047
|
+
style.maxWidth = transformWidthToStr(col.maxWidth) ?? width;
|
|
1048
|
+
}
|
|
1049
|
+
const colKey = colKeyGen.value(col);
|
|
1050
|
+
thMap.set(colKey, Object.assign({ textAlign: col.headerAlign }, style, getFixedStyle(TagType.TH, col, depth)));
|
|
1051
|
+
tdMap.set(colKey, Object.assign({ textAlign: col.align }, style, getFixedStyle(TagType.TD, col, depth)));
|
|
1052
|
+
});
|
|
1053
|
+
});
|
|
1054
|
+
return {
|
|
1055
|
+
[TagType.TH]: thMap,
|
|
1056
|
+
[TagType.TD]: tdMap,
|
|
1057
|
+
};
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
function getRowIndex(rowIndex: number) {
|
|
1061
|
+
return rowIndex + (virtual_on ? virtualScroll.value.startIndex : 0);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/** th title */
|
|
1065
|
+
function getHeaderTitle(col: StkTableColumn<DT>): string {
|
|
1066
|
+
const colKey = colKeyGen.value(col);
|
|
1067
|
+
// hide title
|
|
1068
|
+
if (props.hideHeaderTitle === true || (Array.isArray(props.hideHeaderTitle) && props.hideHeaderTitle.includes(colKey))) {
|
|
1069
|
+
return '';
|
|
1070
|
+
}
|
|
1071
|
+
return col.title || '';
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* 表头点击排序
|
|
1076
|
+
* @param click 是否为点击表头触发
|
|
1077
|
+
* @param options.force sort-remote 开启后是否强制排序
|
|
1078
|
+
* @param options.emit 是否触发回调
|
|
1079
|
+
*/
|
|
1080
|
+
function onColumnSort(col: StkTableColumn<DT> | undefined | null, click = true, options: { force?: boolean; emit?: boolean } = {}) {
|
|
1081
|
+
if (!col) {
|
|
1082
|
+
console.warn('onColumnSort: not found col:', col);
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
if (!col.sorter && click) {
|
|
1086
|
+
// 点击表头触发的排序,如果列没有配置sorter则不处理。setSorter 触发的排序则保持通行。
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
options = { force: false, emit: false, ...options };
|
|
1090
|
+
const colKey = colKeyGen.value(col);
|
|
1091
|
+
if (sortCol.value !== colKey) {
|
|
1092
|
+
// 改变排序的列时,重置排序
|
|
1093
|
+
sortCol.value = colKey;
|
|
1094
|
+
sortOrderIndex.value = 0;
|
|
1095
|
+
}
|
|
1096
|
+
const prevOrder = sortSwitchOrder[sortOrderIndex.value];
|
|
1097
|
+
if (click) sortOrderIndex.value++;
|
|
1098
|
+
sortOrderIndex.value = sortOrderIndex.value % 3;
|
|
1099
|
+
|
|
1100
|
+
let order = sortSwitchOrder[sortOrderIndex.value];
|
|
1101
|
+
const sortConfig = { ...props.sortConfig, ...col.sortConfig };
|
|
1102
|
+
const defaultSort = sortConfig.defaultSort;
|
|
1103
|
+
const colKeyGenValue = colKeyGen.value;
|
|
1104
|
+
|
|
1105
|
+
if (!order && defaultSort) {
|
|
1106
|
+
// if no order ,use default order
|
|
1107
|
+
const defaultColKey = defaultSort.key || defaultSort.dataIndex;
|
|
1108
|
+
if (!defaultColKey) {
|
|
1109
|
+
console.error('sortConfig.defaultSort key or dataIndex is required');
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
if (colKey === defaultColKey && prevOrder === defaultSort.order) {
|
|
1113
|
+
order = sortSwitchOrder.find(o => o !== defaultSort.order && o) as Order;
|
|
1114
|
+
} else {
|
|
1115
|
+
order = defaultSort.order;
|
|
1116
|
+
}
|
|
1117
|
+
sortOrderIndex.value = sortSwitchOrder.indexOf(order);
|
|
1118
|
+
sortCol.value = defaultColKey as string;
|
|
1119
|
+
col = null;
|
|
1120
|
+
for (const row of tableHeaders.value) {
|
|
1121
|
+
const c = row.find(item => colKeyGenValue(item) === defaultColKey);
|
|
1122
|
+
if (c) {
|
|
1123
|
+
col = c;
|
|
1124
|
+
break;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
if (!props.sortRemote || options.force) {
|
|
1129
|
+
const sortOption = col || defaultSort;
|
|
1130
|
+
if (sortOption) {
|
|
1131
|
+
dataSourceCopy.value = tableSort(sortOption, order, props.dataSource, sortConfig);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
// 只有点击才触发事件
|
|
1135
|
+
if (click || options.emit) {
|
|
1136
|
+
emits('sort-change', col, order, toRaw(dataSourceCopy.value), sortConfig);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
function onRowClick(e: MouseEvent, row: DT, rowIndex: number) {
|
|
1141
|
+
emits('row-click', e, row, { rowIndex });
|
|
1142
|
+
const isCurrentRow = props.rowKey ? currentRowKey.value === rowKeyGen(row) : currentRow.value === row;
|
|
1143
|
+
if (isCurrentRow) {
|
|
1144
|
+
if (!props.rowCurrentRevokable) {
|
|
1145
|
+
// 不可取消
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
// 点击同一行,取消当前选中行。
|
|
1149
|
+
currentRow.value = void 0;
|
|
1150
|
+
currentRowKey.value = void 0;
|
|
1151
|
+
} else {
|
|
1152
|
+
currentRow.value = row;
|
|
1153
|
+
currentRowKey.value = rowKeyGen(row);
|
|
1154
|
+
}
|
|
1155
|
+
emits('current-change', e, row, { select: !isCurrentRow });
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
function onRowDblclick(e: MouseEvent, row: DT, rowIndex: number) {
|
|
1159
|
+
emits('row-dblclick', e, row, { rowIndex });
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/** 表头行右键 */
|
|
1163
|
+
function onHeaderMenu(e: MouseEvent) {
|
|
1164
|
+
emits('header-row-menu', e);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
/** 表体行右键 */
|
|
1168
|
+
function onRowMenu(e: MouseEvent, row: DT, rowIndex: number) {
|
|
1169
|
+
emits('row-menu', e, row, { rowIndex });
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
/**
|
|
1173
|
+
* proxy events
|
|
1174
|
+
*/
|
|
1175
|
+
// function onTbodyClick(e: MouseEvent, type: 1 | 2) {
|
|
1176
|
+
// const el = (e.target as HTMLElement).closest<HTMLElement>('td,tr');
|
|
1177
|
+
// if (!el) return;
|
|
1178
|
+
// if (el.tagName === 'TD') {
|
|
1179
|
+
// const [rowKey, colKey] = el.dataset.cellKey?.split(CELL_KEY_SEPARATE) || [];
|
|
1180
|
+
// const row = dataSourceCopy.value.find(item => rowKeyGen(item) === rowKey);
|
|
1181
|
+
// const col = tableHeaderLast.value.find(item => colKeyGen.value(item) === colKey);
|
|
1182
|
+
// if (col) {
|
|
1183
|
+
// if (col.type === 'expand') {
|
|
1184
|
+
// toggleExpandRow(row, col);
|
|
1185
|
+
// }
|
|
1186
|
+
// if (type === 1) {
|
|
1187
|
+
// onCellClick(e, row, col);
|
|
1188
|
+
// } else if (type === 2) {
|
|
1189
|
+
// onCellMouseDown(e, row, col);
|
|
1190
|
+
// }
|
|
1191
|
+
// }
|
|
1192
|
+
// if (type === 1) {
|
|
1193
|
+
// onRowClick(e, row);
|
|
1194
|
+
// }
|
|
1195
|
+
// } else if (el.tagName === 'TR') {
|
|
1196
|
+
// const rowKey = el.dataset.rowKey;
|
|
1197
|
+
// const row = dataSourceCopy.value.find(item => rowKeyGen(item) === rowKey);
|
|
1198
|
+
// onRowClick(e, row);
|
|
1199
|
+
// }
|
|
1200
|
+
// }
|
|
1201
|
+
|
|
1202
|
+
function triangleClick(e: MouseEvent, row: DT, col: StkTableColumn<DT>) {
|
|
1203
|
+
if (col.type === 'expand') {
|
|
1204
|
+
toggleExpandRow(row, col);
|
|
1205
|
+
} else if (col.type === 'tree-node') {
|
|
1206
|
+
toggleTreeNode(row, col);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
/** 单元格单击 */
|
|
1211
|
+
function onCellClick(e: MouseEvent, row: DT, col: StkTableColumn<DT>, rowIndex: number) {
|
|
1212
|
+
if (props.cellActive) {
|
|
1213
|
+
const cellKey = cellKeyGen(row, col);
|
|
1214
|
+
const result = { row, col, select: false, rowIndex };
|
|
1215
|
+
if (props.selectedCellRevokable && currentSelectedCellKey.value === cellKey) {
|
|
1216
|
+
currentSelectedCellKey.value = void 0;
|
|
1217
|
+
} else {
|
|
1218
|
+
currentSelectedCellKey.value = cellKey;
|
|
1219
|
+
result.select = true;
|
|
1220
|
+
}
|
|
1221
|
+
emits('cell-selected', e, result);
|
|
1222
|
+
}
|
|
1223
|
+
emits('cell-click', e, row, col, { rowIndex });
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
/** 表头单元格单击 */
|
|
1227
|
+
function onHeaderCellClick(e: MouseEvent, col: StkTableColumn<DT>) {
|
|
1228
|
+
emits('header-cell-click', e, col);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
/** td mouseenter */
|
|
1232
|
+
function onCellMouseEnter(e: MouseEvent, row: DT, col: StkTableColumn<DT>) {
|
|
1233
|
+
emits('cell-mouseenter', e, row, col);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
/** td mouseleave */
|
|
1237
|
+
function onCellMouseLeave(e: MouseEvent, row: DT, col: StkTableColumn<DT>) {
|
|
1238
|
+
emits('cell-mouseleave', e, row, col);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
/** td mouseover event */
|
|
1242
|
+
function onCellMouseOver(e: MouseEvent, row: DT, col: StkTableColumn<DT>) {
|
|
1243
|
+
emits('cell-mouseover', e, row, col);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
function onCellMouseDown(e: MouseEvent, row: DT, col: StkTableColumn<DT>, rowIndex: number) {
|
|
1247
|
+
emits('cell-mousedown', e, row, col, { rowIndex });
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/**
|
|
1251
|
+
* 鼠标滚轮事件监听。代理滚轮事件,防止滚动过快出现白屏。
|
|
1252
|
+
* @param e
|
|
1253
|
+
*/
|
|
1254
|
+
function onTableWheel(e: WheelEvent) {
|
|
1255
|
+
if (props.smoothScroll) {
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
if (isColResizing.value) {
|
|
1259
|
+
// 正在调整列宽时,不允许用户滚动
|
|
1260
|
+
e.stopPropagation();
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
// #region ---- 控制滚动,防止出现白屏--
|
|
1264
|
+
const dom = tableContainerRef.value;
|
|
1265
|
+
if (!dom) return;
|
|
1266
|
+
const { containerHeight, scrollTop, scrollHeight } = virtualScroll.value;
|
|
1267
|
+
const { containerWidth, scrollLeft, scrollWidth } = virtualScrollX.value;
|
|
1268
|
+
/** 是否滚动在下面 */
|
|
1269
|
+
const isScrollBottom = scrollHeight - containerHeight - scrollTop < 10;
|
|
1270
|
+
/** 是否滚动在右侧 */
|
|
1271
|
+
const isScrollRight = scrollWidth - containerWidth - scrollLeft < 10;
|
|
1272
|
+
const { deltaY, deltaX } = e;
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* 只有虚拟滚动时,才要用 wheel 代理scroll,防止滚动过快导致的白屏。
|
|
1276
|
+
* 滚动条在边界情况时,not preventDefault 。因为会阻塞父级滚动条滚动。
|
|
1277
|
+
*/
|
|
1278
|
+
if (virtual_on && deltaY) {
|
|
1279
|
+
if ((deltaY > 0 && !isScrollBottom) || (deltaY < 0 && scrollTop > 0)) {
|
|
1280
|
+
e.preventDefault();
|
|
1281
|
+
}
|
|
1282
|
+
dom.scrollTop += deltaY;
|
|
1283
|
+
}
|
|
1284
|
+
if (virtualX_on && deltaX) {
|
|
1285
|
+
if ((deltaX > 0 && !isScrollRight) || (deltaX < 0 && scrollLeft > 0)) {
|
|
1286
|
+
e.preventDefault();
|
|
1287
|
+
}
|
|
1288
|
+
dom.scrollLeft += deltaX;
|
|
1289
|
+
}
|
|
1290
|
+
//#endregion
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* 滚动条监听
|
|
1295
|
+
* @param e scrollEvent
|
|
1296
|
+
*/
|
|
1297
|
+
function onTableScroll(e: Event) {
|
|
1298
|
+
if (!e?.target) return;
|
|
1299
|
+
|
|
1300
|
+
const { scrollTop, scrollLeft } = e.target as HTMLElement;
|
|
1301
|
+
const { scrollTop: vScrollTop, startIndex, endIndex } = virtualScroll.value;
|
|
1302
|
+
const { scrollLeft: vScrollLeft } = virtualScrollX.value;
|
|
1303
|
+
const isYScroll = scrollTop !== vScrollTop;
|
|
1304
|
+
const isXScroll = scrollLeft !== vScrollLeft;
|
|
1305
|
+
|
|
1306
|
+
// 纵向滚动有变化
|
|
1307
|
+
if (isYScroll) {
|
|
1308
|
+
updateVirtualScrollY(scrollTop);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// 横向滚动有变化
|
|
1312
|
+
if (isXScroll) {
|
|
1313
|
+
if (virtualX_on.value) {
|
|
1314
|
+
updateVirtualScrollX(scrollLeft);
|
|
1315
|
+
} else {
|
|
1316
|
+
// 非虚拟滚动也记录一下滚动条位置。用于判断isXScroll
|
|
1317
|
+
virtualScrollX.value.scrollLeft = scrollLeft;
|
|
1318
|
+
}
|
|
1319
|
+
updateFixedShadow(virtualScrollX);
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
if (isYScroll) {
|
|
1323
|
+
emits('scroll', e, { startIndex, endIndex });
|
|
1324
|
+
}
|
|
1325
|
+
if (isXScroll) {
|
|
1326
|
+
emits('scroll-x', e);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
/** tr hover */
|
|
1331
|
+
function onTrMouseOver(_e: MouseEvent, row: DT) {
|
|
1332
|
+
if (currentHoverRow === row) return;
|
|
1333
|
+
currentHoverRow = row;
|
|
1334
|
+
currentHoverRowKey.value = rowKeyGen(row);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
/**
|
|
1338
|
+
* 选中一行
|
|
1339
|
+
* @param {string} rowKeyOrRow selected rowKey, undefined to unselect
|
|
1340
|
+
* @param {boolean} option.silent if set true not emit `current-change`. default:false
|
|
1341
|
+
*/
|
|
1342
|
+
function setCurrentRow(rowKeyOrRow: string | undefined | DT, option = { silent: false }) {
|
|
1343
|
+
if (!dataSourceCopy.value.length) return;
|
|
1344
|
+
const select = rowKeyOrRow !== void 0;
|
|
1345
|
+
if (!select) {
|
|
1346
|
+
currentRow.value = void 0;
|
|
1347
|
+
currentRowKey.value = void 0;
|
|
1348
|
+
} else if (typeof rowKeyOrRow === 'string') {
|
|
1349
|
+
const row = dataSourceCopy.value.find(it => rowKeyGen(it) === rowKeyOrRow);
|
|
1350
|
+
if (!row) {
|
|
1351
|
+
console.warn('setCurrentRow failed.rowKey:', rowKeyOrRow);
|
|
1352
|
+
return;
|
|
1353
|
+
}
|
|
1354
|
+
currentRow.value = row;
|
|
1355
|
+
currentRowKey.value = rowKeyOrRow;
|
|
1356
|
+
} else {
|
|
1357
|
+
currentRow.value = rowKeyOrRow;
|
|
1358
|
+
currentRowKey.value = rowKeyGen(rowKeyOrRow);
|
|
1359
|
+
}
|
|
1360
|
+
if (!option.silent) {
|
|
1361
|
+
emits('current-change', /** no Event */ null, currentRow.value, { select });
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
/**
|
|
1366
|
+
* set highlight active cell (props.cellActive=true)
|
|
1367
|
+
* @param row row if undefined, clear highlight
|
|
1368
|
+
* @param col column
|
|
1369
|
+
* @param option.silent if emit current-change. default:false(not emit `current-change`)
|
|
1370
|
+
*/
|
|
1371
|
+
function setSelectedCell(row?: DT, col?: StkTableColumn<DT>, option = { silent: false }) {
|
|
1372
|
+
if (!dataSourceCopy.value.length) return;
|
|
1373
|
+
const select = row !== void 0 && col !== void 0;
|
|
1374
|
+
currentSelectedCellKey.value = select ? cellKeyGen(row, col) : void 0;
|
|
1375
|
+
if (!option.silent) {
|
|
1376
|
+
emits('cell-selected', /** no Event */ null, { row, col, select });
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
/**
|
|
1381
|
+
* 设置表头排序状态。
|
|
1382
|
+
* @param colKey 列唯一键字段。如果你想要取消排序状态,请使用`resetSorter`
|
|
1383
|
+
* @param order 正序倒序
|
|
1384
|
+
* @param option.sortOption 指定排序参数。同 StkTableColumn 中排序相关字段。建议从columns中find得到。
|
|
1385
|
+
* @param option.sort 是否触发排序-默认true
|
|
1386
|
+
* @param option.silent 是否禁止触发回调-默认true
|
|
1387
|
+
* @param option.force 是否触发排序-默认true
|
|
1388
|
+
* @return 表格数据
|
|
1389
|
+
*/
|
|
1390
|
+
function setSorter(colKey: string, order: Order, option: { sortOption?: SortOption<DT>; force?: boolean; silent?: boolean; sort?: boolean } = {}) {
|
|
1391
|
+
const newOption = { silent: true, sortOption: null, sort: true, ...option };
|
|
1392
|
+
sortCol.value = colKey;
|
|
1393
|
+
sortOrderIndex.value = sortSwitchOrder.indexOf(order);
|
|
1394
|
+
const colKeyGenValue = colKeyGen.value;
|
|
1395
|
+
|
|
1396
|
+
if (newOption.sort && dataSourceCopy.value?.length) {
|
|
1397
|
+
// 如果表格有数据,则进行排序
|
|
1398
|
+
const column = newOption.sortOption || tableHeaderLast.value.find(it => colKeyGenValue(it) === sortCol.value);
|
|
1399
|
+
if (column) onColumnSort(column, false, { force: option.force ?? true, emit: !newOption.silent });
|
|
1400
|
+
else console.warn('Can not find column by key:', sortCol.value);
|
|
1401
|
+
}
|
|
1402
|
+
return dataSourceCopy.value;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
function resetSorter() {
|
|
1406
|
+
sortCol.value = void 0;
|
|
1407
|
+
sortOrderIndex.value = 0;
|
|
1408
|
+
dataSourceCopy.value = props.dataSource.slice();
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* set scroll bar position
|
|
1413
|
+
* @param top null to not change
|
|
1414
|
+
* @param left null to not change
|
|
1415
|
+
*/
|
|
1416
|
+
function scrollTo(top: number | null = 0, left: number | null = 0) {
|
|
1417
|
+
if (!tableContainerRef.value) return;
|
|
1418
|
+
if (top !== null) tableContainerRef.value.scrollTop = top;
|
|
1419
|
+
if (left !== null) tableContainerRef.value.scrollLeft = left;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
/** get current table data */
|
|
1423
|
+
function getTableData() {
|
|
1424
|
+
return toRaw(dataSourceCopy.value);
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* get current sort info
|
|
1429
|
+
* @return {{key:string,order:Order}[]}
|
|
1430
|
+
*/
|
|
1431
|
+
function getSortColumns() {
|
|
1432
|
+
const sortOrder = sortSwitchOrder[sortOrderIndex.value];
|
|
1433
|
+
if (!sortOrder) return [];
|
|
1434
|
+
return [{ key: sortCol.value, order: sortOrder }];
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
defineExpose({
|
|
1438
|
+
/**
|
|
1439
|
+
* 重新计算虚拟列表宽高
|
|
1440
|
+
*
|
|
1441
|
+
* en: calc virtual scroll x & y info
|
|
1442
|
+
* @see {@link initVirtualScroll}
|
|
1443
|
+
*/
|
|
1444
|
+
initVirtualScroll,
|
|
1445
|
+
/**
|
|
1446
|
+
* 重新计算虚拟列表宽度
|
|
1447
|
+
*
|
|
1448
|
+
* en: calc virtual scroll x
|
|
1449
|
+
* @see {@link initVirtualScrollX}
|
|
1450
|
+
*/
|
|
1451
|
+
initVirtualScrollX,
|
|
1452
|
+
/**
|
|
1453
|
+
* 重新计算虚拟列表高度
|
|
1454
|
+
*
|
|
1455
|
+
* en: calc virtual scroll y
|
|
1456
|
+
* @see {@link initVirtualScrollY}
|
|
1457
|
+
*/
|
|
1458
|
+
initVirtualScrollY,
|
|
1459
|
+
/**
|
|
1460
|
+
* 选中一行
|
|
1461
|
+
*
|
|
1462
|
+
* en:select a row
|
|
1463
|
+
* @see {@link setCurrentRow}
|
|
1464
|
+
*/
|
|
1465
|
+
setCurrentRow,
|
|
1466
|
+
/**
|
|
1467
|
+
* 取消选中单元格
|
|
1468
|
+
*
|
|
1469
|
+
* en: set highlight active cell (props.cellActive=true)
|
|
1470
|
+
* @see {@link setSelectedCell}
|
|
1471
|
+
*/
|
|
1472
|
+
setSelectedCell,
|
|
1473
|
+
/**
|
|
1474
|
+
* 设置高亮单元格
|
|
1475
|
+
*
|
|
1476
|
+
* en: Set highlight cell
|
|
1477
|
+
* @see {@link setHighlightDimCell}
|
|
1478
|
+
*/
|
|
1479
|
+
setHighlightDimCell,
|
|
1480
|
+
/**
|
|
1481
|
+
* 设置高亮行
|
|
1482
|
+
*
|
|
1483
|
+
* en: Set highlight row
|
|
1484
|
+
* @see {@link setHighlightDimRow}
|
|
1485
|
+
*/
|
|
1486
|
+
setHighlightDimRow,
|
|
1487
|
+
/**
|
|
1488
|
+
* 表格排序列colKey
|
|
1489
|
+
*
|
|
1490
|
+
* en: Table sort column colKey
|
|
1491
|
+
*/
|
|
1492
|
+
sortCol,
|
|
1493
|
+
/**
|
|
1494
|
+
* 表格排序列顺序
|
|
1495
|
+
*
|
|
1496
|
+
* en: get current sort info
|
|
1497
|
+
* @see {@link getSortColumns}
|
|
1498
|
+
*/
|
|
1499
|
+
getSortColumns,
|
|
1500
|
+
/**
|
|
1501
|
+
* 设置表头排序状态
|
|
1502
|
+
*
|
|
1503
|
+
* en: Set the sort status of the table header
|
|
1504
|
+
* @see {@link setSorter}
|
|
1505
|
+
*/
|
|
1506
|
+
setSorter,
|
|
1507
|
+
/**
|
|
1508
|
+
* 重置sorter状态
|
|
1509
|
+
*
|
|
1510
|
+
* en: Reset the sorter status
|
|
1511
|
+
* @see {@link resetSorter}
|
|
1512
|
+
*/
|
|
1513
|
+
resetSorter,
|
|
1514
|
+
/**
|
|
1515
|
+
* 滚动至
|
|
1516
|
+
*
|
|
1517
|
+
* en: Scroll to
|
|
1518
|
+
* @see {@link scrollTo}
|
|
1519
|
+
*/
|
|
1520
|
+
scrollTo,
|
|
1521
|
+
/**
|
|
1522
|
+
* 获取表格数据
|
|
1523
|
+
*
|
|
1524
|
+
* en: Get table data
|
|
1525
|
+
* @see {@link getTableData}
|
|
1526
|
+
*/
|
|
1527
|
+
getTableData,
|
|
1528
|
+
/**
|
|
1529
|
+
* 设置展开的行
|
|
1530
|
+
*
|
|
1531
|
+
* en: Set expanded rows
|
|
1532
|
+
* @see {@link setRowExpand}
|
|
1533
|
+
*/
|
|
1534
|
+
setRowExpand,
|
|
1535
|
+
/**
|
|
1536
|
+
* 不定行高时,如果行高有变化,则调用此方法更新行高。
|
|
1537
|
+
*
|
|
1538
|
+
* en: When the row height is not fixed, call this method to update the row height if the row height changes.
|
|
1539
|
+
* @see {@link setAutoHeight}
|
|
1540
|
+
*/
|
|
1541
|
+
setAutoHeight,
|
|
1542
|
+
/**
|
|
1543
|
+
* 清除所有行高
|
|
1544
|
+
*
|
|
1545
|
+
* en: Clear all row heights
|
|
1546
|
+
* @see {@link clearAllAutoHeight}
|
|
1547
|
+
*/
|
|
1548
|
+
clearAllAutoHeight,
|
|
1549
|
+
/**
|
|
1550
|
+
* 设置树节点展开状态
|
|
1551
|
+
*
|
|
1552
|
+
* en: Set tree node expand state
|
|
1553
|
+
* @see {@link setTreeExpand}
|
|
1554
|
+
*/
|
|
1555
|
+
setTreeExpand,
|
|
1556
|
+
});
|
|
1557
|
+
</script>
|