yy-vue-easytable 2.27.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.
Files changed (205) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +187 -0
  3. package/libs/font/demo.css +539 -0
  4. package/libs/font/demo_index.html +400 -0
  5. package/libs/font/iconfont.css +57 -0
  6. package/libs/font/iconfont.eot +0 -0
  7. package/libs/font/iconfont.js +1 -0
  8. package/libs/font/iconfont.json +79 -0
  9. package/libs/font/iconfont.svg +56 -0
  10. package/libs/font/iconfont.ttf +0 -0
  11. package/libs/font/iconfont.woff +0 -0
  12. package/libs/font/iconfont.woff2 +0 -0
  13. package/libs/locale/lang/af-ZA.js +48 -0
  14. package/libs/locale/lang/en-US.js +48 -0
  15. package/libs/locale/lang/fr-FR.js +48 -0
  16. package/libs/locale/lang/ko-KR.js +48 -0
  17. package/libs/locale/lang/pt-BR.js +48 -0
  18. package/libs/locale/lang/ru-RU.js +48 -0
  19. package/libs/locale/lang/zh-CN.js +48 -0
  20. package/libs/locale/lang/zh-TW.js +48 -0
  21. package/libs/locale/lang/zu-ZA.js +48 -0
  22. package/libs/main.js +1 -0
  23. package/libs/theme-dark/base.css +1 -0
  24. package/libs/theme-dark/index.css +1253 -0
  25. package/libs/theme-dark/var.css +7 -0
  26. package/libs/theme-dark/ve-checkbox.css +150 -0
  27. package/libs/theme-dark/ve-contextmenu.css +71 -0
  28. package/libs/theme-dark/ve-dropdown.css +177 -0
  29. package/libs/theme-dark/ve-icon.css +10 -0
  30. package/libs/theme-dark/ve-loading.css +218 -0
  31. package/libs/theme-dark/ve-pagination.css +136 -0
  32. package/libs/theme-dark/ve-radio.css +111 -0
  33. package/libs/theme-dark/ve-select.css +50 -0
  34. package/libs/theme-dark/ve-table.css +385 -0
  35. package/libs/theme-default/base.css +1 -0
  36. package/libs/theme-default/index.css +1253 -0
  37. package/libs/theme-default/var.css +7 -0
  38. package/libs/theme-default/ve-checkbox.css +150 -0
  39. package/libs/theme-default/ve-contextmenu.css +71 -0
  40. package/libs/theme-default/ve-dropdown.css +177 -0
  41. package/libs/theme-default/ve-icon.css +10 -0
  42. package/libs/theme-default/ve-loading.css +218 -0
  43. package/libs/theme-default/ve-pagination.css +136 -0
  44. package/libs/theme-default/ve-radio.css +111 -0
  45. package/libs/theme-default/ve-select.css +50 -0
  46. package/libs/theme-default/ve-table.css +385 -0
  47. package/libs/umd/index.js +9 -0
  48. package/libs/ve-checkbox-group.js +1 -0
  49. package/libs/ve-checkbox.js +1 -0
  50. package/libs/ve-contextmenu.js +1 -0
  51. package/libs/ve-dropdown.js +1 -0
  52. package/libs/ve-icon.js +1 -0
  53. package/libs/ve-loading.js +1 -0
  54. package/libs/ve-locale.js +1 -0
  55. package/libs/ve-pagination.js +1 -0
  56. package/libs/ve-radio.js +1 -0
  57. package/libs/ve-select.js +1 -0
  58. package/libs/ve-table.js +1 -0
  59. package/package.json +142 -0
  60. package/packages/font/demo.css +539 -0
  61. package/packages/font/demo_index.html +400 -0
  62. package/packages/font/iconfont.css +57 -0
  63. package/packages/font/iconfont.eot +0 -0
  64. package/packages/font/iconfont.js +1 -0
  65. package/packages/font/iconfont.json +79 -0
  66. package/packages/font/iconfont.svg +56 -0
  67. package/packages/font/iconfont.ttf +0 -0
  68. package/packages/font/iconfont.woff +0 -0
  69. package/packages/font/iconfont.woff2 +0 -0
  70. package/packages/index.js +75 -0
  71. package/packages/src/comps/resize-observer/index.js +2 -0
  72. package/packages/src/comps/resize-observer/src/index.jsx +38 -0
  73. package/packages/src/directives/clickoutside.js +31 -0
  74. package/packages/src/directives/events-outside.js +79 -0
  75. package/packages/src/directives/focus.js +28 -0
  76. package/packages/src/locale/index.js +27 -0
  77. package/packages/src/locale/lang/af-ZA.js +29 -0
  78. package/packages/src/locale/lang/en-US.js +30 -0
  79. package/packages/src/locale/lang/fr-FR.js +29 -0
  80. package/packages/src/locale/lang/ko-KR.js +29 -0
  81. package/packages/src/locale/lang/pt-BR.js +29 -0
  82. package/packages/src/locale/lang/ru-RU.js +29 -0
  83. package/packages/src/locale/lang/zh-CN.js +30 -0
  84. package/packages/src/locale/lang/zh-TW.js +29 -0
  85. package/packages/src/locale/lang/zu-ZA.js +29 -0
  86. package/packages/src/mixins/emitter.js +39 -0
  87. package/packages/src/utils/animation-frame.js +39 -0
  88. package/packages/src/utils/auto-resize.js +179 -0
  89. package/packages/src/utils/constant.js +42 -0
  90. package/packages/src/utils/dom.js +239 -0
  91. package/packages/src/utils/event-key-codes.js +53 -0
  92. package/packages/src/utils/hooks-manager.js +76 -0
  93. package/packages/src/utils/index.js +161 -0
  94. package/packages/src/utils/mouse-event.js +24 -0
  95. package/packages/src/utils/random.js +6 -0
  96. package/packages/src/utils/request-animation-timeout.js +36 -0
  97. package/packages/src/utils/resize-event.js +40 -0
  98. package/packages/src/utils/scroll-bar.js +27 -0
  99. package/packages/style/ve-checkbox.less +179 -0
  100. package/packages/style/ve-contextmenu.less +76 -0
  101. package/packages/style/ve-dropdown.less +204 -0
  102. package/packages/style/ve-icon.less +3 -0
  103. package/packages/style/ve-loading.less +242 -0
  104. package/packages/style/ve-pagination.less +153 -0
  105. package/packages/style/ve-radio.less +126 -0
  106. package/packages/style/ve-select.less +48 -0
  107. package/packages/style/ve-table.less +539 -0
  108. package/packages/theme-dark/base.less +1 -0
  109. package/packages/theme-dark/index.less +12 -0
  110. package/packages/theme-dark/var.less +111 -0
  111. package/packages/theme-dark/ve-checkbox.less +2 -0
  112. package/packages/theme-dark/ve-contextmenu.less +2 -0
  113. package/packages/theme-dark/ve-dropdown.less +2 -0
  114. package/packages/theme-dark/ve-icon.less +2 -0
  115. package/packages/theme-dark/ve-loading.less +2 -0
  116. package/packages/theme-dark/ve-pagination.less +2 -0
  117. package/packages/theme-dark/ve-radio.less +2 -0
  118. package/packages/theme-dark/ve-select.less +2 -0
  119. package/packages/theme-dark/ve-table.less +2 -0
  120. package/packages/theme-default/base.less +1 -0
  121. package/packages/theme-default/index.less +12 -0
  122. package/packages/theme-default/var.less +111 -0
  123. package/packages/theme-default/ve-checkbox.less +2 -0
  124. package/packages/theme-default/ve-contextmenu.less +2 -0
  125. package/packages/theme-default/ve-dropdown.less +2 -0
  126. package/packages/theme-default/ve-icon.less +2 -0
  127. package/packages/theme-default/ve-loading.less +2 -0
  128. package/packages/theme-default/ve-pagination.less +2 -0
  129. package/packages/theme-default/ve-radio.less +2 -0
  130. package/packages/theme-default/ve-select.less +2 -0
  131. package/packages/theme-default/ve-table.less +2 -0
  132. package/packages/ve-checkbox/index.js +7 -0
  133. package/packages/ve-checkbox/src/index.jsx +175 -0
  134. package/packages/ve-checkbox/src/util/constant.js +14 -0
  135. package/packages/ve-checkbox/src/util/index.js +10 -0
  136. package/packages/ve-checkbox-group/index.js +7 -0
  137. package/packages/ve-checkbox-group/src/index.jsx +53 -0
  138. package/packages/ve-checkbox-group/src/util/constant.js +14 -0
  139. package/packages/ve-checkbox-group/src/util/index.js +10 -0
  140. package/packages/ve-contextmenu/index.js +7 -0
  141. package/packages/ve-contextmenu/src/index.jsx +731 -0
  142. package/packages/ve-contextmenu/src/util/constant.js +29 -0
  143. package/packages/ve-contextmenu/src/util/index.js +10 -0
  144. package/packages/ve-dropdown/index.js +7 -0
  145. package/packages/ve-dropdown/src/index.jsx +720 -0
  146. package/packages/ve-dropdown/src/util/constant.js +15 -0
  147. package/packages/ve-dropdown/src/util/index.js +10 -0
  148. package/packages/ve-icon/index.js +7 -0
  149. package/packages/ve-icon/src/index.jsx +52 -0
  150. package/packages/ve-icon/src/util/constant.js +10 -0
  151. package/packages/ve-icon/src/util/index.js +10 -0
  152. package/packages/ve-loading/index.js +8 -0
  153. package/packages/ve-loading/src/bounce.jsx +50 -0
  154. package/packages/ve-loading/src/flow.jsx +51 -0
  155. package/packages/ve-loading/src/grid.jsx +57 -0
  156. package/packages/ve-loading/src/index.js +106 -0
  157. package/packages/ve-loading/src/loading.jsx +63 -0
  158. package/packages/ve-loading/src/plane.jsx +38 -0
  159. package/packages/ve-loading/src/pulse.jsx +38 -0
  160. package/packages/ve-loading/src/util/constant.js +31 -0
  161. package/packages/ve-loading/src/util/index.js +10 -0
  162. package/packages/ve-loading/src/wave.jsx +53 -0
  163. package/packages/ve-locale/index.js +28 -0
  164. package/packages/ve-pagination/index.js +7 -0
  165. package/packages/ve-pagination/src/index.jsx +304 -0
  166. package/packages/ve-pagination/src/pager.jsx +166 -0
  167. package/packages/ve-pagination/src/util/constant.js +16 -0
  168. package/packages/ve-pagination/src/util/index.js +10 -0
  169. package/packages/ve-radio/index.js +7 -0
  170. package/packages/ve-radio/src/index.jsx +121 -0
  171. package/packages/ve-radio/src/util/constant.js +13 -0
  172. package/packages/ve-radio/src/util/index.js +10 -0
  173. package/packages/ve-select/index.js +7 -0
  174. package/packages/ve-select/src/index.jsx +193 -0
  175. package/packages/ve-select/src/util/constant.js +13 -0
  176. package/packages/ve-select/src/util/index.js +10 -0
  177. package/packages/ve-table/index.js +7 -0
  178. package/packages/ve-table/src/body/body-checkbox-content.jsx +126 -0
  179. package/packages/ve-table/src/body/body-radio-content.jsx +113 -0
  180. package/packages/ve-table/src/body/body-td.jsx +671 -0
  181. package/packages/ve-table/src/body/body-tr-scrolling.jsx +38 -0
  182. package/packages/ve-table/src/body/body-tr.jsx +383 -0
  183. package/packages/ve-table/src/body/expand-tr-icon.jsx +80 -0
  184. package/packages/ve-table/src/body/expand-tr.jsx +147 -0
  185. package/packages/ve-table/src/body/index.jsx +943 -0
  186. package/packages/ve-table/src/colgroup/index.jsx +48 -0
  187. package/packages/ve-table/src/column-resizer/index.jsx +318 -0
  188. package/packages/ve-table/src/editor/constant.js +5 -0
  189. package/packages/ve-table/src/editor/index.jsx +533 -0
  190. package/packages/ve-table/src/footer/footer-td.jsx +396 -0
  191. package/packages/ve-table/src/footer/footer-tr.jsx +249 -0
  192. package/packages/ve-table/src/footer/index.jsx +108 -0
  193. package/packages/ve-table/src/header/header-checkbox-content.jsx +69 -0
  194. package/packages/ve-table/src/header/header-filter-content.jsx +100 -0
  195. package/packages/ve-table/src/header/header-filter-custom-content.jsx +110 -0
  196. package/packages/ve-table/src/header/header-th.jsx +664 -0
  197. package/packages/ve-table/src/header/header-tr.jsx +255 -0
  198. package/packages/ve-table/src/header/index.jsx +195 -0
  199. package/packages/ve-table/src/index.jsx +4196 -0
  200. package/packages/ve-table/src/selection/constant.js +5 -0
  201. package/packages/ve-table/src/selection/index.jsx +1643 -0
  202. package/packages/ve-table/src/util/clipboard.js +428 -0
  203. package/packages/ve-table/src/util/constant.js +269 -0
  204. package/packages/ve-table/src/util/index.js +1585 -0
  205. package/packages/ve-table/src/util/store.js +14 -0
@@ -0,0 +1,4196 @@
1
+ import { cloneDeep, debounce } from "lodash";
2
+ import {
3
+ initGroupColumns,
4
+ clsName,
5
+ getNotFixedTotalWidthByColumnKey,
6
+ recursiveRemoveColumnByKey,
7
+ setHeaderContextmenuOptions,
8
+ setBodyContextmenuOptions,
9
+ createEmptyRowData,
10
+ isContextmenuPanelClicked,
11
+ getRowKey,
12
+ getColKeysByHeaderColumn,
13
+ getColumnByColkey,
14
+ getLeftmostColKey,
15
+ isCellInSelectionRange,
16
+ isClearSelectionByBodyCellRightClick,
17
+ cellAutofill,
18
+ isOperationColumn,
19
+ getSelectionRangeData,
20
+ getSelectionRangeKeys,
21
+ getSelectionRangeIndexes,
22
+ setColumnFixed,
23
+ cancelColumnFixed,
24
+ } from "./util";
25
+ import {
26
+ onBeforeCopy,
27
+ onAfterCopy,
28
+ onBeforePaste,
29
+ onAfterPaste,
30
+ onBeforeCut,
31
+ onAfterCut,
32
+ onBeforeDelete,
33
+ onAfterDelete,
34
+ } from "./util/clipboard";
35
+ import {
36
+ getValByUnit,
37
+ isFunction,
38
+ isNumber,
39
+ scrollTo,
40
+ isEmptyValue,
41
+ isEmptyArray,
42
+ isBoolean,
43
+ isDefined,
44
+ createLocale,
45
+ } from "../../src/utils/index.js";
46
+ import { KEY_CODES, MOUSE_EVENT_CLICK_TYPE } from "../../src/utils/constant";
47
+ import { getScrollbarWidth } from "../../src/utils/scroll-bar";
48
+ import {
49
+ requestAnimationTimeout,
50
+ cancelAnimationTimeout,
51
+ } from "../../src/utils/request-animation-timeout";
52
+ import { isInputKeyCode } from "../../src/utils/event-key-codes";
53
+ import Hooks from "../../src/utils/hooks-manager";
54
+ import { getMouseEventClickType } from "../../src/utils/mouse-event";
55
+ import emitter from "../../src/mixins/emitter";
56
+ import {
57
+ COMPS_NAME,
58
+ HOOKS_NAME,
59
+ EMIT_EVENTS,
60
+ COMPS_CUSTOM_ATTRS,
61
+ INSTANCE_METHODS,
62
+ CELL_SELECTION_DIRECTION,
63
+ LOCALE_COMP_NAME,
64
+ CONTEXTMENU_TYPES,
65
+ CONTEXTMENU_NODE_TYPES,
66
+ AUTOFILLING_DIRECTION,
67
+ CURRENT_CELL_SELECTION_TYPES,
68
+ COLUMN_FIXED_TYPE,
69
+ } from "./util/constant";
70
+ import Colgroup from "./colgroup";
71
+ import Header from "./header";
72
+ import Body from "./body";
73
+ import Footer from "./footer";
74
+ import EditInput from "./editor/index";
75
+ import Selection from "./selection/index";
76
+ import clickoutside from "../../src/directives/clickoutside";
77
+ import VueDomResizeObserver from "../../src/comps/resize-observer";
78
+ import VeContextmenu from "vue-easytable/packages/ve-contextmenu";
79
+ import ColumnResizer from "./column-resizer";
80
+
81
+ const t = createLocale(LOCALE_COMP_NAME);
82
+
83
+ export default {
84
+ name: COMPS_NAME.VE_TABLE,
85
+ directives: {
86
+ "click-outside": clickoutside,
87
+ },
88
+ mixins: [emitter],
89
+ props: {
90
+ tableData: {
91
+ required: true,
92
+ type: Array,
93
+ },
94
+ footerData: {
95
+ type: Array,
96
+ default: function () {
97
+ return [];
98
+ },
99
+ },
100
+ showHeader: {
101
+ type: Boolean,
102
+ default: true,
103
+ },
104
+ columns: {
105
+ type: Array,
106
+ required: true,
107
+ },
108
+ // row key field for row expand、row selection
109
+ rowKeyFieldName: {
110
+ type: String,
111
+ default: null,
112
+ },
113
+ // table scroll width
114
+ scrollWidth: {
115
+ type: [Number, String],
116
+ default: null,
117
+ },
118
+ // table max height
119
+ maxHeight: {
120
+ type: [Number, String],
121
+ default: null,
122
+ },
123
+ // fixed header
124
+ fixedHeader: {
125
+ type: Boolean,
126
+ default: true,
127
+ },
128
+ // fixed footer
129
+ fixedFooter: {
130
+ type: Boolean,
131
+ default: true,
132
+ },
133
+ // border around
134
+ borderAround: {
135
+ type: Boolean,
136
+ default: true,
137
+ },
138
+ // border horizontal
139
+ borderX: {
140
+ type: Boolean,
141
+ default: true,
142
+ },
143
+ // border vertical
144
+ borderY: {
145
+ type: Boolean,
146
+ default: false,
147
+ },
148
+ // event custom option
149
+ eventCustomOption: {
150
+ type: Object,
151
+ default: function () {
152
+ return null;
153
+ },
154
+ },
155
+ // cell style option
156
+ cellStyleOption: {
157
+ type: Object,
158
+ default: function () {
159
+ return null;
160
+ },
161
+ },
162
+ // cell span option
163
+ cellSpanOption: {
164
+ type: Object,
165
+ default: function () {
166
+ return null;
167
+ },
168
+ },
169
+ // row style option
170
+ rowStyleOption: {
171
+ type: Object,
172
+ default: function () {
173
+ return null;
174
+ },
175
+ },
176
+ /*
177
+ virual scroll option
178
+ {
179
+ enable:true,
180
+ bufferCount:10, // 缓冲的数据
181
+ minRowHeight:40,
182
+ scrolling:(startRowIndex,visibleStartIndex,visibleEndIndex,visibleAboveCount,visibleBelowCount)=>{}
183
+ }
184
+ */
185
+ virtualScrollOption: {
186
+ type: Object,
187
+ default: null,
188
+ },
189
+ // sort option
190
+ sortOption: {
191
+ type: Object,
192
+ default: function () {
193
+ return null;
194
+ },
195
+ },
196
+ // expand row option
197
+ expandOption: {
198
+ type: Object,
199
+ default: function () {
200
+ return null;
201
+ },
202
+ },
203
+ // checkbox option
204
+ checkboxOption: {
205
+ type: Object,
206
+ default: function () {
207
+ return null;
208
+ },
209
+ },
210
+ // radio option
211
+ radioOption: {
212
+ type: Object,
213
+ default: function () {
214
+ return null;
215
+ },
216
+ },
217
+ // cell selection option
218
+ cellSelectionOption: {
219
+ type: Object,
220
+ default: function () {
221
+ return null;
222
+ },
223
+ },
224
+ // cell autofill option
225
+ cellAutofillOption: {
226
+ type: [Object, Boolean],
227
+ default: function () {
228
+ return null;
229
+ },
230
+ },
231
+ // edit option
232
+ editOption: {
233
+ type: Object,
234
+ default: function () {
235
+ return null;
236
+ },
237
+ },
238
+ // column hidden option
239
+ columnHiddenOption: {
240
+ type: Object,
241
+ default: function () {
242
+ return null;
243
+ },
244
+ },
245
+ // contextmenu header option
246
+ contextmenuHeaderOption: {
247
+ type: Object,
248
+ default: function () {
249
+ return null;
250
+ },
251
+ },
252
+ // contextmenu body option
253
+ contextmenuBodyOption: {
254
+ type: Object,
255
+ default: function () {
256
+ return null;
257
+ },
258
+ },
259
+ // clipboard option
260
+ clipboardOption: {
261
+ type: Object,
262
+ default: function () {
263
+ return null;
264
+ },
265
+ },
266
+ // column width resize option
267
+ columnWidthResizeOption: {
268
+ type: Object,
269
+ default: function () {
270
+ return null;
271
+ },
272
+ },
273
+ },
274
+ data() {
275
+ return {
276
+ // Hooks instance
277
+ hooks: {},
278
+ // is parent rendered
279
+ parentRendered: false,
280
+ // table viewport width except scroll bar width
281
+ tableViewportWidth: 0,
282
+ /*
283
+ 列配置变化次数
284
+ 依赖columns 配置渲染,都需要重新计算:粘性布局时,重新触发 on-dom-resize-change 事件
285
+ */
286
+ columnsOptionResetTime: 0,
287
+ tableRootRef: "tableRootRef",
288
+ tableContainerWrapperRef: "tableContainerWrapperRef",
289
+ tableContainerRef: "tableContainerRef",
290
+ tableRef: "tableRef",
291
+ tableBodyRef: "tableBodyRef",
292
+ tableContentWrapperRef: "tableContentWrapperRef",
293
+ virtualPhantomRef: "virtualPhantomRef",
294
+ editInputRef: "editInputRef",
295
+ cellSelectionRef: "cellSelectionRef",
296
+ contextmenuRef: "contextmenuRef",
297
+ cloneColumns: [],
298
+ // is group header
299
+ isGroupHeader: false,
300
+ /*
301
+ header rows created by groupColumns
302
+ */
303
+ headerRows: [
304
+ /* {
305
+ rowHeight:40
306
+ } */
307
+ ],
308
+ /*
309
+ footer rows created by footerData
310
+ */
311
+ footerRows: [
312
+ /* {
313
+ rowHeight:40
314
+ } */
315
+ ],
316
+ // colgroups
317
+ colgroups: [],
318
+ // groupColumns
319
+ groupColumns: [],
320
+ /*
321
+ 存储当前隐藏列信息
322
+ hidden columns
323
+ */
324
+ hiddenColumns: [],
325
+ /*
326
+ // virtual scroll positions(非响应式)
327
+ virtualScrollPositions = [
328
+ {
329
+ rowKey: "", // 当前行数据 rowKey
330
+ top: 0, // 距离上一个项的高度
331
+ bottom: 100, // 距离下一个项的高度
332
+ height: 100 // 自身高度
333
+ }
334
+ ],
335
+ */
336
+ // virtual scroll visible data
337
+ virtualScrollVisibleData: [],
338
+ // virtual scroll visible indexs
339
+ virtualScrollVisibleIndexs: {
340
+ start: -1,
341
+ end: -1,
342
+ },
343
+ // default virtual scroll buffer scale
344
+ defaultVirtualScrollBufferScale: 1,
345
+ // default virtual scroll min row height
346
+ defaultVirtualScrollMinRowHeight: 40,
347
+ // default placeholder per scrolling row count
348
+ defaultPlaceholderPerScrollingRowCount: 8,
349
+ //起始索引
350
+ virtualScrollStartIndex: 0,
351
+ // preview virtual scroll start index
352
+ previewVirtualScrollStartIndex: 0,
353
+ //结束索引
354
+ virtualScrollEndIndex: 0,
355
+ // is scrolling
356
+ showVirtualScrollingPlaceholder: false,
357
+ // disable pointer events timeout id
358
+ disablePointerEventsTimeoutId: null,
359
+ // is scrolling left
360
+ isLeftScrolling: false,
361
+ // is scrolling right
362
+ isRightScrolling: false,
363
+ // is scrolling vertically
364
+ isVerticalScrolling: false,
365
+ // has horizontal scroll bar
366
+ hasXScrollBar: false,
367
+ // has vertical scroll bar
368
+ hasYScrollBar: false,
369
+ // scroll bar width
370
+ scrollBarWidth: 0,
371
+ // preview table container scrollLeft (处理左列或右列固定效果)
372
+ previewTableContainerScrollLeft: null,
373
+ // header cell selection colKeys
374
+ headerIndicatorColKeys: {
375
+ startColKey: "",
376
+ startColKeyIndex: -1,
377
+ endColKey: "",
378
+ endColKeyIndex: -1,
379
+ },
380
+ // body indicator rowKeys
381
+ bodyIndicatorRowKeys: {
382
+ startRowKey: "",
383
+ startRowKeyIndex: -1,
384
+ endRowKey: "",
385
+ endRowKeyIndex: -1,
386
+ },
387
+ // cell selection data
388
+ cellSelectionData: {
389
+ currentCell: {
390
+ rowKey: "",
391
+ colKey: "",
392
+ rowIndex: -1,
393
+ },
394
+ normalEndCell: {
395
+ rowKey: "",
396
+ colKey: "",
397
+ rowIndex: -1,
398
+ },
399
+ autoFillEndCell: {
400
+ rowKey: "",
401
+ colKey: "",
402
+ },
403
+ },
404
+ // cell selection range data
405
+ cellSelectionRangeData: {
406
+ leftColKey: "",
407
+ rightColKey: "",
408
+ topRowKey: "",
409
+ bottomRowKey: "",
410
+ },
411
+ // is header cell mousedown
412
+ isHeaderCellMousedown: false,
413
+ // is body cell mousedown
414
+ isBodyCellMousedown: false,
415
+ // is body operation column mousedown
416
+ isBodyOperationColumnMousedown: false,
417
+ // is cell selection corner mousedown
418
+ isAutofillStarting: false,
419
+ // autofilling direction
420
+ autofillingDirection: null,
421
+ // current cell selection type
422
+ currentCellSelectionType: "",
423
+ /*
424
+ table offest height(开启虚拟滚动时使用)
425
+ 1、当 :max-height="500" 时使用 max-height
426
+ 2、当 max-height="calc(100vh - 210px)" 或者 max-height="80%" 时使用 tableOffestHeight
427
+ */
428
+ tableOffestHeight: 0,
429
+ // table height
430
+ tableHeight: 0,
431
+ // highlight row key
432
+ highlightRowKey: "",
433
+ /*
434
+ editing cell
435
+ */
436
+ editingCell: {
437
+ rowKey: "",
438
+ colKey: "",
439
+ row: null,
440
+ column: null,
441
+ },
442
+ // 编辑单元格每次开始编辑前的初始值
443
+ editorInputStartValue: "",
444
+ /*
445
+ 是否允许按下方向键时,停止编辑并移动选中单元格。当双击可编辑单元格或者点击输入文本框时设置为false值
446
+
447
+ 像excel一样:如果直接在可编辑单元格上输入内容后,按下上、下、左、右按键可以直接选中其他单元格,并停止当前单元格编辑状态
448
+ like Excel:If you directly enter content in an editable cell, press the up, down, left and right buttons to directly select other cells and stop editing the current cell
449
+ */
450
+ enableStopEditing: true,
451
+ // contextmenu event target
452
+ contextmenuEventTarget: "",
453
+ // contextmenu options
454
+ contextmenuOptions: [],
455
+ // column resize cursor
456
+ isColumnResizerHover: false,
457
+ // is column resizing
458
+ isColumnResizing: false,
459
+ };
460
+ },
461
+ computed: {
462
+ // actual render table data
463
+ actualRenderTableData() {
464
+ return this.isVirtualScroll
465
+ ? this.virtualScrollVisibleData
466
+ : this.tableData;
467
+ },
468
+ // return row keys
469
+ allRowKeys() {
470
+ let result = [];
471
+
472
+ const { tableData, rowKeyFieldName } = this;
473
+
474
+ if (rowKeyFieldName) {
475
+ result = tableData.map((x) => {
476
+ return x[rowKeyFieldName];
477
+ });
478
+ }
479
+
480
+ return result;
481
+ },
482
+ // virtual scroll buffer count
483
+ virtualScrollBufferCount() {
484
+ let result = 0;
485
+
486
+ const {
487
+ virtualScrollOption,
488
+ defaultVirtualScrollBufferScale,
489
+ virtualScrollVisibleCount,
490
+ } = this;
491
+
492
+ if (virtualScrollOption) {
493
+ const { bufferScale } = virtualScrollOption;
494
+
495
+ let realBufferScale =
496
+ isNumber(bufferScale) && bufferScale > 0
497
+ ? bufferScale
498
+ : defaultVirtualScrollBufferScale;
499
+
500
+ result = realBufferScale * virtualScrollVisibleCount;
501
+ }
502
+
503
+ return result;
504
+ },
505
+ // virtual scroll visible count
506
+ virtualScrollVisibleCount() {
507
+ let result = 0;
508
+
509
+ const {
510
+ isVirtualScroll,
511
+ virtualScrollOption,
512
+ defaultVirtualScrollMinRowHeight,
513
+ maxHeight,
514
+ tableOffestHeight,
515
+ } = this;
516
+
517
+ if (isVirtualScroll && maxHeight) {
518
+ const minRowHeight = isNumber(virtualScrollOption.minRowHeight)
519
+ ? virtualScrollOption.minRowHeight
520
+ : defaultVirtualScrollMinRowHeight;
521
+
522
+ if (isNumber(maxHeight)) {
523
+ result = Math.ceil(maxHeight / minRowHeight);
524
+ } else if (tableOffestHeight) {
525
+ // 修复当动态高度 当 max-height="calc(100vh - 210px)" 或者 max-height="80%" 时无法计算的问题
526
+ result = Math.ceil(tableOffestHeight / minRowHeight);
527
+ }
528
+ }
529
+ return result;
530
+ },
531
+ // table container wrapper style
532
+ tableContainerWrapperStyle() {
533
+ return {
534
+ width: "100%",
535
+ };
536
+ },
537
+ // table container style
538
+ tableContainerStyle() {
539
+ let maxHeight = getValByUnit(this.maxHeight);
540
+
541
+ let tableContainerHeight = null;
542
+ if (this.isVirtualScroll) {
543
+ if (maxHeight) {
544
+ tableContainerHeight = maxHeight;
545
+ } else {
546
+ console.error(
547
+ "maxHeight prop is required when 'virtualScrollOption.enable = true'",
548
+ );
549
+ }
550
+ } else {
551
+ /*
552
+ fixed:虚拟滚动表格行展开的 ve-table 存在固定头时(sticky 冲突),表格样式错乱的问题
553
+ fixed:When there is a fixed header in the ve-table expanded by the row of the virtual rolling table(header sticky conflict),Incorrect table presentation
554
+ */
555
+ const { tableHeight, hasXScrollBar } = this;
556
+ tableContainerHeight = tableHeight;
557
+ /*
558
+ 有横向滚动条时,表格高度需要加上滚动条的宽度
559
+ When there is a horizontal scroll bar, the table height needs to be added with the width of the scroll bar
560
+ */
561
+ if (hasXScrollBar) {
562
+ tableContainerHeight += this.getScrollBarWidth();
563
+ }
564
+
565
+ tableContainerHeight = getValByUnit(tableContainerHeight);
566
+ }
567
+
568
+ return {
569
+ "max-height": maxHeight,
570
+ // if virtual scroll
571
+ height: tableContainerHeight,
572
+ };
573
+ },
574
+ // table style
575
+ tableStyle() {
576
+ return {
577
+ width: getValByUnit(this.scrollWidth),
578
+ };
579
+ },
580
+ // table class
581
+ tableClass() {
582
+ return {
583
+ [clsName("border-x")]: this.borderX,
584
+ [clsName("border-y")]: this.borderY,
585
+ };
586
+ },
587
+ // table container class
588
+ tableContainerClass() {
589
+ const {
590
+ isVirtualScroll,
591
+ isLeftScrolling,
592
+ isRightScrolling,
593
+ isVerticalScrolling,
594
+ isCellEditing,
595
+ isAutofillStarting,
596
+ enableCellSelection,
597
+ } = this;
598
+
599
+ return {
600
+ [clsName("container")]: true,
601
+ [clsName("virtual-scroll")]: isVirtualScroll,
602
+ [clsName("container-left-scrolling")]: isLeftScrolling,
603
+ [clsName("container-right-scrolling")]: isRightScrolling,
604
+ [clsName("container-vertical-scrolling")]: isVerticalScrolling,
605
+ [clsName("is-cell-editing")]: isCellEditing,
606
+ [clsName("autofilling")]: isAutofillStarting,
607
+ // 如果开启单元格选择,则关闭 user-select
608
+ [clsName("enable-cell-selection")]: enableCellSelection,
609
+ };
610
+ },
611
+ // table body class
612
+ tableBodyClass() {
613
+ let result = null;
614
+
615
+ const { rowStyleOption } = this;
616
+
617
+ let hoverHighlight = true;
618
+ let clickHighlight = true;
619
+ let stripe = false;
620
+
621
+ if (rowStyleOption) {
622
+ hoverHighlight = rowStyleOption.hoverHighlight;
623
+ clickHighlight = rowStyleOption.clickHighlight;
624
+ stripe = rowStyleOption.stripe;
625
+ }
626
+
627
+ result = {
628
+ [clsName("stripe")]: stripe === true, // 默认不开启
629
+ [clsName("row-hover")]: hoverHighlight !== false, // 默认开启
630
+ [clsName("row-highlight")]: clickHighlight !== false, // 默认开启
631
+ };
632
+
633
+ return result;
634
+ },
635
+ // is virtual scroll
636
+ isVirtualScroll() {
637
+ const { virtualScrollOption } = this;
638
+ return virtualScrollOption && virtualScrollOption.enable;
639
+ },
640
+ // has fixed column
641
+ hasFixedColumn() {
642
+ return this.colgroups.some(
643
+ (x) =>
644
+ x.fixed === COLUMN_FIXED_TYPE.LEFT ||
645
+ x.fixed === COLUMN_FIXED_TYPE.RIGHT,
646
+ );
647
+ },
648
+ // has left fixed column
649
+ hasLeftFixedColumn() {
650
+ return this.colgroups.some(
651
+ (x) => x.fixed === COLUMN_FIXED_TYPE.LEFT,
652
+ );
653
+ },
654
+ // has right fixed column
655
+ hasRightFixedColumn() {
656
+ return this.colgroups.some(
657
+ (x) => x.fixed === COLUMN_FIXED_TYPE.RIGHT,
658
+ );
659
+ },
660
+ // is editing cell
661
+ isCellEditing() {
662
+ const { editingCell } = this;
663
+
664
+ return (
665
+ !isEmptyValue(editingCell.rowKey) &&
666
+ !isEmptyValue(editingCell.colKey)
667
+ );
668
+ },
669
+ // has edit column
670
+ hasEditColumn() {
671
+ return this.colgroups.some((x) => x.edit);
672
+ },
673
+ // enable header contextmenu
674
+ enableHeaderContextmenu() {
675
+ let result = false;
676
+
677
+ const { contextmenuHeaderOption } = this;
678
+ if (contextmenuHeaderOption) {
679
+ const { contextmenus } = contextmenuHeaderOption;
680
+
681
+ if (Array.isArray(contextmenus) && contextmenus.length) {
682
+ result = true;
683
+ }
684
+ }
685
+ return result;
686
+ },
687
+ // enable body contextmenu
688
+ enableBodyContextmenu() {
689
+ let result = false;
690
+
691
+ const { contextmenuBodyOption } = this;
692
+ if (contextmenuBodyOption) {
693
+ const { contextmenus } = contextmenuBodyOption;
694
+
695
+ if (Array.isArray(contextmenus) && contextmenus.length) {
696
+ result = true;
697
+ }
698
+ }
699
+ return result;
700
+ },
701
+ // contextmenu type
702
+ contextMenuType() {
703
+ if (this.headerIndicatorColKeys.startColKeyIndex > -1) {
704
+ return CONTEXTMENU_TYPES.HEADER_CONTEXTMENU;
705
+ } else {
706
+ return CONTEXTMENU_TYPES.BODY_CONTEXTMENU;
707
+ }
708
+ },
709
+ /*
710
+ enable cell selection
711
+ 单元格编辑、剪贴板都依赖单元格选择
712
+ */
713
+ enableCellSelection() {
714
+ let result = true;
715
+
716
+ const { cellSelectionOption, rowKeyFieldName } = this;
717
+
718
+ if (isEmptyValue(rowKeyFieldName)) {
719
+ result = false;
720
+ } else if (
721
+ cellSelectionOption &&
722
+ isBoolean(cellSelectionOption.enable) &&
723
+ cellSelectionOption.enable === false
724
+ ) {
725
+ result = false;
726
+ }
727
+ return result;
728
+ },
729
+ // enable clipboard
730
+ enableClipboard() {
731
+ return this.rowKeyFieldName;
732
+ },
733
+ // eanble width resize
734
+ enableColumnResize() {
735
+ let result = false;
736
+ const { columnWidthResizeOption } = this;
737
+ if (columnWidthResizeOption) {
738
+ const { enable } = columnWidthResizeOption;
739
+ if (isBoolean(enable)) {
740
+ result = enable;
741
+ }
742
+ }
743
+ return result;
744
+ },
745
+ // header total height
746
+ headerTotalHeight() {
747
+ let result = 0;
748
+ if (this.showHeader) {
749
+ result = this.headerRows.reduce((total, currentVal) => {
750
+ return currentVal.rowHeight + total;
751
+ }, 0);
752
+ }
753
+ return result;
754
+ },
755
+ // footer total height
756
+ footerTotalHeight() {
757
+ return this.footerRows.reduce((total, currentVal) => {
758
+ return currentVal.rowHeight + total;
759
+ }, 0);
760
+ },
761
+ },
762
+ watch: {
763
+ // watch clone table data
764
+ tableData: {
765
+ handler(newVal, oldVal) {
766
+ this.initVirtualScrollPositions();
767
+ // 第一次不需要触发,仅数据变更触发
768
+ if (oldVal) {
769
+ this.initVirtualScroll();
770
+ }
771
+ },
772
+ immediate: true,
773
+ },
774
+ allRowKeys: {
775
+ handler(newVal) {
776
+ if (Array.isArray(newVal)) {
777
+ const { currentCell } = this.cellSelectionData;
778
+ // 行被移除,清空单元格选中
779
+ if (currentCell.rowIndex > -1) {
780
+ if (newVal.indexOf(currentCell.rowKey) === -1) {
781
+ this.clearCellSelectionCurrentCell();
782
+ }
783
+ }
784
+ }
785
+ },
786
+ immediate: false,
787
+ },
788
+ columns: {
789
+ handler(newVal, oldVal) {
790
+ this.initColumns();
791
+ this.initGroupColumns();
792
+ this.initColumnWidthByColumnResize();
793
+
794
+ // 排除首次
795
+ if (newVal != oldVal && oldVal) {
796
+ this.columnsOptionResetTime++;
797
+ // 需要等待 initColumns 和 initGroupColumns 先执行
798
+ this.initScrolling();
799
+ }
800
+ },
801
+ immediate: true,
802
+ },
803
+ cloneColumns: {
804
+ handler() {
805
+ this.initGroupColumns();
806
+ // 右键(取消)固定列会操作 cloneColumns
807
+ this.initColumnWidthByColumnResize();
808
+
809
+ this.columnsOptionResetTime++;
810
+ // 需要等待 initColumns 和 initGroupColumns 先执行
811
+ this.initScrolling();
812
+ },
813
+ immediate: false,
814
+ },
815
+ // group columns change watch
816
+ groupColumns: {
817
+ handler(val) {
818
+ if (!isEmptyArray(val)) {
819
+ this.initHeaderRows();
820
+ }
821
+ },
822
+ immediate: true,
823
+ },
824
+ // footer data
825
+ footerData: {
826
+ handler(val) {
827
+ if (!isEmptyArray(val)) {
828
+ this.initFooterRows();
829
+ }
830
+ },
831
+ immediate: true,
832
+ },
833
+ /*
834
+ watch virtualScrollOption enable
835
+ 允许按需开启虚拟滚动
836
+ */
837
+ "virtualScrollOption.enable": {
838
+ handler(newVal) {
839
+ // enable virtual scroll
840
+ if (newVal) {
841
+ this.initVirtualScrollPositions();
842
+ this.initVirtualScroll();
843
+ }
844
+ // disable virtual scroll
845
+ else {
846
+ // clear table content top value
847
+ this.setTableContentTopValue({ top: 0 });
848
+ }
849
+ },
850
+ immediate: false,
851
+ },
852
+ // is auto fill starting
853
+ isAutofillStarting: {
854
+ handler(val) {
855
+ if (!val) {
856
+ this.setCellSelectionByAutofill();
857
+ this.clearCellSelectionAutofillEndCell();
858
+ }
859
+ },
860
+ },
861
+ // watch current cell
862
+ "cellSelectionData.currentCell": {
863
+ handler: function () {
864
+ this.setCurrentCellSelectionType();
865
+ },
866
+ deep: true,
867
+ immediate: true,
868
+ },
869
+ // watch normal end cell
870
+ "cellSelectionData.normalEndCell": {
871
+ handler: function () {
872
+ this.setCurrentCellSelectionType();
873
+ },
874
+ deep: true,
875
+ immediate: true,
876
+ },
877
+ // watch header indicator colKeys
878
+ headerIndicatorColKeys: {
879
+ handler: function () {
880
+ this.setRangeCellSelectionByHeaderIndicator();
881
+ },
882
+ deep: true,
883
+ },
884
+ // watch body indicator rowKeys
885
+ bodyIndicatorRowKeys: {
886
+ handler: function () {
887
+ this.setRangeCellSelectionByBodyIndicator();
888
+ },
889
+ deep: true,
890
+ },
891
+ },
892
+
893
+ methods: {
894
+ // int header rows
895
+ initHeaderRows() {
896
+ const { groupColumns } = this;
897
+
898
+ if (Array.isArray(groupColumns)) {
899
+ this.headerRows = groupColumns.map(() => {
900
+ return { rowHeight: 0 };
901
+ });
902
+ }
903
+ },
904
+
905
+ // int footer rows
906
+ initFooterRows() {
907
+ const { footerData } = this;
908
+
909
+ if (Array.isArray(footerData)) {
910
+ this.footerRows = footerData.map(() => {
911
+ return { rowHeight: 0 };
912
+ });
913
+ }
914
+ },
915
+
916
+ // header tr height resize
917
+ headerRowHeightChange({ rowIndex, height }) {
918
+ this.headerRows.splice(rowIndex, 1, { rowHeight: height });
919
+ },
920
+
921
+ // footer row height resize
922
+ footRowHeightChange({ rowIndex, height }) {
923
+ this.footerRows.splice(rowIndex, 1, { rowHeight: height });
924
+ },
925
+
926
+ // body cell width change
927
+ bodyCellWidthChange(colWidths) {
928
+ this.colgroups = this.colgroups.map((item) => {
929
+ item._realTimeWidth = colWidths.get(item.key);
930
+ return item;
931
+ });
932
+
933
+ this.hooks.triggerHook(HOOKS_NAME.TABLE_CELL_WIDTH_CHANGE);
934
+ },
935
+
936
+ // set column width for column resize
937
+ setColumnWidth({ colKey, width }) {
938
+ this.colgroups = this.colgroups.map((item) => {
939
+ if (item.key === colKey) {
940
+ item._columnResizeWidth = width;
941
+ }
942
+ return item;
943
+ });
944
+ this.$nextTick(() => {
945
+ this.setScrollBarStatus();
946
+ });
947
+ this.hooks.triggerHook(HOOKS_NAME.TABLE_CELL_WIDTH_CHANGE);
948
+ },
949
+
950
+ // update colgroups by sort change
951
+ updateColgroupsBySortChange(sortColumns) {
952
+ this.colgroups = this.colgroups.map((item) => {
953
+ // update colgroups by sort columns
954
+ if (Object.keys(sortColumns).indexOf(item.field) > -1) {
955
+ item.sortBy = sortColumns[item.field];
956
+ }
957
+ return item;
958
+ });
959
+ },
960
+
961
+ // init column width by column resize
962
+ initColumnWidthByColumnResize() {
963
+ const { enableColumnResize } = this;
964
+
965
+ const columnDefaultWidth = 50;
966
+ if (enableColumnResize) {
967
+ this.colgroups = this.colgroups.map((item) => {
968
+ let columnWidth = columnDefaultWidth;
969
+ if (isNumber(item.width)) {
970
+ columnWidth = item.width;
971
+ }
972
+ item._columnResizeWidth = columnWidth;
973
+ return item;
974
+ });
975
+ }
976
+ },
977
+
978
+ // init columns
979
+ initColumns() {
980
+ const { columnHiddenOption } = this;
981
+ if (columnHiddenOption) {
982
+ const { defaultHiddenColumnKeys } = columnHiddenOption;
983
+
984
+ if (!isEmptyArray(defaultHiddenColumnKeys)) {
985
+ this.hiddenColumns = defaultHiddenColumnKeys;
986
+ }
987
+ }
988
+
989
+ this.showOrHideColumns();
990
+ },
991
+
992
+ // show or hide columns
993
+ showOrHideColumns() {
994
+ let cloneColumns = cloneDeep(this.columns);
995
+
996
+ cloneColumns = cloneColumns.map((col) => {
997
+ // 操作列默认左固定
998
+ if (col.operationColumn) {
999
+ col.fixed = COLUMN_FIXED_TYPE.LEFT;
1000
+ }
1001
+ return col;
1002
+ });
1003
+
1004
+ const { hiddenColumns } = this;
1005
+
1006
+ if (!isEmptyArray(hiddenColumns)) {
1007
+ // recursive remove column key
1008
+ hiddenColumns.forEach((key) => {
1009
+ cloneColumns = recursiveRemoveColumnByKey(
1010
+ cloneColumns,
1011
+ key,
1012
+ );
1013
+ });
1014
+ }
1015
+
1016
+ this.cloneColumns = cloneColumns;
1017
+ },
1018
+
1019
+ // 初始化分组表头
1020
+ initGroupColumns() {
1021
+ const result = initGroupColumns(this.cloneColumns);
1022
+
1023
+ // set is group header
1024
+ this.isGroupHeader = result.isGroupHeader;
1025
+ // set colgroups
1026
+ this.colgroups = result.colgroups;
1027
+ // set groupColumns
1028
+ this.groupColumns = result.groupColumns;
1029
+ },
1030
+
1031
+ // scroll bar width
1032
+ getScrollBarWidth() {
1033
+ let result = 0;
1034
+
1035
+ const { scrollBarWidth } = this;
1036
+
1037
+ if (scrollBarWidth) {
1038
+ result = scrollBarWidth;
1039
+ } else {
1040
+ result = getScrollbarWidth();
1041
+ this.scrollBarWidth = result;
1042
+ }
1043
+
1044
+ return result;
1045
+ },
1046
+
1047
+ /*
1048
+ * @selectedAllChange
1049
+ * @desc selected all change
1050
+ * @param {bool} isSelected - is selected
1051
+ */
1052
+ selectedAllChange({ isSelected }) {
1053
+ this.broadcast(
1054
+ COMPS_NAME.VE_TABLE_BODY,
1055
+ EMIT_EVENTS.CHECKBOX_SELECTED_ALL_CHANGE,
1056
+ {
1057
+ isSelected,
1058
+ },
1059
+ );
1060
+ },
1061
+
1062
+ /*
1063
+ * @setSelectedAllInfo
1064
+ * @desc set selected all info
1065
+ * @param {bool} isSelected - is selected
1066
+ * @param {bool} isIndeterminate - is indeterminate
1067
+ */
1068
+ setSelectedAllInfo({ isSelected, isIndeterminate }) {
1069
+ this.broadcast(
1070
+ COMPS_NAME.VE_TABLE_HEADER_CHECKBOX_CONTENT,
1071
+ EMIT_EVENTS.CHECKBOX_SELECTED_ALL_INFO,
1072
+ {
1073
+ isSelected,
1074
+ isIndeterminate,
1075
+ },
1076
+ );
1077
+ },
1078
+
1079
+ // cell selection current cell change
1080
+ cellSelectionCurrentCellChange({ rowKey, colKey }) {
1081
+ this.cellSelectionData.currentCell.colKey = colKey;
1082
+ this.cellSelectionData.currentCell.rowKey = rowKey;
1083
+ this.cellSelectionData.currentCell.rowIndex =
1084
+ this.allRowKeys.indexOf(rowKey);
1085
+ },
1086
+
1087
+ // cell selection end cell change
1088
+ cellSelectionNormalEndCellChange({ rowKey, colKey }) {
1089
+ this.cellSelectionData.normalEndCell.colKey = colKey;
1090
+ this.cellSelectionData.normalEndCell.rowKey = rowKey;
1091
+ this.cellSelectionData.normalEndCell.rowIndex =
1092
+ this.allRowKeys.indexOf(rowKey);
1093
+ },
1094
+
1095
+ // cell selection auto fill cell change
1096
+ cellSelectionAutofillCellChange({ rowKey, colKey }) {
1097
+ this.cellSelectionData.autoFillEndCell.colKey = colKey;
1098
+ this.cellSelectionData.autoFillEndCell.rowKey = rowKey;
1099
+ },
1100
+
1101
+ // clear cell selection current cell
1102
+ clearCellSelectionCurrentCell() {
1103
+ this.cellSelectionCurrentCellChange({
1104
+ rowKey: "",
1105
+ colKey: "",
1106
+ rowIndex: -1,
1107
+ });
1108
+ },
1109
+
1110
+ // clear cell selection normal end cell
1111
+ clearCellSelectionNormalEndCell() {
1112
+ this.cellSelectionNormalEndCellChange({
1113
+ rowKey: "",
1114
+ colKey: "",
1115
+ rowIndex: -1,
1116
+ });
1117
+ },
1118
+
1119
+ // clear cell selection autofill end cell
1120
+ clearCellSelectionAutofillEndCell() {
1121
+ this.cellSelectionAutofillCellChange({ rowKey: "", colKey: "" });
1122
+ },
1123
+
1124
+ // header indicator colKeys change
1125
+ headerIndicatorColKeysChange({ startColKey, endColKey }) {
1126
+ const { colgroups } = this;
1127
+ this.headerIndicatorColKeys.startColKey = startColKey;
1128
+ this.headerIndicatorColKeys.startColKeyIndex = colgroups.findIndex(
1129
+ (x) => x.key === startColKey,
1130
+ );
1131
+ this.headerIndicatorColKeys.endColKey = endColKey;
1132
+ this.headerIndicatorColKeys.endColKeyIndex = colgroups.findIndex(
1133
+ (x) => x.key === endColKey,
1134
+ );
1135
+ },
1136
+
1137
+ // clear header indicator colKeys
1138
+ clearHeaderIndicatorColKeys() {
1139
+ this.headerIndicatorColKeys.startColKey = "";
1140
+ this.headerIndicatorColKeys.startColKeyIndex = -1;
1141
+ this.headerIndicatorColKeys.endColKey = "";
1142
+ this.headerIndicatorColKeys.endColKeyIndex = -1;
1143
+ },
1144
+
1145
+ // body indicator rowKeys change
1146
+ bodyIndicatorRowKeysChange({ startRowKey, endRowKey }) {
1147
+ const { allRowKeys } = this;
1148
+ this.bodyIndicatorRowKeys.startRowKey = startRowKey;
1149
+ this.bodyIndicatorRowKeys.startRowKeyIndex =
1150
+ allRowKeys.indexOf(startRowKey);
1151
+ this.bodyIndicatorRowKeys.endRowKey = endRowKey;
1152
+ this.bodyIndicatorRowKeys.endRowKeyIndex =
1153
+ allRowKeys.indexOf(endRowKey);
1154
+ },
1155
+
1156
+ // clear body indicator RowKeys
1157
+ clearBodyIndicatorRowKeys() {
1158
+ this.bodyIndicatorRowKeys.startRowKey = "";
1159
+ this.bodyIndicatorRowKeys.startRowKeyIndex = -1;
1160
+ this.bodyIndicatorRowKeys.endRowKey = "";
1161
+ this.bodyIndicatorRowKeys.endRowKeyIndex = -1;
1162
+ },
1163
+
1164
+ // set cell selection by autofill
1165
+ setCellSelectionByAutofill() {
1166
+ const {
1167
+ cellAutofillOption,
1168
+ cellSelectionRangeData,
1169
+ colgroups,
1170
+ allRowKeys,
1171
+ autofillingDirection,
1172
+ currentCellSelectionType,
1173
+ } = this;
1174
+ const { autoFillEndCell, currentCell } = this.cellSelectionData;
1175
+
1176
+ const { rowKey, colKey } = autoFillEndCell;
1177
+
1178
+ if (isEmptyValue(rowKey) || isEmptyValue(colKey)) {
1179
+ return false;
1180
+ }
1181
+
1182
+ let currentCellData = {};
1183
+ let normalEndCellData = {};
1184
+
1185
+ const { leftColKey, rightColKey, topRowKey, bottomRowKey } =
1186
+ cellSelectionRangeData;
1187
+
1188
+ // cell selection range auto fill
1189
+ if (
1190
+ currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.RANGE
1191
+ ) {
1192
+ if (
1193
+ !isCellInSelectionRange({
1194
+ cellData: autoFillEndCell,
1195
+ cellSelectionRangeData,
1196
+ colgroups,
1197
+ allRowKeys,
1198
+ })
1199
+ ) {
1200
+ if (autofillingDirection === AUTOFILLING_DIRECTION.RIGHT) {
1201
+ currentCellData = {
1202
+ rowKey: topRowKey,
1203
+ colKey: leftColKey,
1204
+ };
1205
+ normalEndCellData = { rowKey: bottomRowKey, colKey };
1206
+ } else if (
1207
+ autofillingDirection === AUTOFILLING_DIRECTION.DOWN
1208
+ ) {
1209
+ currentCellData = {
1210
+ rowKey: topRowKey,
1211
+ colKey: leftColKey,
1212
+ };
1213
+ normalEndCellData = { rowKey, colKey: rightColKey };
1214
+ } else if (
1215
+ autofillingDirection === AUTOFILLING_DIRECTION.UP
1216
+ ) {
1217
+ currentCellData = {
1218
+ rowKey,
1219
+ colKey: leftColKey,
1220
+ };
1221
+ normalEndCellData = {
1222
+ rowKey: bottomRowKey,
1223
+ colKey: rightColKey,
1224
+ };
1225
+ } else if (
1226
+ autofillingDirection === AUTOFILLING_DIRECTION.LEFT
1227
+ ) {
1228
+ currentCellData = { rowKey: topRowKey, colKey };
1229
+ normalEndCellData = {
1230
+ rowKey: bottomRowKey,
1231
+ colKey: rightColKey,
1232
+ };
1233
+ }
1234
+ } else {
1235
+ // return if within the range
1236
+ return false;
1237
+ }
1238
+ }
1239
+ // cell selection single auto fill
1240
+ else if (
1241
+ currentCellSelectionType === CURRENT_CELL_SELECTION_TYPES.SINGLE
1242
+ ) {
1243
+ if (
1244
+ currentCell.rowKey !== rowKey ||
1245
+ currentCell.colKey !== colKey
1246
+ ) {
1247
+ if (autofillingDirection === AUTOFILLING_DIRECTION.RIGHT) {
1248
+ currentCellData = {
1249
+ rowKey,
1250
+ colKey: leftColKey,
1251
+ };
1252
+ normalEndCellData = {
1253
+ rowKey,
1254
+ colKey,
1255
+ };
1256
+ } else if (
1257
+ autofillingDirection === AUTOFILLING_DIRECTION.DOWN
1258
+ ) {
1259
+ currentCellData = {
1260
+ rowKey: topRowKey,
1261
+ colKey: leftColKey,
1262
+ };
1263
+ normalEndCellData = {
1264
+ rowKey,
1265
+ colKey: leftColKey,
1266
+ };
1267
+ } else if (
1268
+ autofillingDirection === AUTOFILLING_DIRECTION.UP
1269
+ ) {
1270
+ currentCellData = {
1271
+ rowKey,
1272
+ colKey: leftColKey,
1273
+ };
1274
+ normalEndCellData = {
1275
+ rowKey: bottomRowKey,
1276
+ colKey: leftColKey,
1277
+ };
1278
+ } else if (
1279
+ autofillingDirection === AUTOFILLING_DIRECTION.LEFT
1280
+ ) {
1281
+ currentCellData = {
1282
+ rowKey,
1283
+ colKey,
1284
+ };
1285
+ normalEndCellData = {
1286
+ rowKey,
1287
+ colKey: rightColKey,
1288
+ };
1289
+ }
1290
+ } else {
1291
+ // return if within the range
1292
+ return false;
1293
+ }
1294
+ }
1295
+
1296
+ const cellAutofillParams = {
1297
+ tableData: this.tableData,
1298
+ allRowKeys: this.allRowKeys,
1299
+ colgroups: this.colgroups,
1300
+ rowKeyFieldName: this.rowKeyFieldName,
1301
+ direction: autofillingDirection,
1302
+ currentCellSelectionType,
1303
+ cellSelectionRangeData,
1304
+ nextCurrentCell: currentCellData,
1305
+ nextNormalEndCell: normalEndCellData,
1306
+ };
1307
+
1308
+ if (cellAutofillOption) {
1309
+ const { beforeAutofill, afterAutofill } = cellAutofillOption;
1310
+
1311
+ if (isFunction(beforeAutofill)) {
1312
+ // before autofill
1313
+ const autofillResponse = cellAutofill({
1314
+ isReplaceData: false,
1315
+ ...cellAutofillParams,
1316
+ });
1317
+ const callback = beforeAutofill(autofillResponse);
1318
+ if (isBoolean(callback) && !callback) {
1319
+ return false;
1320
+ }
1321
+ }
1322
+
1323
+ // after autofill
1324
+ const autofillResponse = cellAutofill({
1325
+ isReplaceData: true,
1326
+ ...cellAutofillParams,
1327
+ });
1328
+ if (isFunction(afterAutofill)) {
1329
+ afterAutofill(autofillResponse);
1330
+ }
1331
+ }
1332
+
1333
+ if (!isEmptyValue(currentCellData.rowKey)) {
1334
+ this.cellSelectionCurrentCellChange({
1335
+ rowKey: currentCellData.rowKey,
1336
+ colKey: currentCellData.colKey,
1337
+ });
1338
+ }
1339
+
1340
+ if (!isEmptyValue(normalEndCellData.rowKey)) {
1341
+ this.cellSelectionNormalEndCellChange({
1342
+ rowKey: normalEndCellData.rowKey,
1343
+ colKey: normalEndCellData.colKey,
1344
+ });
1345
+ }
1346
+ },
1347
+
1348
+ // cell selection range data change
1349
+ cellSelectionRangeDataChange(newData) {
1350
+ this.cellSelectionRangeData = Object.assign(
1351
+ this.cellSelectionRangeData,
1352
+ newData,
1353
+ );
1354
+ },
1355
+
1356
+ // autofilling direction change
1357
+ autofillingDirectionChange(direction) {
1358
+ this.autofillingDirection = direction;
1359
+ },
1360
+
1361
+ // set current cell selection type
1362
+ setCurrentCellSelectionType() {
1363
+ const { currentCell, normalEndCell } = this.cellSelectionData;
1364
+
1365
+ let result;
1366
+
1367
+ if (
1368
+ isEmptyValue(currentCell.rowKey) ||
1369
+ isEmptyValue(currentCell.colKey)
1370
+ ) {
1371
+ result = "";
1372
+ } else {
1373
+ if (
1374
+ !isEmptyValue(normalEndCell.rowKey) &&
1375
+ !isEmptyValue(normalEndCell.colKey)
1376
+ ) {
1377
+ result = CURRENT_CELL_SELECTION_TYPES.RANGE;
1378
+ } else {
1379
+ result = CURRENT_CELL_SELECTION_TYPES.SINGLE;
1380
+ }
1381
+ }
1382
+
1383
+ this.currentCellSelectionType = result;
1384
+ },
1385
+
1386
+ // deal keydown event
1387
+ dealKeydownEvent(event) {
1388
+ const {
1389
+ colgroups,
1390
+ cellSelectionData,
1391
+ enableStopEditing,
1392
+ isCellEditing,
1393
+ } = this;
1394
+
1395
+ const { keyCode, ctrlKey, shiftKey, altKey } = event;
1396
+
1397
+ const { rowKey, colKey } = cellSelectionData.currentCell;
1398
+
1399
+ const currentColumn = colgroups.find((x) => x.key === colKey);
1400
+
1401
+ if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) {
1402
+ switch (keyCode) {
1403
+ case KEY_CODES.TAB: {
1404
+ let direction;
1405
+ if (shiftKey) {
1406
+ direction = CELL_SELECTION_DIRECTION.LEFT;
1407
+ } else {
1408
+ direction = CELL_SELECTION_DIRECTION.RIGHT;
1409
+ }
1410
+
1411
+ this.selectCellByDirection({
1412
+ direction,
1413
+ });
1414
+
1415
+ this.clearCellSelectionNormalEndCell();
1416
+
1417
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
1418
+ event.preventDefault();
1419
+ break;
1420
+ }
1421
+ case KEY_CODES.ARROW_LEFT: {
1422
+ const direction = CELL_SELECTION_DIRECTION.LEFT;
1423
+ if (enableStopEditing) {
1424
+ this.selectCellByDirection({
1425
+ direction,
1426
+ });
1427
+
1428
+ this.clearCellSelectionNormalEndCell();
1429
+
1430
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
1431
+ event.preventDefault();
1432
+ }
1433
+
1434
+ break;
1435
+ }
1436
+ case KEY_CODES.ARROW_RIGHT: {
1437
+ const direction = CELL_SELECTION_DIRECTION.RIGHT;
1438
+
1439
+ if (enableStopEditing) {
1440
+ this.selectCellByDirection({
1441
+ direction,
1442
+ });
1443
+
1444
+ this.clearCellSelectionNormalEndCell();
1445
+
1446
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
1447
+ event.preventDefault();
1448
+ }
1449
+ break;
1450
+ }
1451
+ case KEY_CODES.ARROW_UP: {
1452
+ const direction = CELL_SELECTION_DIRECTION.UP;
1453
+
1454
+ if (enableStopEditing) {
1455
+ this.selectCellByDirection({
1456
+ direction,
1457
+ });
1458
+
1459
+ this.clearCellSelectionNormalEndCell();
1460
+
1461
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
1462
+ event.preventDefault();
1463
+ }
1464
+ break;
1465
+ }
1466
+ case KEY_CODES.ARROW_DOWN: {
1467
+ const direction = CELL_SELECTION_DIRECTION.DOWN;
1468
+
1469
+ if (enableStopEditing) {
1470
+ this.selectCellByDirection({
1471
+ direction,
1472
+ });
1473
+
1474
+ this.clearCellSelectionNormalEndCell();
1475
+
1476
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
1477
+ event.preventDefault();
1478
+ }
1479
+ break;
1480
+ }
1481
+ case KEY_CODES.ENTER: {
1482
+ let direction;
1483
+ // add new line
1484
+ if (altKey) {
1485
+ const editInputEditor =
1486
+ this.$refs[this.editInputRef];
1487
+
1488
+ editInputEditor.textareaAddNewLine();
1489
+ }
1490
+ // direction up
1491
+ else if (shiftKey) {
1492
+ direction = CELL_SELECTION_DIRECTION.UP;
1493
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
1494
+ }
1495
+ // stop editing and stay in current cell
1496
+ else if (ctrlKey) {
1497
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
1498
+ }
1499
+ // direction down
1500
+ else {
1501
+ direction = CELL_SELECTION_DIRECTION.DOWN;
1502
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
1503
+ }
1504
+
1505
+ if (direction) {
1506
+ this.clearCellSelectionNormalEndCell();
1507
+ this.selectCellByDirection({
1508
+ direction,
1509
+ });
1510
+ }
1511
+ event.preventDefault();
1512
+ break;
1513
+ }
1514
+ case KEY_CODES.SPACE: {
1515
+ if (!isCellEditing) {
1516
+ // start editing and enter a space
1517
+ this[INSTANCE_METHODS.START_EDITING_CELL]({
1518
+ rowKey,
1519
+ colKey,
1520
+ defaultValue: " ",
1521
+ });
1522
+ event.preventDefault();
1523
+ }
1524
+
1525
+ break;
1526
+ }
1527
+ case KEY_CODES.BACK_SPACE: {
1528
+ if (!isCellEditing) {
1529
+ // start editing and clear value
1530
+ this[INSTANCE_METHODS.START_EDITING_CELL]({
1531
+ rowKey,
1532
+ colKey,
1533
+ defaultValue: "",
1534
+ });
1535
+ event.preventDefault();
1536
+ }
1537
+
1538
+ break;
1539
+ }
1540
+ case KEY_CODES.DELETE: {
1541
+ if (!isCellEditing) {
1542
+ // delete cell selection range value
1543
+ this.deleteCellSelectionRangeValue();
1544
+ event.preventDefault();
1545
+ }
1546
+
1547
+ break;
1548
+ }
1549
+ case KEY_CODES.F2: {
1550
+ if (!isCellEditing) {
1551
+ if (currentColumn.edit) {
1552
+ // start editing cell and don't allow stop eidting by direction key
1553
+ this.enableStopEditing = false;
1554
+ this[INSTANCE_METHODS.START_EDITING_CELL]({
1555
+ rowKey,
1556
+ colKey,
1557
+ });
1558
+ }
1559
+ event.preventDefault();
1560
+ }
1561
+
1562
+ break;
1563
+ }
1564
+ default: {
1565
+ // enter text directly
1566
+ if (isInputKeyCode(event)) {
1567
+ this[INSTANCE_METHODS.START_EDITING_CELL]({
1568
+ rowKey,
1569
+ colKey,
1570
+ defaultValue: "",
1571
+ });
1572
+ }
1573
+ break;
1574
+ }
1575
+ }
1576
+ }
1577
+ },
1578
+
1579
+ // select cell by direction
1580
+ selectCellByDirection({ direction }) {
1581
+ const { colgroups, allRowKeys, cellSelectionData } = this;
1582
+
1583
+ const { rowKey, colKey } = cellSelectionData.currentCell;
1584
+
1585
+ let columnIndex = colgroups.findIndex((x) => x.key === colKey);
1586
+ let rowIndex = allRowKeys.indexOf(rowKey);
1587
+
1588
+ if (direction === CELL_SELECTION_DIRECTION.LEFT) {
1589
+ if (columnIndex > 0) {
1590
+ let nextColumn = colgroups[columnIndex - 1];
1591
+ this.cellSelectionData.currentCell.colKey = nextColumn.key;
1592
+ this.columnToVisible(nextColumn);
1593
+ }
1594
+ } else if (direction === CELL_SELECTION_DIRECTION.RIGHT) {
1595
+ if (columnIndex < colgroups.length - 1) {
1596
+ let nextColumn = colgroups[columnIndex + 1];
1597
+ this.cellSelectionData.currentCell.colKey = nextColumn.key;
1598
+ this.columnToVisible(nextColumn);
1599
+ }
1600
+ } else if (direction === CELL_SELECTION_DIRECTION.UP) {
1601
+ if (rowIndex > 0) {
1602
+ const nextRowKey = allRowKeys[rowIndex - 1];
1603
+ this.rowToVisible(KEY_CODES.ARROW_UP, nextRowKey);
1604
+ }
1605
+ } else if (direction === CELL_SELECTION_DIRECTION.DOWN) {
1606
+ if (rowIndex < allRowKeys.length - 1) {
1607
+ const nextRowKey = allRowKeys[rowIndex + 1];
1608
+ this.rowToVisible(KEY_CODES.ARROW_DOWN, nextRowKey);
1609
+ }
1610
+ }
1611
+ },
1612
+
1613
+ /*
1614
+ * @columnToVisible
1615
+ * @desc column to visible
1616
+ * @param {object} nextColumn - next column
1617
+ */
1618
+ columnToVisible(nextColumn) {
1619
+ const { hasXScrollBar, colgroups } = this;
1620
+
1621
+ if (!hasXScrollBar) {
1622
+ return false;
1623
+ }
1624
+
1625
+ const tableContainerRef = this.$refs[this.tableContainerRef];
1626
+
1627
+ const { scrollWidth, clientWidth, scrollLeft } = tableContainerRef;
1628
+
1629
+ if (!nextColumn.fixed) {
1630
+ const leftTotalWidth = getNotFixedTotalWidthByColumnKey({
1631
+ colgroups,
1632
+ colKey: nextColumn.key,
1633
+ fixed: COLUMN_FIXED_TYPE.LEFT,
1634
+ });
1635
+
1636
+ const rightTotalWidth = getNotFixedTotalWidthByColumnKey({
1637
+ colgroups,
1638
+ colKey: nextColumn.key,
1639
+ fixed: COLUMN_FIXED_TYPE.RIGHT,
1640
+ });
1641
+
1642
+ if (scrollLeft) {
1643
+ const diff = scrollLeft - leftTotalWidth;
1644
+ if (diff > 0) {
1645
+ tableContainerRef.scrollLeft = scrollLeft - diff;
1646
+ }
1647
+ }
1648
+
1649
+ const scrollRight = scrollWidth - clientWidth - scrollLeft;
1650
+ if (scrollRight) {
1651
+ const diff = scrollRight - rightTotalWidth;
1652
+ if (diff > 0) {
1653
+ tableContainerRef.scrollLeft = scrollLeft + diff;
1654
+ }
1655
+ }
1656
+ }
1657
+ },
1658
+
1659
+ /*
1660
+ * @rowToVisible
1661
+ * @desc row to visible
1662
+ * @param {number} keyCode - current keyCode
1663
+ * @param {any} nextRowKey - next row key
1664
+ */
1665
+ rowToVisible(keyCode, nextRowKey) {
1666
+ const tableContainerRef = this.$refs[this.tableContainerRef];
1667
+ const tableContentWrapperRef =
1668
+ this.$refs[this.tableContentWrapperRef].$el;
1669
+
1670
+ const { isVirtualScroll, headerTotalHeight, footerTotalHeight } =
1671
+ this;
1672
+
1673
+ const {
1674
+ clientHeight: containerClientHeight,
1675
+ scrollTop: containerScrollTop,
1676
+ } = tableContainerRef;
1677
+
1678
+ const nextRowEl = this.$el.querySelector(
1679
+ `tbody tr[${COMPS_CUSTOM_ATTRS.BODY_ROW_KEY}="${nextRowKey}"]`,
1680
+ );
1681
+
1682
+ if (nextRowEl) {
1683
+ const { offsetTop: trOffsetTop, clientHeight: trClientHeight } =
1684
+ nextRowEl;
1685
+
1686
+ const parentOffsetTop = tableContentWrapperRef.offsetTop;
1687
+
1688
+ // arrow up
1689
+ if (keyCode === KEY_CODES.ARROW_UP) {
1690
+ let diff = 0;
1691
+ if (isVirtualScroll) {
1692
+ diff =
1693
+ headerTotalHeight -
1694
+ (trOffsetTop -
1695
+ (containerScrollTop - parentOffsetTop));
1696
+ } else {
1697
+ diff =
1698
+ containerScrollTop +
1699
+ headerTotalHeight -
1700
+ trOffsetTop;
1701
+ }
1702
+
1703
+ if (diff > 0) {
1704
+ tableContainerRef.scrollTop = containerScrollTop - diff;
1705
+ }
1706
+ }
1707
+ // arrow down
1708
+ else if (keyCode === KEY_CODES.ARROW_DOWN) {
1709
+ let diff = 0;
1710
+ if (isVirtualScroll) {
1711
+ diff =
1712
+ trOffsetTop -
1713
+ (containerScrollTop - parentOffsetTop) +
1714
+ trClientHeight +
1715
+ footerTotalHeight -
1716
+ containerClientHeight;
1717
+ } else {
1718
+ diff =
1719
+ trOffsetTop +
1720
+ trClientHeight +
1721
+ footerTotalHeight -
1722
+ (containerClientHeight + containerScrollTop);
1723
+ }
1724
+
1725
+ if (diff >= 0) {
1726
+ tableContainerRef.scrollTop = containerScrollTop + diff;
1727
+ }
1728
+ }
1729
+ const { currentCell } = this.cellSelectionData;
1730
+ this.cellSelectionCurrentCellChange({
1731
+ rowKey: nextRowKey,
1732
+ colKey: currentCell.colKey,
1733
+ });
1734
+ }
1735
+ },
1736
+
1737
+ // set virtual scroll visible data
1738
+ setVirtualScrollVisibleData() {
1739
+ const { tableData } = this;
1740
+
1741
+ const startIndex = this.virtualScrollStartIndex;
1742
+ const endIndex = this.virtualScrollEndIndex;
1743
+
1744
+ const aboveCount = this.getVirtualScrollAboveCount();
1745
+ const belowCount = this.getVirtualScrollBelowCount();
1746
+
1747
+ let start = startIndex - aboveCount;
1748
+ let end = endIndex + belowCount;
1749
+
1750
+ this.virtualScrollVisibleIndexs.start = start;
1751
+ this.virtualScrollVisibleIndexs.end = end - 1;
1752
+
1753
+ this.virtualScrollVisibleData = tableData.slice(start, end);
1754
+ },
1755
+
1756
+ // get virtual scroll above count
1757
+ getVirtualScrollAboveCount() {
1758
+ let result = 0;
1759
+ const { isVirtualScroll, virtualScrollBufferCount } = this;
1760
+
1761
+ const virtualScrollStartIndex = this.virtualScrollStartIndex;
1762
+
1763
+ if (isVirtualScroll) {
1764
+ result = Math.min(
1765
+ virtualScrollStartIndex,
1766
+ virtualScrollBufferCount,
1767
+ );
1768
+ }
1769
+ return result;
1770
+ },
1771
+
1772
+ // get virtual scroll bellow count
1773
+ getVirtualScrollBelowCount() {
1774
+ let result = 0;
1775
+
1776
+ const { isVirtualScroll, tableData, virtualScrollBufferCount } =
1777
+ this;
1778
+
1779
+ const virtualScrollEndIndex = this.virtualScrollEndIndex;
1780
+
1781
+ if (isVirtualScroll) {
1782
+ result = Math.min(
1783
+ tableData.length - virtualScrollEndIndex,
1784
+ virtualScrollBufferCount,
1785
+ );
1786
+ }
1787
+
1788
+ return result;
1789
+ },
1790
+
1791
+ // get virtual phantom
1792
+ getVirtualViewPhantom() {
1793
+ let content = null;
1794
+
1795
+ /*
1796
+ 1、is virtualScroll
1797
+ or
1798
+ 2、
1799
+ has left fixed column and expand option(resolve expand row content sticky)
1800
+ */
1801
+ const { isVirtualScroll, hasLeftFixedColumn, expandOption } = this;
1802
+
1803
+ if (isVirtualScroll || (hasLeftFixedColumn && expandOption)) {
1804
+ const props = {
1805
+ props: {
1806
+ tagName: "div",
1807
+ },
1808
+ style: {
1809
+ width: "100%",
1810
+ },
1811
+ on: {
1812
+ "on-dom-resize-change": ({ width }) => {
1813
+ this.tableViewportWidth = width;
1814
+ },
1815
+ },
1816
+ };
1817
+
1818
+ content = (
1819
+ <div
1820
+ ref={this.virtualPhantomRef}
1821
+ class={[
1822
+ clsName("virtual-phantom"),
1823
+ isVirtualScroll ? clsName("virtual-scroll") : "",
1824
+ ]}
1825
+ >
1826
+ <VueDomResizeObserver {...props} />
1827
+ </div>
1828
+ );
1829
+ }
1830
+
1831
+ return content;
1832
+ },
1833
+
1834
+ // init virtual scroll positions
1835
+ initVirtualScrollPositions() {
1836
+ if (this.isVirtualScroll) {
1837
+ const {
1838
+ virtualScrollOption,
1839
+ rowKeyFieldName,
1840
+ tableData,
1841
+ defaultVirtualScrollMinRowHeight,
1842
+ } = this;
1843
+
1844
+ const minRowHeight = isNumber(virtualScrollOption.minRowHeight)
1845
+ ? virtualScrollOption.minRowHeight
1846
+ : defaultVirtualScrollMinRowHeight;
1847
+
1848
+ this.virtualScrollPositions = tableData.map((item, index) => ({
1849
+ rowKey: item[rowKeyFieldName],
1850
+ height: minRowHeight,
1851
+ top: index * minRowHeight,
1852
+ bottom: (index + 1) * minRowHeight,
1853
+ }));
1854
+ }
1855
+ },
1856
+
1857
+ // list item height change
1858
+ bodyRowHeightChange({ rowKey, height }) {
1859
+ //获取真实元素大小,修改对应的尺寸缓存
1860
+ const index = this.virtualScrollPositions.findIndex(
1861
+ (x) => x.rowKey === rowKey,
1862
+ );
1863
+
1864
+ let oldHeight = this.virtualScrollPositions[index].height;
1865
+ let dValue = oldHeight - height;
1866
+ //存在差值
1867
+ if (dValue) {
1868
+ this.virtualScrollPositions[index].bottom =
1869
+ this.virtualScrollPositions[index].bottom - dValue;
1870
+ this.virtualScrollPositions[index].height = height;
1871
+ for (
1872
+ let k = index + 1;
1873
+ k < this.virtualScrollPositions.length;
1874
+ k++
1875
+ ) {
1876
+ this.virtualScrollPositions[k].top =
1877
+ this.virtualScrollPositions[k - 1].bottom;
1878
+ this.virtualScrollPositions[k].bottom =
1879
+ this.virtualScrollPositions[k].bottom - dValue;
1880
+ }
1881
+
1882
+ // 更新 virtual phantom 列表总高度
1883
+ this.setVirtualPhantomHeight();
1884
+
1885
+ //更新真实偏移量
1886
+ this.setVirtualScrollStartOffset();
1887
+ }
1888
+ },
1889
+ // update virtual phantom list height
1890
+ setVirtualPhantomHeight() {
1891
+ let totalHeight = 0;
1892
+ if (this.virtualScrollPositions.length) {
1893
+ totalHeight =
1894
+ this.virtualScrollPositions[
1895
+ this.virtualScrollPositions.length - 1
1896
+ ].bottom;
1897
+ }
1898
+
1899
+ this.$refs[this.virtualPhantomRef].style.height =
1900
+ totalHeight + "px";
1901
+ },
1902
+ // set virtual scroll start offset
1903
+ setVirtualScrollStartOffset() {
1904
+ const start = this.virtualScrollStartIndex;
1905
+
1906
+ const aboveCount = this.getVirtualScrollAboveCount();
1907
+
1908
+ let startOffset = 0;
1909
+
1910
+ if (start >= 1) {
1911
+ let size =
1912
+ this.virtualScrollPositions[start].top -
1913
+ (this.virtualScrollPositions[start - aboveCount]
1914
+ ? this.virtualScrollPositions[start - aboveCount].top
1915
+ : 0);
1916
+ startOffset =
1917
+ this.virtualScrollPositions[start - 1].bottom - size;
1918
+ }
1919
+
1920
+ this.setTableContentTopValue({ top: startOffset });
1921
+ },
1922
+ // set table content top value
1923
+ setTableContentTopValue({ top }) {
1924
+ //this.$refs[this.tableContentWrapperRef].style.transform = `translate3d(0,${startOffset}px,0)`;
1925
+ window.requestAnimationFrame(() => {
1926
+ const ele = this.$refs[this.tableContentWrapperRef];
1927
+ if (ele) {
1928
+ ele.$el.style.top = `${top}px`;
1929
+ }
1930
+ });
1931
+ },
1932
+ // get virtual scroll start index
1933
+ getVirtualScrollStartIndex(scrollTop = 0) {
1934
+ return this.virtualScrollBinarySearch(
1935
+ this.virtualScrollPositions,
1936
+ scrollTop,
1937
+ );
1938
+ },
1939
+ // virtual scroll binary search
1940
+ virtualScrollBinarySearch(list, value) {
1941
+ let start = 0;
1942
+ let end = list.length - 1;
1943
+ let tempIndex = null;
1944
+
1945
+ while (start <= end) {
1946
+ let midIndex = parseInt((start + end) / 2);
1947
+ let midValue = list[midIndex].bottom;
1948
+ if (midValue === value) {
1949
+ return midIndex + 1;
1950
+ } else if (midValue < value) {
1951
+ start = midIndex + 1;
1952
+ } else if (midValue > value) {
1953
+ if (tempIndex === null || tempIndex > midIndex) {
1954
+ tempIndex = midIndex;
1955
+ }
1956
+ end = end - 1;
1957
+ }
1958
+ }
1959
+ return tempIndex;
1960
+ },
1961
+ // table container virtual scroll handler
1962
+ tableContainerVirtualScrollHandler(tableContainerRef) {
1963
+ const {
1964
+ virtualScrollVisibleCount: visibleCount,
1965
+ virtualScrollOption,
1966
+ } = this;
1967
+
1968
+ //当前滚动位置
1969
+ let scrollTop = tableContainerRef.scrollTop;
1970
+
1971
+ //此时的开始索引
1972
+ let visibleStartIndex = this.getVirtualScrollStartIndex(scrollTop);
1973
+ this.virtualScrollStartIndex = visibleStartIndex;
1974
+
1975
+ //此时的结束索引
1976
+ let visibleEndIndex = visibleStartIndex + visibleCount;
1977
+ this.virtualScrollEndIndex = visibleEndIndex;
1978
+
1979
+ const visibleAboveCount = this.getVirtualScrollAboveCount();
1980
+ const visibleBelowCount = this.getVirtualScrollBelowCount();
1981
+
1982
+ //此时的偏移量
1983
+ this.setVirtualScrollStartOffset();
1984
+
1985
+ if (!this.showVirtualScrollingPlaceholder) {
1986
+ const bodyElement = this.$refs[this.tableBodyRef];
1987
+
1988
+ if (bodyElement) {
1989
+ bodyElement.renderingRowKeys(
1990
+ this.allRowKeys.slice(
1991
+ visibleStartIndex - visibleAboveCount,
1992
+ visibleEndIndex + visibleBelowCount,
1993
+ ),
1994
+ );
1995
+ }
1996
+ }
1997
+
1998
+ const { scrolling } = virtualScrollOption;
1999
+ if (isFunction(scrolling)) {
2000
+ const visibleAboveCount = this.getVirtualScrollAboveCount();
2001
+ const visibleBelowCount = this.getVirtualScrollBelowCount();
2002
+
2003
+ let startRowIndex = visibleStartIndex - visibleAboveCount;
2004
+
2005
+ scrolling({
2006
+ startRowIndex: startRowIndex > 0 ? startRowIndex : 0,
2007
+ visibleStartIndex,
2008
+ visibleEndIndex,
2009
+ visibleAboveCount,
2010
+ visibleBelowCount,
2011
+ });
2012
+ }
2013
+
2014
+ this.setVirtualScrollVisibleData();
2015
+ },
2016
+ // debounce scroll ended
2017
+ debounceScrollEnded() {
2018
+ const scrollingResetTimeInterval = 150;
2019
+
2020
+ const { disablePointerEventsTimeoutId } = this;
2021
+
2022
+ if (disablePointerEventsTimeoutId) {
2023
+ cancelAnimationTimeout(disablePointerEventsTimeoutId);
2024
+ }
2025
+
2026
+ this.disablePointerEventsTimeoutId = requestAnimationTimeout(
2027
+ this.debounceScrollEndedCallback,
2028
+ scrollingResetTimeInterval,
2029
+ );
2030
+ },
2031
+ // debounce scroll callback
2032
+ debounceScrollEndedCallback() {
2033
+ this.disablePointerEventsTimeoutId = null;
2034
+ this.showVirtualScrollingPlaceholder = false;
2035
+ },
2036
+ // init virtual scroll
2037
+ initVirtualScroll() {
2038
+ if (this.isVirtualScroll) {
2039
+ const startIndex = 0;
2040
+
2041
+ this.virtualScrollStartIndex = startIndex;
2042
+ this.virtualScrollEndIndex =
2043
+ startIndex + this.virtualScrollVisibleCount;
2044
+
2045
+ // 修复渲染结束,同时开启虚拟滚动和设置表格数据,无法设置 virtual phantom 高度的问题
2046
+ this.$nextTick(() => {
2047
+ const tableContainerRef =
2048
+ this.$refs[this.tableContainerRef];
2049
+ this.tableContainerVirtualScrollHandler(tableContainerRef);
2050
+ this.setVirtualPhantomHeight();
2051
+ });
2052
+ }
2053
+ },
2054
+
2055
+ // set scrolling
2056
+ setScrolling(tableContainerRef) {
2057
+ if (this.hasFixedColumn) {
2058
+ const { scrollWidth, clientWidth, scrollLeft } =
2059
+ tableContainerRef;
2060
+
2061
+ const { previewTableContainerScrollLeft: previewScrollLeft } =
2062
+ this;
2063
+
2064
+ // 仅横向滚动需要处理
2065
+ if (
2066
+ previewScrollLeft === 0 ||
2067
+ previewScrollLeft !== scrollLeft
2068
+ ) {
2069
+ this.previewTableContainerScrollLeft = scrollLeft;
2070
+
2071
+ this.isLeftScrolling = scrollLeft > 0;
2072
+ this.isRightScrolling =
2073
+ scrollWidth - clientWidth > scrollLeft;
2074
+ }
2075
+ this.isLeftScrolling = scrollLeft > 0;
2076
+ this.isRightScrolling = scrollWidth - clientWidth > scrollLeft;
2077
+ }
2078
+
2079
+ if (this.fixedHeader) {
2080
+ const { scrollTop } = tableContainerRef;
2081
+ this.isVerticalScrolling = scrollTop > 0;
2082
+ }
2083
+ },
2084
+
2085
+ // set scroll bar status
2086
+ setScrollBarStatus() {
2087
+ const tableContainerRef = this.$refs[this.tableContainerRef];
2088
+ if (tableContainerRef) {
2089
+ const { scrollWidth, clientWidth, scrollHeight, clientHeight } =
2090
+ tableContainerRef;
2091
+
2092
+ if (scrollWidth && clientWidth) {
2093
+ this.hasXScrollBar =
2094
+ scrollWidth - clientWidth ? true : false;
2095
+ }
2096
+
2097
+ if (scrollHeight && clientHeight) {
2098
+ this.hasYScrollBar =
2099
+ scrollHeight - clientHeight ? true : false;
2100
+ }
2101
+ }
2102
+ },
2103
+
2104
+ // init scrolling
2105
+ initScrolling() {
2106
+ this.setScrolling(this.$refs[this.tableContainerRef]);
2107
+ },
2108
+
2109
+ // table click outside
2110
+ tableClickOutside(e) {
2111
+ // exclude contextmenu panel clicked
2112
+ if (isContextmenuPanelClicked(e)) {
2113
+ return false;
2114
+ }
2115
+
2116
+ this.isHeaderCellMousedown = false;
2117
+ this.isBodyCellMousedown = false;
2118
+ this.isBodyOperationColumnMousedown = false;
2119
+ this.isAutofillStarting = false;
2120
+ this.setIsColumnResizing(false);
2121
+
2122
+ // clear cell selection
2123
+ this.clearCellSelectionCurrentCell();
2124
+ this.clearCellSelectionNormalEndCell();
2125
+
2126
+ // clear indicators
2127
+ this.clearHeaderIndicatorColKeys();
2128
+ this.clearBodyIndicatorRowKeys();
2129
+
2130
+ // stop editing cell
2131
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
2132
+ },
2133
+
2134
+ // save cell when stop editing
2135
+ saveCellWhenStopEditing() {
2136
+ const {
2137
+ colgroups,
2138
+ rowKeyFieldName,
2139
+ editOption,
2140
+ editingCell,
2141
+ isCellEditing,
2142
+ } = this;
2143
+
2144
+ const {
2145
+ cellValueChange,
2146
+ beforeCellValueChange,
2147
+ afterCellValueChange,
2148
+ } = editOption;
2149
+
2150
+ if (isCellEditing) {
2151
+ const { rowKey, colKey } = editingCell;
2152
+
2153
+ let currentRow = this.tableData.find(
2154
+ (x) => x[rowKeyFieldName] === rowKey,
2155
+ );
2156
+
2157
+ if (currentRow) {
2158
+ const currentColumn = colgroups.find(
2159
+ (x) => x.key === colKey,
2160
+ );
2161
+
2162
+ const changeValue = editingCell.row[currentColumn.field];
2163
+
2164
+ if (isFunction(beforeCellValueChange)) {
2165
+ const allowChange = beforeCellValueChange({
2166
+ row: cloneDeep(currentRow),
2167
+ column: currentColumn,
2168
+ changeValue,
2169
+ });
2170
+ if (isBoolean(allowChange) && !allowChange) {
2171
+ // celar editing cell
2172
+ this.clearEditingCell();
2173
+ return false;
2174
+ }
2175
+ }
2176
+
2177
+ currentRow[currentColumn.field] = changeValue;
2178
+
2179
+ // 同 afterCellValueChange,未来被移除
2180
+ cellValueChange &&
2181
+ cellValueChange({
2182
+ row: currentRow,
2183
+ column: currentColumn,
2184
+ changeValue,
2185
+ });
2186
+
2187
+ afterCellValueChange &&
2188
+ afterCellValueChange({
2189
+ row: currentRow,
2190
+ column: currentColumn,
2191
+ changeValue,
2192
+ });
2193
+
2194
+ // celar editing cell
2195
+ this.clearEditingCell();
2196
+ }
2197
+
2198
+ // reset status
2199
+ this.enableStopEditing = true;
2200
+ }
2201
+ },
2202
+
2203
+ // cell selection by click
2204
+ cellSelectionByClick({ rowData, column }) {
2205
+ const { rowKeyFieldName } = this;
2206
+
2207
+ const rowKey = getRowKey(rowData, rowKeyFieldName);
2208
+
2209
+ // set cell selection and column to visible
2210
+ this[INSTANCE_METHODS.SET_CELL_SELECTION]({
2211
+ rowKey,
2212
+ colKey: column.key,
2213
+ isScrollToRow: false,
2214
+ });
2215
+ // row to visible
2216
+ this.rowToVisible(KEY_CODES.ARROW_UP, rowKey);
2217
+ this.rowToVisible(KEY_CODES.ARROW_DOWN, rowKey);
2218
+ },
2219
+
2220
+ /*
2221
+ * @bodyCellContextmenu
2222
+ * @desc recieve td right click\contextmenu event
2223
+ * @param {object} rowData - row data
2224
+ * @param {object} column - column data
2225
+ */
2226
+ bodyCellContextmenu({ event, rowData, column }) {
2227
+ const { editOption, rowKeyFieldName } = this;
2228
+
2229
+ if (editOption) {
2230
+ const rowKey = getRowKey(rowData, rowKeyFieldName);
2231
+ this.editCellByClick({
2232
+ isDblclick: false,
2233
+ rowKey,
2234
+ colKey: column.key,
2235
+ });
2236
+ }
2237
+
2238
+ this.setContextmenuOptions(column);
2239
+ },
2240
+
2241
+ /*
2242
+ * @bodyCellDoubleClick
2243
+ * @desc recieve td double click event
2244
+ * @param {object} rowData - row data
2245
+ * @param {object} column - column data
2246
+ */
2247
+ bodyCellDoubleClick({ event, rowData, column }) {
2248
+ const { editOption, rowKeyFieldName, colgroups } = this;
2249
+
2250
+ if (isOperationColumn(column.key, colgroups)) {
2251
+ // clear cell selection
2252
+ this.clearCellSelectionCurrentCell();
2253
+ this.clearCellSelectionNormalEndCell();
2254
+
2255
+ // stop editing cell
2256
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
2257
+ return false;
2258
+ }
2259
+
2260
+ if (editOption) {
2261
+ const rowKey = getRowKey(rowData, rowKeyFieldName);
2262
+ this.editCellByClick({
2263
+ isDblclick: true,
2264
+ rowKey,
2265
+ colKey: column.key,
2266
+ });
2267
+ }
2268
+ },
2269
+
2270
+ /*
2271
+ * @bodyCellClick
2272
+ * @desc recieve td click event
2273
+ * @param {object} rowData - row data
2274
+ * @param {object} column - column data
2275
+ */
2276
+ bodyCellClick({ event, rowData, column }) {
2277
+ // feature...
2278
+ },
2279
+
2280
+ /*
2281
+ * @bodyCellMousedown
2282
+ * @desc recieve td mousedown event
2283
+ * @param {object} rowData - row data
2284
+ * @param {object} column - column data
2285
+ */
2286
+ bodyCellMousedown({ event, rowData, column }) {
2287
+ if (!this.enableCellSelection) {
2288
+ return false;
2289
+ }
2290
+
2291
+ const { shiftKey } = event;
2292
+
2293
+ const {
2294
+ editOption,
2295
+ rowKeyFieldName,
2296
+ colgroups,
2297
+ cellSelectionData,
2298
+ cellSelectionRangeData,
2299
+ allRowKeys,
2300
+ } = this;
2301
+
2302
+ const rowKey = getRowKey(rowData, rowKeyFieldName);
2303
+ const colKey = column.key;
2304
+
2305
+ const { currentCell } = cellSelectionData;
2306
+
2307
+ const mouseEventClickType = getMouseEventClickType(event);
2308
+
2309
+ if (isOperationColumn(colKey, colgroups)) {
2310
+ // clear header indicator colKeys
2311
+ this.clearHeaderIndicatorColKeys();
2312
+
2313
+ const { bodyIndicatorRowKeys } = this;
2314
+ this.isBodyOperationColumnMousedown = true;
2315
+
2316
+ const {
2317
+ startRowKey,
2318
+ endRowKey,
2319
+ startRowKeyIndex,
2320
+ endRowKeyIndex,
2321
+ } = bodyIndicatorRowKeys;
2322
+ let newStartRowKey = startRowKey;
2323
+ let newEndRowKey = endRowKey;
2324
+
2325
+ if (
2326
+ shiftKey &&
2327
+ (startRowKeyIndex > -1 || currentCell.rowIndex > -1)
2328
+ ) {
2329
+ newStartRowKey = isEmptyValue(currentCell.rowKey)
2330
+ ? startRowKey
2331
+ : currentCell.rowKey;
2332
+ newEndRowKey = rowKey;
2333
+ } else {
2334
+ const currentRowIndex = allRowKeys.indexOf(rowKey);
2335
+
2336
+ // 左键点击 || 不在当前选择行内
2337
+ if (
2338
+ mouseEventClickType ===
2339
+ MOUSE_EVENT_CLICK_TYPE.LEFT_MOUSE ||
2340
+ currentRowIndex < startRowKeyIndex ||
2341
+ currentRowIndex > endRowKeyIndex
2342
+ ) {
2343
+ newStartRowKey = rowKey;
2344
+ newEndRowKey = rowKey;
2345
+ }
2346
+ }
2347
+
2348
+ this.bodyIndicatorRowKeysChange({
2349
+ startRowKey: newStartRowKey,
2350
+ endRowKey: newEndRowKey,
2351
+ });
2352
+ } else {
2353
+ // body cell mousedown
2354
+ this.isBodyCellMousedown = true;
2355
+
2356
+ const isClearByRightClick =
2357
+ isClearSelectionByBodyCellRightClick({
2358
+ mouseEventClickType,
2359
+ cellData: {
2360
+ rowKey,
2361
+ colKey,
2362
+ },
2363
+ cellSelectionData,
2364
+ cellSelectionRangeData,
2365
+ colgroups,
2366
+ allRowKeys,
2367
+ });
2368
+
2369
+ if (isClearByRightClick) {
2370
+ // clear header indicator colKeys
2371
+ this.clearHeaderIndicatorColKeys();
2372
+ // clear body indicator colKeys
2373
+ this.clearBodyIndicatorRowKeys();
2374
+
2375
+ if (shiftKey && currentCell.rowIndex > -1) {
2376
+ this.cellSelectionNormalEndCellChange({
2377
+ rowKey,
2378
+ colKey,
2379
+ });
2380
+ } else {
2381
+ // cell selection by click
2382
+ this.cellSelectionByClick({ rowData, column });
2383
+ this.clearCellSelectionNormalEndCell();
2384
+ }
2385
+ }
2386
+ }
2387
+
2388
+ if (editOption) {
2389
+ this.editCellByClick({
2390
+ isDblclick: false,
2391
+ rowKey,
2392
+ colKey,
2393
+ });
2394
+ }
2395
+ },
2396
+
2397
+ /*
2398
+ * @bodyCellMouseover
2399
+ * @desc recieve td mouseover event
2400
+ * @param {object} rowData - row data
2401
+ * @param {object} column - column data
2402
+ */
2403
+ bodyCellMouseover({ event, rowData, column }) {
2404
+ const {
2405
+ rowKeyFieldName,
2406
+ isBodyCellMousedown,
2407
+ isAutofillStarting,
2408
+ isHeaderCellMousedown,
2409
+ isBodyOperationColumnMousedown,
2410
+ } = this;
2411
+
2412
+ const rowKey = getRowKey(rowData, rowKeyFieldName);
2413
+ const colKey = column.key;
2414
+
2415
+ if (isBodyCellMousedown) {
2416
+ // 操作列不能单元格选中
2417
+ if (isOperationColumn(colKey, this.colgroups)) {
2418
+ return false;
2419
+ }
2420
+ this.cellSelectionNormalEndCellChange({
2421
+ rowKey,
2422
+ colKey,
2423
+ });
2424
+ }
2425
+
2426
+ if (isBodyOperationColumnMousedown) {
2427
+ this.bodyIndicatorRowKeysChange({
2428
+ startRowKey: this.bodyIndicatorRowKeys.startRowKey,
2429
+ endRowKey: rowKey,
2430
+ });
2431
+ }
2432
+
2433
+ // 允许在body cell mouseover 里补充 header indicator 信息
2434
+ if (isHeaderCellMousedown) {
2435
+ this.headerIndicatorColKeysChange({
2436
+ startColKey: this.headerIndicatorColKeys.startColKey,
2437
+ endColKey: colKey,
2438
+ });
2439
+ }
2440
+
2441
+ if (isAutofillStarting) {
2442
+ // 操作列不能autofilling 效果
2443
+ if (isOperationColumn(colKey, this.colgroups)) {
2444
+ return false;
2445
+ }
2446
+ this.cellSelectionAutofillCellChange({
2447
+ rowKey,
2448
+ colKey,
2449
+ });
2450
+ }
2451
+ },
2452
+
2453
+ /*
2454
+ * @bodyCellMousemove
2455
+ * @desc recieve td mousemove event
2456
+ * @param {object} rowData - row data
2457
+ * @param {object} column - column data
2458
+ */
2459
+ bodyCellMousemove({ event, rowData, column }) {
2460
+ this.hooks.triggerHook(HOOKS_NAME.BODY_CELL_MOUSEMOVE, {
2461
+ event,
2462
+ column,
2463
+ });
2464
+ },
2465
+
2466
+ /*
2467
+ * @bodyCellMouseup
2468
+ * @desc recieve td mouseup event
2469
+ * @param {object} rowData - row data
2470
+ * @param {object} column - column data
2471
+ */
2472
+ bodyCellMouseup({ event, rowData, column }) {
2473
+ // feature...
2474
+ },
2475
+
2476
+ // header cell click
2477
+ headerCellClick({ event, column }) {
2478
+ // feature...
2479
+ },
2480
+
2481
+ // header cell contextmenu
2482
+ headerCellContextmenu({ event, column }) {
2483
+ this.setContextmenuOptions(column);
2484
+ },
2485
+
2486
+ // set contextmenu options
2487
+ setContextmenuOptions(column) {
2488
+ const { contextMenuType } = this;
2489
+
2490
+ // header contextmenu
2491
+ if (contextMenuType === CONTEXTMENU_TYPES.HEADER_CONTEXTMENU) {
2492
+ // set header contextmenu options before contextmen show
2493
+ this.contextmenuOptions = setHeaderContextmenuOptions({
2494
+ column,
2495
+ contextmenuHeaderOption: this.contextmenuHeaderOption,
2496
+ cellSelectionRangeData: this.cellSelectionRangeData,
2497
+ colgroups: this.colgroups,
2498
+ allRowKeys: this.allRowKeys,
2499
+ headerIndicatorColKeys: this.headerIndicatorColKeys,
2500
+ enableHeaderContextmenu: this.enableHeaderContextmenu,
2501
+ t,
2502
+ });
2503
+ }
2504
+ // body contextmenu
2505
+ else {
2506
+ // set body contextmenu options before contextmen show
2507
+ this.contextmenuOptions = setBodyContextmenuOptions({
2508
+ enableBodyContextmenu: this.enableBodyContextmenu,
2509
+ contextmenuBodyOption: this.contextmenuBodyOption,
2510
+ cellSelectionRangeData: this.cellSelectionRangeData,
2511
+ colgroups: this.colgroups,
2512
+ allRowKeys: this.allRowKeys,
2513
+ bodyIndicatorRowKeys: this.bodyIndicatorRowKeys,
2514
+ t,
2515
+ });
2516
+ }
2517
+ },
2518
+
2519
+ // header cell mousedown
2520
+ headerCellMousedown({ event, column }) {
2521
+ if (!this.enableCellSelection) {
2522
+ return false;
2523
+ }
2524
+
2525
+ this.isHeaderCellMousedown = true;
2526
+
2527
+ const { shiftKey } = event;
2528
+
2529
+ const {
2530
+ isGroupHeader,
2531
+ colgroups,
2532
+ headerIndicatorColKeys,
2533
+ cellSelectionData,
2534
+ } = this;
2535
+
2536
+ // clear body indicator colKeys
2537
+ this.clearBodyIndicatorRowKeys();
2538
+
2539
+ let colKeys;
2540
+ if (isGroupHeader) {
2541
+ colKeys = getColKeysByHeaderColumn({
2542
+ headerColumnItem: column,
2543
+ });
2544
+ } else {
2545
+ colKeys = [column.key];
2546
+ }
2547
+
2548
+ const currentCellStartColKey = colKeys[0];
2549
+ const currentCellEndColKey = colKeys[colKeys.length - 1];
2550
+
2551
+ const { currentCell } = cellSelectionData;
2552
+
2553
+ if (isOperationColumn(column.key, colgroups)) {
2554
+ // clear cell selection
2555
+ this.clearCellSelectionCurrentCell();
2556
+ this.clearCellSelectionNormalEndCell();
2557
+ this.$nextTick(() => {
2558
+ // select all cell
2559
+ this[INSTANCE_METHODS.SET_ALL_CELL_SELECTION]();
2560
+ });
2561
+ return false;
2562
+ }
2563
+
2564
+ // 需要先将之前选中单元格元素清空
2565
+ if (isEmptyValue(headerIndicatorColKeys.startColKey)) {
2566
+ // 值的比较(currentCell.colKey 会变化)
2567
+ if (
2568
+ JSON.stringify(colKeys) !=
2569
+ JSON.stringify([currentCell.colKey])
2570
+ ) {
2571
+ this.$refs[this.cellSelectionRef].clearCurrentCellRect();
2572
+ }
2573
+ this.$refs[this.cellSelectionRef].clearNormalEndCellRect();
2574
+ }
2575
+
2576
+ const { startColKey, endColKey, startColKeyIndex, endColKeyIndex } =
2577
+ headerIndicatorColKeys;
2578
+
2579
+ let newStartColKey = startColKey;
2580
+ let newEndColKey = endColKey;
2581
+ if (shiftKey) {
2582
+ if (isEmptyValue(startColKey)) {
2583
+ if (!isEmptyValue(currentCell.colKey)) {
2584
+ const leftColKey = getLeftmostColKey({
2585
+ colgroups,
2586
+ colKeys: colKeys.concat([currentCell.colKey]),
2587
+ });
2588
+
2589
+ newStartColKey = currentCell.colKey;
2590
+ if (leftColKey === currentCell.colKey) {
2591
+ newEndColKey = currentCellEndColKey;
2592
+ } else {
2593
+ newEndColKey = currentCellStartColKey;
2594
+ }
2595
+ } else {
2596
+ newStartColKey = currentCellStartColKey;
2597
+ newEndColKey = currentCellEndColKey;
2598
+ }
2599
+ } else {
2600
+ newStartColKey = startColKey;
2601
+ const leftColKey = getLeftmostColKey({
2602
+ colgroups,
2603
+ colKeys: colKeys.concat([startColKey]),
2604
+ });
2605
+
2606
+ if (leftColKey === startColKey) {
2607
+ newEndColKey = currentCellEndColKey;
2608
+ } else {
2609
+ newEndColKey = currentCellStartColKey;
2610
+ }
2611
+ }
2612
+ } else {
2613
+ const mouseEventClickType = getMouseEventClickType(event);
2614
+ const currentCellStartColIndex = colgroups.findIndex(
2615
+ (x) => x.key === currentCellEndColKey,
2616
+ );
2617
+ const currentCellEndColIndex = colgroups.findIndex(
2618
+ (x) => x.key === currentCellStartColKey,
2619
+ );
2620
+ // 左键点击 || 不在当前选择列内
2621
+ if (
2622
+ mouseEventClickType === MOUSE_EVENT_CLICK_TYPE.LEFT_MOUSE ||
2623
+ currentCellStartColIndex < startColKeyIndex ||
2624
+ currentCellEndColIndex < startColKeyIndex ||
2625
+ currentCellStartColIndex > endColKeyIndex ||
2626
+ currentCellEndColIndex > endColKeyIndex
2627
+ ) {
2628
+ newStartColKey = currentCellStartColKey;
2629
+ newEndColKey = currentCellEndColKey;
2630
+ }
2631
+ }
2632
+
2633
+ this.headerIndicatorColKeysChange({
2634
+ startColKey: newStartColKey,
2635
+ endColKey: newEndColKey,
2636
+ });
2637
+ },
2638
+
2639
+ // header cell mouseover
2640
+ headerCellMouseover({ event, column }) {
2641
+ const {
2642
+ colgroups,
2643
+ isGroupHeader,
2644
+ isHeaderCellMousedown,
2645
+ headerIndicatorColKeys,
2646
+ } = this;
2647
+
2648
+ if (
2649
+ isHeaderCellMousedown &&
2650
+ !isOperationColumn(column.key, colgroups)
2651
+ ) {
2652
+ let colKeys;
2653
+ if (isGroupHeader) {
2654
+ colKeys = getColKeysByHeaderColumn({
2655
+ headerColumnItem: column,
2656
+ });
2657
+ } else {
2658
+ colKeys = [column.key];
2659
+ }
2660
+
2661
+ const leftColKey = getLeftmostColKey({
2662
+ colgroups,
2663
+ colKeys: colKeys.concat([
2664
+ headerIndicatorColKeys.startColKey,
2665
+ ]),
2666
+ });
2667
+
2668
+ let endColKey;
2669
+ if (leftColKey === headerIndicatorColKeys.startColKey) {
2670
+ endColKey = colKeys[colKeys.length - 1];
2671
+ } else {
2672
+ endColKey = colKeys[0];
2673
+ }
2674
+ this.headerIndicatorColKeysChange({
2675
+ startColKey: this.headerIndicatorColKeys.startColKey,
2676
+ endColKey,
2677
+ });
2678
+ }
2679
+ },
2680
+
2681
+ // header cell mousemove
2682
+ headerCellMousemove({ event, column }) {
2683
+ this.hooks.triggerHook(HOOKS_NAME.HEADER_CELL_MOUSEMOVE, {
2684
+ event,
2685
+ column,
2686
+ });
2687
+ },
2688
+
2689
+ // header cell mouseleave
2690
+ headerCellMouseleave({ event, column }) {
2691
+ // todo
2692
+ },
2693
+
2694
+ // header mouseleave
2695
+ headerMouseleave(event) {
2696
+ this.setIsColumnResizerHover(false);
2697
+ },
2698
+
2699
+ // table container mouseup
2700
+ tableContainerMouseup() {
2701
+ this.isHeaderCellMousedown = false;
2702
+ this.isBodyCellMousedown = false;
2703
+ this.isBodyOperationColumnMousedown = false;
2704
+ this.isAutofillStarting = false;
2705
+ },
2706
+
2707
+ /*
2708
+ * @cellSelectionCornerMousedown
2709
+ * @desc recieve cell selection corner mousedown
2710
+ */
2711
+ cellSelectionCornerMousedown({ event }) {
2712
+ this.isAutofillStarting = true;
2713
+ },
2714
+
2715
+ /*
2716
+ * @cellSelectionCornerMouseup
2717
+ * @desc recieve cell selection corner mouseup
2718
+ */
2719
+ cellSelectionCornerMouseup({ event }) {
2720
+ this.isAutofillStarting = false;
2721
+ },
2722
+
2723
+ // is edit column
2724
+ isEditColumn(colKey) {
2725
+ return this.colgroups.some((x) => x.key === colKey && x.edit);
2726
+ },
2727
+
2728
+ /*
2729
+ * @editCellByClick
2730
+ * @desc recieve td click event
2731
+ * @param {boolean} isDblclick - is dblclick
2732
+ */
2733
+ editCellByClick({ isDblclick, rowKey, colKey }) {
2734
+ const {
2735
+ editOption,
2736
+ isCellEditing,
2737
+ hasEditColumn,
2738
+ editingCell,
2739
+ isEditColumn,
2740
+ } = this;
2741
+
2742
+ if (!editOption) {
2743
+ return false;
2744
+ }
2745
+
2746
+ // has edit column
2747
+ if (!hasEditColumn) {
2748
+ return false;
2749
+ }
2750
+
2751
+ if (isEmptyValue(rowKey) || isEmptyValue(colKey)) {
2752
+ return false;
2753
+ }
2754
+ if (
2755
+ editingCell &&
2756
+ editingCell.rowKey == rowKey &&
2757
+ editingCell.colKey == colKey
2758
+ ) {
2759
+ return false;
2760
+ }
2761
+ if (isCellEditing) {
2762
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
2763
+ }
2764
+
2765
+ if (isDblclick && isEditColumn(colKey)) {
2766
+ this.enableStopEditing = false;
2767
+
2768
+ this[INSTANCE_METHODS.START_EDITING_CELL]({
2769
+ rowKey,
2770
+ colKey,
2771
+ });
2772
+ } else {
2773
+ this.enableStopEditing = true;
2774
+ }
2775
+ },
2776
+
2777
+ /*
2778
+ * @setEditingCell
2779
+ * @desc add editing cells
2780
+ * @param {object} rowKey - row key
2781
+ * @param {object} colKey - col key
2782
+ * @param {object} column - column
2783
+ * @param {object} row - row data
2784
+ */
2785
+ setEditingCell({ rowKey, colKey, column, row }) {
2786
+ this.editingCell = {
2787
+ rowKey,
2788
+ row: cloneDeep(row),
2789
+ colKey,
2790
+ column,
2791
+ };
2792
+ },
2793
+
2794
+ // update editing cell value
2795
+ updateEditingCellValue(value) {
2796
+ const { editingCell } = this;
2797
+ let { row, column } = editingCell;
2798
+ row[column.field] = value;
2799
+ this.editingCell.row = row;
2800
+ },
2801
+
2802
+ /*
2803
+ * @clearEditingCell
2804
+ * @desc clear editing cell
2805
+ */
2806
+ clearEditingCell() {
2807
+ this.editingCell = {
2808
+ rowKey: "",
2809
+ colKey: "",
2810
+ row: null,
2811
+ column: null,
2812
+ };
2813
+ },
2814
+
2815
+ // contextmenu item click
2816
+ contextmenuItemClick(type) {
2817
+ // header contextmenu
2818
+ if (this.contextMenuType === CONTEXTMENU_TYPES.HEADER_CONTEXTMENU) {
2819
+ this.headerContextmenuItemClick(type);
2820
+ }
2821
+ // body contextmenu
2822
+ else {
2823
+ this.bodyContextmenuItemClick(type);
2824
+ }
2825
+ },
2826
+
2827
+ // header contextmenu item click
2828
+ headerContextmenuItemClick(type) {
2829
+ const {
2830
+ contextmenuHeaderOption,
2831
+ cellSelectionData,
2832
+ cellSelectionRangeData,
2833
+ allRowKeys,
2834
+ colgroups,
2835
+ enableColumnResize,
2836
+ } = this;
2837
+
2838
+ const { rowKey, colKey } = cellSelectionData.currentCell;
2839
+ const { afterMenuClick } = contextmenuHeaderOption;
2840
+
2841
+ if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) {
2842
+ let selectionRangeKeys = getSelectionRangeKeys({
2843
+ cellSelectionRangeData,
2844
+ });
2845
+
2846
+ let selectionRangeIndexes = getSelectionRangeIndexes({
2847
+ cellSelectionRangeData,
2848
+ colgroups,
2849
+ allRowKeys,
2850
+ });
2851
+
2852
+ if (isFunction(afterMenuClick)) {
2853
+ const callback = afterMenuClick({
2854
+ type,
2855
+ selectionRangeKeys,
2856
+ selectionRangeIndexes,
2857
+ });
2858
+ if (isBoolean(callback) && !callback) {
2859
+ return false;
2860
+ }
2861
+ }
2862
+ const editInputEditor = this.$refs[this.editInputRef];
2863
+
2864
+ // cut
2865
+ if (CONTEXTMENU_NODE_TYPES.CUT === type) {
2866
+ editInputEditor.textareaSelect();
2867
+ document.execCommand("cut");
2868
+ }
2869
+ // copy
2870
+ else if (CONTEXTMENU_NODE_TYPES.COPY === type) {
2871
+ editInputEditor.textareaSelect();
2872
+ document.execCommand("copy");
2873
+ }
2874
+ // empty column
2875
+ else if (CONTEXTMENU_NODE_TYPES.EMPTY_COLUMN === type) {
2876
+ this.deleteCellSelectionRangeValue();
2877
+ }
2878
+ // left fixed column to
2879
+ else if (CONTEXTMENU_NODE_TYPES.LEFT_FIXED_COLUMN_TO === type) {
2880
+ this.cloneColumns = setColumnFixed({
2881
+ cloneColumns: this.cloneColumns,
2882
+ cellSelectionRangeData,
2883
+ fixedType: COLUMN_FIXED_TYPE.LEFT,
2884
+ colgroups,
2885
+ enableColumnResize,
2886
+ });
2887
+ }
2888
+ // cancel left fixed column to
2889
+ else if (
2890
+ CONTEXTMENU_NODE_TYPES.CANCEL_LEFT_FIXED_COLUMN_TO === type
2891
+ ) {
2892
+ this.cloneColumns = cancelColumnFixed({
2893
+ cloneColumns: this.cloneColumns,
2894
+ colgroups,
2895
+ fixedType: COLUMN_FIXED_TYPE.LEFT,
2896
+ enableColumnResize,
2897
+ });
2898
+ }
2899
+ // right fixed column to
2900
+ else if (
2901
+ CONTEXTMENU_NODE_TYPES.RIGHT_FIXED_COLUMN_TO === type
2902
+ ) {
2903
+ this.cloneColumns = setColumnFixed({
2904
+ cloneColumns: this.cloneColumns,
2905
+ cellSelectionRangeData,
2906
+ fixedType: COLUMN_FIXED_TYPE.RIGHT,
2907
+ colgroups,
2908
+ enableColumnResize,
2909
+ });
2910
+ }
2911
+ // cancel right fixed column to
2912
+ else if (
2913
+ CONTEXTMENU_NODE_TYPES.CANCEL_RIGHT_FIXED_COLUMN_TO === type
2914
+ ) {
2915
+ this.cloneColumns = cancelColumnFixed({
2916
+ cloneColumns: this.cloneColumns,
2917
+ colgroups,
2918
+ fixedType: COLUMN_FIXED_TYPE.RIGHT,
2919
+ enableColumnResize,
2920
+ });
2921
+ }
2922
+ }
2923
+ },
2924
+
2925
+ // body contextmenu item click
2926
+ bodyContextmenuItemClick(type) {
2927
+ const {
2928
+ contextmenuBodyOption,
2929
+ cellSelectionData,
2930
+ cellSelectionRangeData,
2931
+ tableData,
2932
+ allRowKeys,
2933
+ colgroups,
2934
+ rowKeyFieldName,
2935
+ } = this;
2936
+
2937
+ const { rowKey, colKey } = cellSelectionData.currentCell;
2938
+ const { afterMenuClick } = contextmenuBodyOption;
2939
+
2940
+ if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) {
2941
+ let selectionRangeKeys = getSelectionRangeKeys({
2942
+ cellSelectionRangeData,
2943
+ });
2944
+
2945
+ let selectionRangeIndexes = getSelectionRangeIndexes({
2946
+ cellSelectionRangeData,
2947
+ colgroups,
2948
+ allRowKeys,
2949
+ });
2950
+
2951
+ if (isFunction(afterMenuClick)) {
2952
+ const callback = afterMenuClick({
2953
+ type,
2954
+ selectionRangeKeys,
2955
+ selectionRangeIndexes,
2956
+ });
2957
+ if (isBoolean(callback) && !callback) {
2958
+ return false;
2959
+ }
2960
+ }
2961
+
2962
+ const { startRowIndex, endRowIndex } = selectionRangeIndexes;
2963
+
2964
+ const currentRowIndex = allRowKeys.findIndex(
2965
+ (x) => x === rowKey,
2966
+ );
2967
+
2968
+ const editInputEditor = this.$refs[this.editInputRef];
2969
+
2970
+ // cut
2971
+ if (CONTEXTMENU_NODE_TYPES.CUT === type) {
2972
+ editInputEditor.textareaSelect();
2973
+ document.execCommand("cut");
2974
+ }
2975
+ // copy
2976
+ else if (CONTEXTMENU_NODE_TYPES.COPY === type) {
2977
+ editInputEditor.textareaSelect();
2978
+ document.execCommand("copy");
2979
+ }
2980
+ // paste todo
2981
+ // else if (CONTEXTMENU_NODE_TYPES.PASTE === type) {
2982
+ // editInputEditor.textareaSelect();
2983
+ // document.execCommand("paste", null, null);
2984
+ // }
2985
+ // remove rows
2986
+ else if (CONTEXTMENU_NODE_TYPES.REMOVE_ROW === type) {
2987
+ tableData.splice(
2988
+ startRowIndex,
2989
+ endRowIndex - startRowIndex + 1,
2990
+ );
2991
+ }
2992
+ // empty rows
2993
+ else if (CONTEXTMENU_NODE_TYPES.EMPTY_ROW === type) {
2994
+ this.deleteCellSelectionRangeValue();
2995
+ }
2996
+ // empty rows
2997
+ else if (CONTEXTMENU_NODE_TYPES.EMPTY_CELL === type) {
2998
+ this.deleteCellSelectionRangeValue();
2999
+ }
3000
+ // insert row above
3001
+ else if (CONTEXTMENU_NODE_TYPES.INSERT_ROW_ABOVE === type) {
3002
+ tableData.splice(
3003
+ currentRowIndex,
3004
+ 0,
3005
+ createEmptyRowData({ colgroups, rowKeyFieldName }),
3006
+ );
3007
+ }
3008
+ // insert row below
3009
+ else if (CONTEXTMENU_NODE_TYPES.INSERT_ROW_BELOW === type) {
3010
+ tableData.splice(
3011
+ currentRowIndex + 1,
3012
+ 0,
3013
+ createEmptyRowData({ colgroups, rowKeyFieldName }),
3014
+ );
3015
+ }
3016
+ }
3017
+ },
3018
+
3019
+ // editor copy
3020
+ editorCopy(event) {
3021
+ const {
3022
+ isCellEditing,
3023
+ enableClipboard,
3024
+ clipboardOption,
3025
+ cellSelectionRangeData,
3026
+ tableData,
3027
+ colgroups,
3028
+ allRowKeys,
3029
+ } = this;
3030
+
3031
+ if (!enableClipboard) {
3032
+ return false;
3033
+ }
3034
+
3035
+ // 正在编辑的单元格不进行自定义复制功能
3036
+ if (isCellEditing) {
3037
+ return false;
3038
+ }
3039
+
3040
+ const {
3041
+ copy,
3042
+ beforeCopy: beforeCopyCallback,
3043
+ afterCopy: afterCopyCallback,
3044
+ } = clipboardOption || {};
3045
+
3046
+ if (isBoolean(copy) && !copy) {
3047
+ return false;
3048
+ }
3049
+
3050
+ event.preventDefault();
3051
+
3052
+ const selectionRangeData = getSelectionRangeData({
3053
+ cellSelectionRangeData,
3054
+ resultType: "flat",
3055
+ tableData,
3056
+ colgroups,
3057
+ allRowKeys,
3058
+ });
3059
+
3060
+ const response = onBeforeCopy({
3061
+ cellSelectionRangeData,
3062
+ selectionRangeData,
3063
+ colgroups,
3064
+ allRowKeys,
3065
+ });
3066
+
3067
+ if (isFunction(beforeCopyCallback)) {
3068
+ const allowCoping = beforeCopyCallback(response);
3069
+ if (isBoolean(allowCoping) && !allowCoping) {
3070
+ return false;
3071
+ }
3072
+ }
3073
+
3074
+ onAfterCopy({ event, selectionRangeData });
3075
+
3076
+ if (isFunction(afterCopyCallback)) {
3077
+ afterCopyCallback(response);
3078
+ }
3079
+ },
3080
+
3081
+ // editor paste
3082
+ editorPaste(event) {
3083
+ const { isCellEditing, enableClipboard, clipboardOption } = this;
3084
+
3085
+ if (!enableClipboard) {
3086
+ return false;
3087
+ }
3088
+
3089
+ // 正在编辑的单元格不进行自定义粘贴功能
3090
+ if (isCellEditing) {
3091
+ return false;
3092
+ }
3093
+
3094
+ const {
3095
+ paste,
3096
+ beforePaste: beforePasteCallback,
3097
+ afterPaste: afterPasteCallback,
3098
+ } = clipboardOption || {};
3099
+
3100
+ if (isBoolean(paste) && !paste) {
3101
+ return false;
3102
+ }
3103
+
3104
+ event.preventDefault();
3105
+
3106
+ const response = onBeforePaste({
3107
+ event,
3108
+ cellSelectionRangeData: this.cellSelectionRangeData,
3109
+ colgroups: this.colgroups,
3110
+ allRowKeys: this.allRowKeys,
3111
+ rowKeyFieldName: this.rowKeyFieldName,
3112
+ });
3113
+
3114
+ if (
3115
+ response &&
3116
+ Array.isArray(response.data) &&
3117
+ response.data.length
3118
+ ) {
3119
+ if (isFunction(beforePasteCallback)) {
3120
+ const allowPasting = beforePasteCallback(response);
3121
+ if (isBoolean(allowPasting) && !allowPasting) {
3122
+ return false;
3123
+ }
3124
+ }
3125
+ // change table cell data
3126
+ onAfterPaste({
3127
+ tableData: this.tableData,
3128
+ beforePasteResponse: response,
3129
+ });
3130
+
3131
+ if (isFunction(afterPasteCallback)) {
3132
+ afterPasteCallback(response);
3133
+ }
3134
+
3135
+ const { startColKey, endColKey, startRowKey, endRowKey } =
3136
+ response.selectionRangeKeys;
3137
+
3138
+ this.cellSelectionCurrentCellChange({
3139
+ rowKey: startRowKey,
3140
+ colKey: startColKey,
3141
+ });
3142
+
3143
+ this.cellSelectionNormalEndCellChange({
3144
+ rowKey: endRowKey,
3145
+ colKey: endColKey,
3146
+ });
3147
+
3148
+ // clipboard cell value change
3149
+ this.hooks.triggerHook(HOOKS_NAME.CLIPBOARD_CELL_VALUE_CHANGE);
3150
+ }
3151
+ },
3152
+
3153
+ // editor cut
3154
+ editorCut(event) {
3155
+ const {
3156
+ isCellEditing,
3157
+ enableClipboard,
3158
+ clipboardOption,
3159
+ cellSelectionRangeData,
3160
+ tableData,
3161
+ colgroups,
3162
+ allRowKeys,
3163
+ } = this;
3164
+
3165
+ if (!enableClipboard) {
3166
+ return false;
3167
+ }
3168
+
3169
+ // 正在编辑的单元格不进行自定义剪切功能
3170
+ if (isCellEditing) {
3171
+ return false;
3172
+ }
3173
+
3174
+ const {
3175
+ cut,
3176
+ beforeCut: beforeCutCallback,
3177
+ afterCut: afterCutCallback,
3178
+ } = clipboardOption || {};
3179
+
3180
+ if (isBoolean(cut) && !cut) {
3181
+ return false;
3182
+ }
3183
+
3184
+ event.preventDefault();
3185
+
3186
+ const selectionRangeData = getSelectionRangeData({
3187
+ cellSelectionRangeData,
3188
+ resultType: "flat",
3189
+ tableData,
3190
+ colgroups,
3191
+ allRowKeys,
3192
+ });
3193
+
3194
+ const response = onBeforeCut({
3195
+ cellSelectionRangeData,
3196
+ selectionRangeData,
3197
+ colgroups,
3198
+ allRowKeys,
3199
+ });
3200
+
3201
+ if (isFunction(beforeCutCallback)) {
3202
+ const allowCuting = beforeCutCallback(response);
3203
+ if (isBoolean(allowCuting) && !allowCuting) {
3204
+ return false;
3205
+ }
3206
+ }
3207
+
3208
+ onAfterCut({
3209
+ event,
3210
+ tableData,
3211
+ colgroups,
3212
+ selectionRangeData,
3213
+ selectionRangeIndexes: response.selectionRangeIndexes,
3214
+ });
3215
+
3216
+ if (isFunction(afterCutCallback)) {
3217
+ afterCutCallback(response);
3218
+ }
3219
+ },
3220
+
3221
+ // delete selection cell value
3222
+ deleteCellSelectionRangeValue() {
3223
+ const {
3224
+ isCellEditing,
3225
+ enableClipboard,
3226
+ clipboardOption,
3227
+ cellSelectionRangeData,
3228
+ tableData,
3229
+ colgroups,
3230
+ allRowKeys,
3231
+ } = this;
3232
+
3233
+ if (!enableClipboard) {
3234
+ return false;
3235
+ }
3236
+
3237
+ // 正在编辑的单元格不进行删除区域单元格功能
3238
+ if (isCellEditing) {
3239
+ return false;
3240
+ }
3241
+
3242
+ const {
3243
+ // delete is key word
3244
+ delete: delete2,
3245
+ beforeDelete: beforeDeleteCallback,
3246
+ afterDelete: afterDeleteCallback,
3247
+ } = clipboardOption || {};
3248
+
3249
+ if (isBoolean(delete2) && !delete2) {
3250
+ return false;
3251
+ }
3252
+
3253
+ const selectionRangeData = getSelectionRangeData({
3254
+ cellSelectionRangeData,
3255
+ resultType: "flat",
3256
+ tableData,
3257
+ colgroups,
3258
+ allRowKeys,
3259
+ });
3260
+
3261
+ const response = onBeforeDelete({
3262
+ cellSelectionRangeData,
3263
+ selectionRangeData,
3264
+ colgroups,
3265
+ allRowKeys,
3266
+ });
3267
+
3268
+ if (isFunction(beforeDeleteCallback)) {
3269
+ const allowDeleting = beforeDeleteCallback(response);
3270
+ if (isBoolean(allowDeleting) && !allowDeleting) {
3271
+ return false;
3272
+ }
3273
+ }
3274
+
3275
+ onAfterDelete({
3276
+ tableData,
3277
+ colgroups,
3278
+ selectionRangeIndexes: response.selectionRangeIndexes,
3279
+ });
3280
+
3281
+ if (isFunction(afterDeleteCallback)) {
3282
+ afterDeleteCallback(response);
3283
+ }
3284
+ },
3285
+
3286
+ // set range cell selection by header indicator
3287
+ setRangeCellSelectionByHeaderIndicator() {
3288
+ const { headerIndicatorColKeys, allRowKeys } = this;
3289
+ const { startColKey, endColKey } = headerIndicatorColKeys;
3290
+
3291
+ if (isEmptyValue(startColKey) || isEmptyValue(endColKey)) {
3292
+ return false;
3293
+ }
3294
+
3295
+ this.cellSelectionCurrentCellChange({
3296
+ rowKey: allRowKeys[0],
3297
+ colKey: startColKey,
3298
+ });
3299
+
3300
+ this.cellSelectionNormalEndCellChange({
3301
+ rowKey: allRowKeys[allRowKeys.length - 1],
3302
+ colKey: endColKey,
3303
+ });
3304
+ },
3305
+
3306
+ // set range cell selection by body indicator
3307
+ setRangeCellSelectionByBodyIndicator() {
3308
+ const { bodyIndicatorRowKeys, colgroups } = this;
3309
+ const { startRowKey, endRowKey } = bodyIndicatorRowKeys;
3310
+
3311
+ if (isEmptyValue(startRowKey) || isEmptyValue(endRowKey)) {
3312
+ return false;
3313
+ }
3314
+
3315
+ if (colgroups.length > 1) {
3316
+ this.cellSelectionCurrentCellChange({
3317
+ rowKey: startRowKey,
3318
+ colKey: colgroups[1].key,
3319
+ });
3320
+
3321
+ this.cellSelectionNormalEndCellChange({
3322
+ rowKey: endRowKey,
3323
+ colKey: colgroups[colgroups.length - 1].key,
3324
+ });
3325
+ }
3326
+ },
3327
+
3328
+ // set isColumnResizerHover
3329
+ setIsColumnResizerHover(val) {
3330
+ this.isColumnResizerHover = val;
3331
+ },
3332
+
3333
+ // set isColumnResizing
3334
+ setIsColumnResizing(val) {
3335
+ this.isColumnResizing = val;
3336
+ },
3337
+
3338
+ /*
3339
+ set cell selection and column to visible
3340
+ */
3341
+ [INSTANCE_METHODS.SET_CELL_SELECTION]({
3342
+ rowKey,
3343
+ colKey,
3344
+ isScrollToRow = true,
3345
+ }) {
3346
+ const { enableCellSelection } = this;
3347
+
3348
+ if (!enableCellSelection) {
3349
+ return false;
3350
+ }
3351
+
3352
+ if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) {
3353
+ this.cellSelectionCurrentCellChange({
3354
+ rowKey,
3355
+ colKey,
3356
+ });
3357
+
3358
+ const column = getColumnByColkey(colKey, this.colgroups);
3359
+ // column to visible
3360
+ this.columnToVisible(column);
3361
+ // row to visible
3362
+ if (isScrollToRow) {
3363
+ this[INSTANCE_METHODS.SCROLL_TO_ROW_KEY]({ rowKey });
3364
+ }
3365
+ }
3366
+ },
3367
+
3368
+ /*
3369
+ set range cell selection and column to visible
3370
+ */
3371
+ [INSTANCE_METHODS.SET_RANGE_CELL_SELECTION]({
3372
+ startRowKey,
3373
+ startColKey,
3374
+ endRowKey,
3375
+ endColKey,
3376
+ isScrollToStartCell = false,
3377
+ }) {
3378
+ const { enableCellSelection } = this;
3379
+
3380
+ if (!enableCellSelection) {
3381
+ return false;
3382
+ }
3383
+
3384
+ if (
3385
+ isEmptyValue(startRowKey) ||
3386
+ isEmptyValue(startColKey) ||
3387
+ isEmptyValue(endRowKey) ||
3388
+ isEmptyValue(endColKey)
3389
+ ) {
3390
+ return false;
3391
+ }
3392
+
3393
+ this.cellSelectionCurrentCellChange({
3394
+ rowKey: startRowKey,
3395
+ colKey: startColKey,
3396
+ });
3397
+
3398
+ this.cellSelectionNormalEndCellChange({
3399
+ rowKey: endRowKey,
3400
+ colKey: endColKey,
3401
+ });
3402
+
3403
+ // row to visible
3404
+ if (isScrollToStartCell) {
3405
+ const column = getColumnByColkey(startColKey, this.colgroups);
3406
+ // column to visible
3407
+ this.columnToVisible(column);
3408
+ this[INSTANCE_METHODS.SCROLL_TO_ROW_KEY]({
3409
+ rowKey: startRowKey,
3410
+ });
3411
+ }
3412
+ },
3413
+
3414
+ /*
3415
+ get range cell selection
3416
+ */
3417
+ [INSTANCE_METHODS.GET_RANGE_CELL_SELECTION]() {
3418
+ const {
3419
+ cellSelectionData,
3420
+ cellSelectionRangeData,
3421
+ allRowKeys,
3422
+ colgroups,
3423
+ } = this;
3424
+
3425
+ const { rowKey, colKey } = cellSelectionData.currentCell;
3426
+
3427
+ if (!isEmptyValue(rowKey) && !isEmptyValue(colKey)) {
3428
+ let selectionRangeKeys = getSelectionRangeKeys({
3429
+ cellSelectionRangeData,
3430
+ });
3431
+
3432
+ let selectionRangeIndexes = getSelectionRangeIndexes({
3433
+ cellSelectionRangeData,
3434
+ colgroups,
3435
+ allRowKeys,
3436
+ });
3437
+
3438
+ return {
3439
+ selectionRangeKeys,
3440
+ selectionRangeIndexes,
3441
+ };
3442
+ }
3443
+ },
3444
+
3445
+ /*
3446
+ set all cell selection and column to visible
3447
+ */
3448
+ [INSTANCE_METHODS.SET_ALL_CELL_SELECTION]() {
3449
+ const { enableCellSelection } = this;
3450
+
3451
+ if (!enableCellSelection) {
3452
+ return false;
3453
+ }
3454
+
3455
+ const { colgroups, allRowKeys } = this;
3456
+
3457
+ if (colgroups.length) {
3458
+ const colKeys = colgroups
3459
+ .filter((x) => !x.operationColumn)
3460
+ .map((x) => x.key);
3461
+
3462
+ if (colKeys.length) {
3463
+ this.headerIndicatorColKeysChange({
3464
+ startColKey: colKeys[0],
3465
+ endColKey: colKeys[colKeys.length - 1],
3466
+ });
3467
+ }
3468
+ }
3469
+
3470
+ if (allRowKeys.length) {
3471
+ this.bodyIndicatorRowKeysChange({
3472
+ startRowKey: allRowKeys[0],
3473
+ endRowKey: allRowKeys[allRowKeys.length - 1],
3474
+ });
3475
+ }
3476
+ },
3477
+
3478
+ // hide columns by keys
3479
+ [INSTANCE_METHODS.HIDE_COLUMNS_BY_KEYS](keys) {
3480
+ if (!isEmptyArray(keys)) {
3481
+ /*
3482
+ 将要隐藏的列添加到 hiddenColumns 中
3483
+ Add the columns you want to hide to hidden columns
3484
+ */
3485
+ this.hiddenColumns = Array.from(
3486
+ new Set(this.hiddenColumns.concat(keys)),
3487
+ );
3488
+
3489
+ this.showOrHideColumns();
3490
+ }
3491
+ },
3492
+
3493
+ // show columns by keys
3494
+ [INSTANCE_METHODS.SHOW_COLUMNS_BY_KEYS](keys) {
3495
+ if (!isEmptyArray(keys)) {
3496
+ /*
3497
+ 将要显示的列从 hiddenColumns 中移除
3498
+ Remove the columns to show from hidden columns
3499
+ */
3500
+ for (let i = keys.length - 1; i >= 0; i--) {
3501
+ const delIndex = this.hiddenColumns.indexOf(keys[i]);
3502
+ if (delIndex > -1) {
3503
+ this.hiddenColumns.splice(delIndex, 1);
3504
+ }
3505
+ }
3506
+
3507
+ this.showOrHideColumns();
3508
+ }
3509
+ },
3510
+
3511
+ // table scrollTo
3512
+ [INSTANCE_METHODS.SCROLL_TO](option) {
3513
+ scrollTo(this.$refs[this.tableContainerRef], option);
3514
+ },
3515
+ // table scroll to rowKey position
3516
+ [INSTANCE_METHODS.SCROLL_TO_ROW_KEY]({ rowKey }) {
3517
+ if (isEmptyValue(rowKey)) {
3518
+ console.warn("Row key can't be empty!");
3519
+ return false;
3520
+ }
3521
+
3522
+ let scrollTop = 0;
3523
+
3524
+ const { isVirtualScroll, headerTotalHeight } = this;
3525
+
3526
+ const tableContainerRef = this.$refs[this.tableContainerRef];
3527
+
3528
+ if (isVirtualScroll) {
3529
+ const position = this.virtualScrollPositions.find(
3530
+ (x) => x.rowKey === rowKey,
3531
+ );
3532
+
3533
+ if (position) {
3534
+ scrollTop = position.top;
3535
+ }
3536
+
3537
+ // fix bug #470
3538
+ setTimeout(() => {
3539
+ scrollTo(tableContainerRef, {
3540
+ top: scrollTop,
3541
+ behavior: "auto",
3542
+ });
3543
+ }, 200);
3544
+ } else {
3545
+ const rowEl = this.$el.querySelector(
3546
+ `tbody tr[${COMPS_CUSTOM_ATTRS.BODY_ROW_KEY}="${rowKey}"]`,
3547
+ );
3548
+
3549
+ scrollTop = rowEl.offsetTop - headerTotalHeight;
3550
+ }
3551
+
3552
+ scrollTo(tableContainerRef, {
3553
+ top: scrollTop,
3554
+ behavior: isVirtualScroll ? "auto" : "smooth",
3555
+ });
3556
+ },
3557
+ // scroll to col key position
3558
+ [INSTANCE_METHODS.SCROLL_TO_COL_KEY]({ colKey }) {
3559
+ const column = getColumnByColkey(colKey, this.colgroups);
3560
+ if (column) {
3561
+ this.columnToVisible(column);
3562
+ }
3563
+ },
3564
+ // start editing cell
3565
+ [INSTANCE_METHODS.START_EDITING_CELL]({
3566
+ rowKey,
3567
+ colKey,
3568
+ defaultValue,
3569
+ }) {
3570
+ const {
3571
+ editOption,
3572
+ colgroups,
3573
+ rowKeyFieldName,
3574
+ editingCell,
3575
+ cellSelectionData,
3576
+ } = this;
3577
+
3578
+ if (!editOption) {
3579
+ return false;
3580
+ }
3581
+
3582
+ let currentRow = this.tableData.find(
3583
+ (x) => x[rowKeyFieldName] === rowKey,
3584
+ );
3585
+
3586
+ currentRow = cloneDeep(currentRow);
3587
+
3588
+ /*
3589
+ 调用API编辑的情况,需要关闭之前编辑的单元格
3590
+ */
3591
+ if (
3592
+ editingCell.rowKey === rowKey &&
3593
+ editingCell.colKey === colKey
3594
+ ) {
3595
+ return false;
3596
+ }
3597
+
3598
+ const currentColumn = colgroups.find((x) => x.key === colKey);
3599
+ // 当前列是否可编辑
3600
+ if (!currentColumn.edit) {
3601
+ return false;
3602
+ }
3603
+
3604
+ const { beforeStartCellEditing } = editOption;
3605
+
3606
+ if (isFunction(beforeStartCellEditing)) {
3607
+ const allowContinue = beforeStartCellEditing({
3608
+ row: cloneDeep(currentRow),
3609
+ column: currentColumn,
3610
+ cellValue: isDefined(defaultValue)
3611
+ ? defaultValue
3612
+ : currentRow[currentColumn.field],
3613
+ });
3614
+ if (isBoolean(allowContinue) && !allowContinue) {
3615
+ return false;
3616
+ }
3617
+ }
3618
+
3619
+ // 给当前列赋默认值
3620
+ if (isDefined(defaultValue)) {
3621
+ this.editorInputStartValue = defaultValue;
3622
+ // doesn't change cell original value
3623
+ currentRow[currentColumn.field] = defaultValue;
3624
+ } else {
3625
+ this.editorInputStartValue = currentRow[currentColumn.field];
3626
+ }
3627
+
3628
+ if (
3629
+ cellSelectionData.currentCell.colKey !== colKey ||
3630
+ cellSelectionData.currentCell.rowKey !== rowKey
3631
+ ) {
3632
+ this.cellSelectionCurrentCellChange({
3633
+ rowKey,
3634
+ colKey,
3635
+ });
3636
+ }
3637
+
3638
+ // set editing cell
3639
+ this.setEditingCell({
3640
+ rowKey,
3641
+ colKey,
3642
+ column: currentColumn,
3643
+ row: cloneDeep(currentRow),
3644
+ });
3645
+ },
3646
+ // stop editing cell
3647
+ [INSTANCE_METHODS.STOP_EDITING_CELL]() {
3648
+ const { editOption, isCellEditing } = this;
3649
+
3650
+ if (!editOption) {
3651
+ return false;
3652
+ }
3653
+
3654
+ // clear editor input start value
3655
+ this.editorInputStartValue = "";
3656
+
3657
+ if (isCellEditing) {
3658
+ this.saveCellWhenStopEditing();
3659
+ }
3660
+ },
3661
+ // set highlight row
3662
+ [INSTANCE_METHODS.SET_HIGHLIGHT_ROW]({ rowKey }) {
3663
+ this.highlightRowKey = rowKey;
3664
+ },
3665
+ },
3666
+ created() {
3667
+ // bug fixed #467
3668
+ this.debouncedBodyCellWidthChange = debounce(
3669
+ this.bodyCellWidthChange,
3670
+ 0,
3671
+ );
3672
+ },
3673
+ mounted() {
3674
+ this.parentRendered = true;
3675
+
3676
+ // set contextmenu event target
3677
+ this.contextmenuEventTarget = this.$el.querySelector(
3678
+ `.${clsName("content")}`,
3679
+ );
3680
+
3681
+ // create hook instance
3682
+ this.hooks = new Hooks();
3683
+
3684
+ // receive sort change
3685
+ this.$on(EMIT_EVENTS.SORT_CHANGE, (params) => {
3686
+ this.updateColgroupsBySortChange(params);
3687
+ });
3688
+
3689
+ // receive row selected change
3690
+ this.$on(EMIT_EVENTS.CHECKBOX_SELECTED_ALL_CHANGE, (params) => {
3691
+ this.selectedAllChange(params);
3692
+ });
3693
+
3694
+ // receive selected all info
3695
+ this.$on(EMIT_EVENTS.CHECKBOX_SELECTED_ALL_INFO, (params) => {
3696
+ this.setSelectedAllInfo(params);
3697
+ });
3698
+
3699
+ // receive multiple header row height change
3700
+ this.$on(
3701
+ EMIT_EVENTS.HEADER_ROW_HEIGHT_CHANGE,
3702
+ ({ rowIndex, height }) => {
3703
+ this.headerRowHeightChange({ rowIndex, height });
3704
+ },
3705
+ );
3706
+
3707
+ // receive virtual scroll row height change
3708
+ this.$on(EMIT_EVENTS.BODY_ROW_HEIGHT_CHANGE, ({ rowKey, height }) => {
3709
+ this.bodyRowHeightChange({ rowKey, height });
3710
+ });
3711
+
3712
+ // receive footer row height change
3713
+ this.$on(
3714
+ EMIT_EVENTS.FOOTER_ROW_HEIGHT_CHANGE,
3715
+ ({ rowIndex, height }) => {
3716
+ this.footRowHeightChange({ rowIndex, height });
3717
+ },
3718
+ );
3719
+
3720
+ // recieve body cell click
3721
+ this.$on(EMIT_EVENTS.BODY_CELL_CLICK, (params) => {
3722
+ this.bodyCellClick(params);
3723
+ });
3724
+
3725
+ // recieve body cell mouseover
3726
+ this.$on(EMIT_EVENTS.BODY_CELL_MOUSEOVER, (params) => {
3727
+ this.bodyCellMouseover(params);
3728
+ });
3729
+
3730
+ // recieve body cell mousedown
3731
+ this.$on(EMIT_EVENTS.BODY_CELL_MOUSEDOWN, (params) => {
3732
+ this.bodyCellMousedown(params);
3733
+ });
3734
+
3735
+ // recieve body cell mousemove
3736
+ this.$on(EMIT_EVENTS.BODY_CELL_MOUSEMOVE, (params) => {
3737
+ this.bodyCellMousemove(params);
3738
+ });
3739
+
3740
+ // recieve body cell mouseup
3741
+ this.$on(EMIT_EVENTS.BODY_CELL_MOUSEUP, (params) => {
3742
+ this.bodyCellMouseup(params);
3743
+ });
3744
+
3745
+ // recieve selection corner mousedown
3746
+ this.$on(EMIT_EVENTS.SELECTION_CORNER_MOUSEDOWN, (params) => {
3747
+ this.cellSelectionCornerMousedown(params);
3748
+ });
3749
+
3750
+ // recieve selection corner mouseup
3751
+ this.$on(EMIT_EVENTS.SELECTION_CORNER_MOUSEUP, (params) => {
3752
+ this.cellSelectionCornerMouseup(params);
3753
+ });
3754
+
3755
+ // autofilling direction change
3756
+ this.$on(EMIT_EVENTS.AUTOFILLING_DIRECTION_CHANGE, (params) => {
3757
+ this.autofillingDirectionChange(params);
3758
+ });
3759
+
3760
+ // recieve body cell contextmenu(right click)
3761
+ this.$on(EMIT_EVENTS.BODY_CELL_CONTEXTMENU, (params) => {
3762
+ this.bodyCellContextmenu(params);
3763
+ });
3764
+
3765
+ // recieve body cell double click
3766
+ this.$on(EMIT_EVENTS.BODY_CELL_DOUBLE_CLICK, (params) => {
3767
+ this.bodyCellDoubleClick(params);
3768
+ });
3769
+
3770
+ // recieve header cell contextmenu(right click)
3771
+ this.$on(EMIT_EVENTS.HEADER_CELL_CLICK, (params) => {
3772
+ this.headerCellClick(params);
3773
+ });
3774
+
3775
+ // recieve header cell contextmenu(right click)
3776
+ this.$on(EMIT_EVENTS.HEADER_CELL_CONTEXTMENU, (params) => {
3777
+ this.headerCellContextmenu(params);
3778
+ });
3779
+
3780
+ // recieve header cell mousedown
3781
+ this.$on(EMIT_EVENTS.HEADER_CELL_MOUSEDOWN, (params) => {
3782
+ this.headerCellMousedown(params);
3783
+ });
3784
+
3785
+ // recieve header cell mouseover
3786
+ this.$on(EMIT_EVENTS.HEADER_CELL_MOUSEOVER, (params) => {
3787
+ this.headerCellMouseover(params);
3788
+ });
3789
+
3790
+ // recieve header cell mousemove
3791
+ this.$on(EMIT_EVENTS.HEADER_CELL_MOUSEMOVE, (params) => {
3792
+ this.headerCellMousemove(params);
3793
+ });
3794
+
3795
+ // recieve header cell mouseleave
3796
+ this.$on(EMIT_EVENTS.HEADER_CELL_MOUSELEAVE, (params) => {
3797
+ this.headerCellMouseleave(params);
3798
+ });
3799
+
3800
+ // add key down event listener
3801
+ document.addEventListener("keydown", this.dealKeydownEvent);
3802
+
3803
+ // init scrolling
3804
+ this.initScrolling();
3805
+ },
3806
+ destroyed() {
3807
+ // remove key down event listener
3808
+ document.removeEventListener("keydown", this.dealKeydownEvent);
3809
+ },
3810
+ render() {
3811
+ const {
3812
+ showHeader,
3813
+ tableViewportWidth,
3814
+ tableContainerStyle,
3815
+ tableStyle,
3816
+ tableClass,
3817
+ colgroups,
3818
+ groupColumns,
3819
+ fixedHeader,
3820
+ fixedFooter,
3821
+ actualRenderTableData,
3822
+ debouncedBodyCellWidthChange,
3823
+ expandOption,
3824
+ checkboxOption,
3825
+ radioOption,
3826
+ rowKeyFieldName,
3827
+ virtualScrollOption,
3828
+ isVirtualScroll,
3829
+ sortOption,
3830
+ cellStyleOption,
3831
+ showVirtualScrollingPlaceholder,
3832
+ cellSelectionData,
3833
+ editOption,
3834
+ contextmenuOptions,
3835
+ allRowKeys,
3836
+ enableCellSelection,
3837
+ enableColumnResize,
3838
+ cellSelectionRangeData,
3839
+ headerIndicatorColKeys,
3840
+ bodyIndicatorRowKeys,
3841
+ } = this;
3842
+
3843
+ // header props
3844
+ const headerProps = {
3845
+ class: clsName("header"),
3846
+ style: {
3847
+ cursor:
3848
+ this.isColumnResizerHover || this.isColumnResizing
3849
+ ? "col-resize"
3850
+ : "",
3851
+ },
3852
+ props: {
3853
+ columnsOptionResetTime: this.columnsOptionResetTime,
3854
+ tableViewportWidth,
3855
+ groupColumns,
3856
+ colgroups,
3857
+ isGroupHeader: this.isGroupHeader,
3858
+ fixedHeader,
3859
+ checkboxOption,
3860
+ sortOption,
3861
+ cellStyleOption,
3862
+ eventCustomOption: this.eventCustomOption,
3863
+ headerRows: this.headerRows,
3864
+ cellSelectionData,
3865
+ cellSelectionRangeData,
3866
+ headerIndicatorColKeys,
3867
+ },
3868
+ nativeOn: {
3869
+ click: () => {
3870
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
3871
+ },
3872
+ mouseleave: (event) => {
3873
+ this.headerMouseleave(event);
3874
+ },
3875
+ },
3876
+ };
3877
+
3878
+ // body props
3879
+ const bodyProps = {
3880
+ ref: this.tableBodyRef,
3881
+ class: [clsName("body"), this.tableBodyClass],
3882
+ props: {
3883
+ tableViewportWidth,
3884
+ columnsOptionResetTime: this.columnsOptionResetTime,
3885
+ colgroups,
3886
+ expandOption,
3887
+ checkboxOption,
3888
+ actualRenderTableData,
3889
+ rowKeyFieldName,
3890
+ radioOption,
3891
+ virtualScrollOption,
3892
+ isVirtualScroll,
3893
+ cellStyleOption,
3894
+ cellSpanOption: this.cellSpanOption,
3895
+ eventCustomOption: this.eventCustomOption,
3896
+ cellSelectionOption: this.cellSelectionOption,
3897
+ hasFixedColumn: this.hasFixedColumn,
3898
+ cellSelectionData,
3899
+ cellSelectionRangeData,
3900
+ allRowKeys,
3901
+ editOption,
3902
+ highlightRowKey: this.highlightRowKey,
3903
+ showVirtualScrollingPlaceholder,
3904
+ bodyIndicatorRowKeys,
3905
+ },
3906
+ on: {
3907
+ [EMIT_EVENTS.BODY_CELL_WIDTH_CHANGE]:
3908
+ debouncedBodyCellWidthChange,
3909
+ [EMIT_EVENTS.HIGHLIGHT_ROW_CHANGE]:
3910
+ this[INSTANCE_METHODS.SET_HIGHLIGHT_ROW],
3911
+ },
3912
+ scopedSlots: {
3913
+ body: this.$slots.body,
3914
+ },
3915
+ };
3916
+
3917
+ // footer props
3918
+ const footerProps = {
3919
+ class: [clsName("footer")],
3920
+ props: {
3921
+ colgroups,
3922
+ footerData: this.footerData,
3923
+ rowKeyFieldName,
3924
+ cellStyleOption,
3925
+ fixedFooter,
3926
+ cellSpanOption: this.cellSpanOption,
3927
+ eventCustomOption: this.eventCustomOption,
3928
+ hasFixedColumn: this.hasFixedColumn,
3929
+ allRowKeys,
3930
+ footerRows: this.footerRows,
3931
+ },
3932
+ nativeOn: {
3933
+ click: () => {
3934
+ this[INSTANCE_METHODS.STOP_EDITING_CELL]();
3935
+ },
3936
+ },
3937
+ };
3938
+
3939
+ // table root props
3940
+ const tableRootProps = {
3941
+ ref: this.tableRootRef,
3942
+ class: {
3943
+ "vue-table-root": true,
3944
+ },
3945
+ };
3946
+
3947
+ // table container wrapper props
3948
+ const tableContainerWrapperProps = {
3949
+ ref: this.tableContainerWrapperRef,
3950
+ style: this.tableContainerWrapperStyle,
3951
+ class: {
3952
+ "ve-table": true,
3953
+ [clsName("border-around")]: this.borderAround,
3954
+ },
3955
+ props: {
3956
+ tagName: "div",
3957
+ },
3958
+ on: {
3959
+ "on-dom-resize-change": ({ height }) => {
3960
+ this.tableOffestHeight = height;
3961
+ this.initVirtualScroll();
3962
+ // fixed #404
3963
+ this.initScrolling();
3964
+ this.setScrollBarStatus();
3965
+ this.hooks.triggerHook(HOOKS_NAME.TABLE_SIZE_CHANGE);
3966
+ },
3967
+ },
3968
+ directives: [
3969
+ {
3970
+ name: "click-outside",
3971
+ value: (e) => {
3972
+ this.tableClickOutside(e);
3973
+ },
3974
+ },
3975
+ ],
3976
+ };
3977
+
3978
+ // table container props
3979
+ const tableContainerProps = {
3980
+ ref: this.tableContainerRef,
3981
+ class: this.tableContainerClass,
3982
+ style: tableContainerStyle,
3983
+ on: {
3984
+ scroll: () => {
3985
+ const tableContainerRef =
3986
+ this.$refs[this.tableContainerRef];
3987
+
3988
+ this.hooks.triggerHook(
3989
+ HOOKS_NAME.TABLE_CONTAINER_SCROLL,
3990
+ tableContainerRef,
3991
+ );
3992
+ this.setScrolling(tableContainerRef);
3993
+
3994
+ if (isVirtualScroll) {
3995
+ this.tableContainerVirtualScrollHandler(
3996
+ tableContainerRef,
3997
+ );
3998
+
3999
+ const {
4000
+ virtualScrollStartIndex: startIndex,
4001
+ previewVirtualScrollStartIndex: previewStartIndex,
4002
+ } = this;
4003
+
4004
+ const differ = Math.abs(startIndex - previewStartIndex);
4005
+
4006
+ this.previewVirtualScrollStartIndex = startIndex;
4007
+
4008
+ // default placeholder per scrolling row count
4009
+ if (
4010
+ differ > this.defaultPlaceholderPerScrollingRowCount
4011
+ ) {
4012
+ this.showVirtualScrollingPlaceholder = true;
4013
+ } else {
4014
+ this.showVirtualScrollingPlaceholder = false;
4015
+ }
4016
+
4017
+ this.debounceScrollEnded();
4018
+ }
4019
+ },
4020
+ mouseup: () => {
4021
+ // 事件的先后顺序 containerMouseup > bodyCellMousedown > bodyCellMouseup > bodyCellClick
4022
+ this.tableContainerMouseup();
4023
+ },
4024
+ mousemove: (event) => {
4025
+ // todo
4026
+ },
4027
+ },
4028
+ };
4029
+
4030
+ // table wrapper props
4031
+ const tableWrapperProps = {
4032
+ ref: this.tableContentWrapperRef,
4033
+ class: [clsName("content-wrapper")],
4034
+ props: {
4035
+ tagName: "div",
4036
+ },
4037
+ on: {
4038
+ "on-dom-resize-change": ({ height }) => {
4039
+ this.tableHeight = height;
4040
+ },
4041
+ },
4042
+ };
4043
+
4044
+ // tale props
4045
+ const tableProps = {
4046
+ ref: this.tableRef,
4047
+ class: [clsName("content"), tableClass],
4048
+ style: tableStyle,
4049
+ };
4050
+
4051
+ // selection props
4052
+ const selectionProps = {
4053
+ ref: this.cellSelectionRef,
4054
+ props: {
4055
+ tableEl: this.$refs[this.tableRef],
4056
+ allRowKeys,
4057
+ colgroups,
4058
+ parentRendered: this.parentRendered,
4059
+ hooks: this.hooks,
4060
+ cellSelectionData,
4061
+ isAutofillStarting: this.isAutofillStarting,
4062
+ cellSelectionRangeData,
4063
+ currentCellSelectionType: this.currentCellSelectionType,
4064
+ showVirtualScrollingPlaceholder,
4065
+ isVirtualScroll,
4066
+ virtualScrollVisibleIndexs: this.virtualScrollVisibleIndexs,
4067
+ isCellEditing: this.isCellEditing,
4068
+ cellAutofillOption: this.cellAutofillOption,
4069
+ },
4070
+ on: {
4071
+ [EMIT_EVENTS.CELL_SELECTION_RANGE_DATA_CHANGE]: (newData) => {
4072
+ this.cellSelectionRangeDataChange(newData);
4073
+ },
4074
+ },
4075
+ };
4076
+
4077
+ // edit input props
4078
+ const editInputProps = {
4079
+ ref: this.editInputRef,
4080
+ props: {
4081
+ hooks: this.hooks,
4082
+ parentRendered: this.parentRendered,
4083
+ inputStartValue: this.editorInputStartValue,
4084
+ rowKeyFieldName,
4085
+ tableData: this.tableData,
4086
+ cellSelectionData,
4087
+ colgroups,
4088
+ editingCell: this.editingCell,
4089
+ isCellEditing: this.isCellEditing,
4090
+ allRowKeys,
4091
+ hasXScrollBar: this.hasXScrollBar,
4092
+ hasYScrollBar: this.hasYScrollBar,
4093
+ hasRightFixedColumn: this.hasRightFixedColumn,
4094
+ scrollBarWidth: this.getScrollBarWidth(),
4095
+ },
4096
+ on: {
4097
+ // edit input click
4098
+ [EMIT_EVENTS.EDIT_INPUT_CLICK]: () => {
4099
+ this.enableStopEditing = false;
4100
+ },
4101
+ // edit input value change
4102
+ [EMIT_EVENTS.EDIT_INPUT_VALUE_CHANGE]: (value) => {
4103
+ this.updateEditingCellValue(value);
4104
+ },
4105
+ // copy
4106
+ [EMIT_EVENTS.EDIT_INPUT_COPY]: (e) => {
4107
+ this.editorCopy(e);
4108
+ },
4109
+ // paste
4110
+ [EMIT_EVENTS.EDIT_INPUT_PASTE]: (e) => {
4111
+ this.editorPaste(e);
4112
+ },
4113
+ // cut
4114
+ [EMIT_EVENTS.EDIT_INPUT_CUT]: (e) => {
4115
+ this.editorCut(e);
4116
+ },
4117
+ },
4118
+ };
4119
+
4120
+ // 直接在组件上写事件,单元测试无法通过。如 on={{"on-node-click":()=>{}}}
4121
+ const contextmenuProps = {
4122
+ ref: this.contextmenuRef,
4123
+ props: {
4124
+ eventTarget: this.contextmenuEventTarget,
4125
+ options: contextmenuOptions,
4126
+ },
4127
+ on: {
4128
+ "on-node-click": (type) => {
4129
+ this.contextmenuItemClick(type);
4130
+ },
4131
+ },
4132
+ };
4133
+
4134
+ // column resizer props
4135
+ const columnResizerProps = {
4136
+ props: {
4137
+ parentRendered: this.parentRendered,
4138
+ tableContainerEl: this.$refs[this.tableContainerRef],
4139
+ hooks: this.hooks,
4140
+ colgroups,
4141
+ isColumnResizerHover: this.isColumnResizerHover,
4142
+ isColumnResizing: this.isColumnResizing,
4143
+ setIsColumnResizerHover: this.setIsColumnResizerHover,
4144
+ setIsColumnResizing: this.setIsColumnResizing,
4145
+ setColumnWidth: this.setColumnWidth,
4146
+ columnWidthResizeOption: this.columnWidthResizeOption,
4147
+ },
4148
+ };
4149
+
4150
+ return (
4151
+ <div {...tableRootProps}>
4152
+ <VueDomResizeObserver {...tableContainerWrapperProps}>
4153
+ <div {...tableContainerProps}>
4154
+ {/* virtual view phantom */}
4155
+ {this.getVirtualViewPhantom()}
4156
+ {/* vue 实例类型,访问dom时需要通过$el属性访问 */}
4157
+ <VueDomResizeObserver {...tableWrapperProps}>
4158
+ <table {...tableProps}>
4159
+ {/* colgroup */}
4160
+ <Colgroup
4161
+ colgroups={colgroups}
4162
+ enableColumnResize={enableColumnResize}
4163
+ />
4164
+ {/* table header */}
4165
+ {showHeader && <Header {...headerProps} />}
4166
+ {/* table body */}
4167
+ <Body {...bodyProps}>
4168
+ {this.$slots.body}
4169
+ </Body>
4170
+ {/* table footer */}
4171
+ <Footer {...footerProps}>
4172
+ {this.$slots.footer}
4173
+ </Footer>
4174
+ </table>
4175
+ {/* cell selection */}
4176
+ {enableCellSelection && (
4177
+ <Selection {...selectionProps} />
4178
+ )}
4179
+ </VueDomResizeObserver>
4180
+ </div>
4181
+ {/* edit input */}
4182
+ {enableCellSelection && <EditInput {...editInputProps} />}
4183
+ {/* contextmenu */}
4184
+ {(this.enableHeaderContextmenu ||
4185
+ this.enableBodyContextmenu) && (
4186
+ <VeContextmenu {...contextmenuProps} />
4187
+ )}
4188
+ {/* column resizer */}
4189
+ {enableColumnResize && (
4190
+ <ColumnResizer {...columnResizerProps} />
4191
+ )}
4192
+ </VueDomResizeObserver>
4193
+ </div>
4194
+ );
4195
+ },
4196
+ };