umy-ui-table 1.2.4 → 1.2.6

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 (63) hide show
  1. package/lib/button.js +1 -1
  2. package/lib/icon.js +1 -1
  3. package/lib/index.js +1 -1
  4. package/lib/locale/format.js +1 -1
  5. package/lib/locale/index.js +1 -72
  6. package/lib/mixins/locale.js +1 -1
  7. package/lib/theme-chalk/button.css +1 -1
  8. package/lib/theme-chalk/icon.css +1 -1
  9. package/lib/theme-chalk/iconfont.1785242763644.ttf +0 -0
  10. package/lib/theme-chalk/iconfont.1785242763644.woff +0 -0
  11. package/lib/theme-chalk/iconfont.1785242763644.woff2 +0 -0
  12. package/lib/theme-chalk/index.css +1 -1
  13. package/lib/theme-chalk/u-table.css +1 -1
  14. package/lib/theme-chalk/ux-grid.css +1 -1
  15. package/lib/u-table-column.js +1 -1
  16. package/lib/u-table.js +1 -1
  17. package/lib/umy-ui.common.js +1 -1
  18. package/lib/utils/util.js +1 -1
  19. package/lib/ux-grid.js +1 -1
  20. package/lib/ux-table-column.js +1 -1
  21. package/package.json +4 -3
  22. package/packages/.DS_Store +0 -0
  23. package/packages/input/.DS_Store +0 -0
  24. package/packages/pagination/.DS_Store +0 -0
  25. package/packages/scrollbar/.DS_Store +0 -0
  26. package/packages/select/.DS_Store +0 -0
  27. package/packages/table/.DS_Store +0 -0
  28. package/packages/tag/.DS_Store +0 -0
  29. package/packages/tools/.DS_Store +0 -0
  30. package/packages/tools/locale/index.js +2 -48
  31. package/packages/tools/utils/.DS_Store +0 -0
  32. package/packages/tooltip/.DS_Store +0 -0
  33. package/packages/u-table/.DS_Store +0 -0
  34. package/packages/ux-grid/.DS_Store +0 -0
  35. package/packages/ux-grid/mixins/index.js +133 -25
  36. package/packages/ux-grid/src/dialog-draft.js +75 -0
  37. package/packages/ux-grid/src/element-renderer.js +809 -0
  38. package/packages/ux-grid/src/grid-height.js +75 -0
  39. package/packages/ux-grid/src/grid-kernel.js +14 -0
  40. package/packages/ux-grid/src/setup.js +42 -0
  41. package/packages/ux-grid/src/ux-grid.vue +215 -57
  42. package/packages/ux-grid/test/browser-acceptance.cjs +192 -0
  43. package/packages/ux-grid/test/browser-baseline-loader.cjs +10 -0
  44. package/packages/ux-grid/test/browser-entry.js +242 -0
  45. package/packages/ux-grid/test/browser-layout-contracts.cjs +105 -0
  46. package/packages/ux-grid/test/browser-layout-entry.js +66 -0
  47. package/packages/ux-grid/test/browser-renderer-contracts.cjs +262 -0
  48. package/packages/ux-grid/test/browser-renderer-entry.js +129 -0
  49. package/packages/ux-grid/test/browser-resize-contracts.cjs +150 -0
  50. package/packages/ux-grid/test/compatibility.cjs +176 -0
  51. package/packages/ux-grid/test/contracts.cjs +281 -0
  52. package/packages/ux-grid/test/delivery-umd.cjs +48 -0
  53. package/packages/ux-grid/test/delivery.cjs +103 -0
  54. package/packages/ux-grid/test/integration.cjs +132 -0
  55. package/packages/ux-grid/test/real-kernel-contracts.cjs +335 -0
  56. package/packages/ux-grid/test/real-kernel-events.cjs +233 -0
  57. package/packages/ux-grid/test/renderer-async.cjs +140 -0
  58. package/packages/ux-grid/test/renderer-boundaries.cjs +196 -0
  59. package/packages/ux-grid/test/ui-components.cjs +103 -0
  60. package/tools/locale/format.js +1 -1
  61. package/tools/locale/index.js +1 -7
  62. package/tools/mixins/locale.js +1 -1
  63. package/tools/utils/util.js +1 -1
@@ -1 +1 @@
1
- module.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist/",n(n.s=35)}({33:function(e,t){e.exports=require("vxe-table/lib/column")},35:function(e,t,n){"use strict";n.r(t);var r=n(33),o=n.n(r),u=Object.assign({},o.a,{name:"UxTableColumn"});u.install=function(e){e.component(u.name,u)},t.default=u}});
1
+ module.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist/",n(n.s=39)}({35:function(e,t){e.exports=require("vxe-table/lib/column")},39:function(e,t,n){"use strict";n.r(t);var r=n(35),o=n.n(r),u=Object.assign({},o.a,{name:"UxTableColumn"});u.install=function(e){e.component(u.name,u)},t.default=u}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umy-ui-table",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "一个基于 vue 的 PC 端表格UI库,解决万级数据渲染卡顿问题,过万数据点击全选卡顿,等等问题",
5
5
  "author": {
6
6
  "name": "foriacus"
@@ -9,7 +9,7 @@
9
9
  "lint": "eslint --fix --ext .js,.vue examples",
10
10
  "clean": "rimraf lib && rimraf packages/*/lib",
11
11
  "lib:file": "node build/build-entry.js",
12
- "lib:utils": "cross-env BABEL_ENV=utils babel tools --out-dir lib",
12
+ "lib:utils": "cross-env BABEL_ENV=utils babel tools --out-dir lib && webpack --config build/webpack.locale.js",
13
13
  "lib:umd": "node build/build-locale.js",
14
14
  "lib:theme": "gulp build",
15
15
  "lib": "npm run clean && npm run lib:file && webpack --config build/webpack.conf.js && webpack --config build/webpack.common.js && webpack --config build/webpack.component.js && npm run lib:utils && npm run lib:umd && npm run lib:theme"
@@ -34,6 +34,7 @@
34
34
  "url": "git+https://github.com/popo-fishes/umy-ui.git"
35
35
  },
36
36
  "dependencies": {
37
+ "babel-helper-vue-jsx-merge-props": "^2.0.0",
37
38
  "async-validator": "~1.8.1",
38
39
  "deepmerge": "^1.2.0",
39
40
  "normalize-wheel": "^1.0.1",
@@ -41,6 +42,7 @@
41
42
  "throttle-debounce": "^1.0.1",
42
43
  "vuedraggable": "^2.23.2",
43
44
  "vxe-table": "^3.22.9",
45
+ "vxe-pc-ui": "3.16.23",
44
46
  "@vxe-ui/core": "^3.4.19",
45
47
  "xe-utils": ">= 3"
46
48
  },
@@ -54,7 +56,6 @@
54
56
  "animejs": "^3.1.0",
55
57
  "babel-cli": "^6.26.0",
56
58
  "babel-core": "^6.26.3",
57
- "babel-helper-vue-jsx-merge-props": "^2.0.0",
58
59
  "babel-loader": "^7.1.5",
59
60
  "babel-plugin-add-module-exports": "^0.2.1",
60
61
  "babel-plugin-istanbul": "^4.1.1",
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,48 +1,2 @@
1
- import defaultLang from './lang/zh-CN';
2
- import Vue from 'vue';
3
- import deepmerge from 'deepmerge';
4
- import Format from './format';
5
-
6
- const format = Format(Vue);
7
- let lang = defaultLang;
8
- let merged = false;
9
- let i18nHandler = function() {
10
- const vuei18n = Object.getPrototypeOf(this || Vue).$t;
11
- if (typeof vuei18n === 'function' && !!Vue.locale) {
12
- if (!merged) {
13
- merged = true;
14
- Vue.locale(
15
- Vue.config.lang,
16
- deepmerge(lang, Vue.locale(Vue.config.lang) || {}, { clone: true })
17
- );
18
- }
19
- return vuei18n.apply(this, arguments);
20
- }
21
- };
22
-
23
- export const t = function(path, options) {
24
- let value = i18nHandler.apply(this, arguments);
25
- if (value !== null && value !== undefined) return value;
26
- const array = path.split('.');
27
- let current = lang;
28
- for (let i = 0, j = array.length; i < j; i++) {
29
- const property = array[i];
30
- value = current[property];
31
- if (i === j - 1) {
32
- return format(value, options)
33
- }
34
- if (!value) return '';
35
- current = value;
36
- }
37
- return '';
38
- };
39
-
40
- export const use = function(l) {
41
- lang = l || lang;
42
- };
43
-
44
- export const i18n = function(fn) {
45
- i18nHandler = fn || i18nHandler;
46
- };
47
-
48
- export default { use, t, i18n };
1
+ // Table, pagination and the public locale entry share one language store.
2
+ export { default, use, t, i18n } from "../../../tools/locale";
Binary file
Binary file
Binary file
Binary file
@@ -1,5 +1,41 @@
1
1
  import { isArrayFn } from "../../utils/common";
2
+ import { createDialogDraft, mergeDialogDraft } from "../src/dialog-draft";
3
+ // Vue 2 instance listeners ($on/$once) are not included in $listeners.
4
+ function hasGridListener(vm, name) {
5
+ const events = vm._events && vm._events[name];
6
+ return !!((vm.$listeners && vm.$listeners[name]) || (events && events.length));
7
+ }
8
+ function bridgeStoppedClick(vm, params, header) {
9
+ if (vm._isDestroyed || vm._isBeingDestroyed) return;
10
+ const event = params && params.$event;
11
+ if (!event || event.type !== "click" || !event.target || !event.target.closest) return;
12
+ // Only VXE's built-in controls stop propagation. Row/cell-triggered actions
13
+ // must reach the native cell/header handler so current-change stays ordered.
14
+ if (!event.target.closest(".vxe-cell--checkbox,.vxe-cell--radio,.vxe-table--expand-btn,.vxe-cell--tree-btn,.vxe-sort--asc-btn,.vxe-sort--desc-btn")) return;
15
+ if (!hasGridListener(vm, header ? "header-click" : "cell-click") &&
16
+ (header || !hasGridListener(vm, "row-click"))) return;
17
+ const cell = event.target.closest(header ? "th" : "td");
18
+ const table = vm.$refs.singleTable;
19
+ const columnNode = cell && table && table.getColumnNode ? table.getColumnNode(cell) : null;
20
+ const column = params.column || (columnNode && columnNode.item);
21
+ if (!cell || !column) return;
22
+ const payload = Object.assign({}, params, { column, cell });
23
+ if (header) vm.headerClick(payload);
24
+ else vm.cellClick(payload);
25
+ }
26
+ function repeatedClick(vm, key, event) {
27
+ if (!event) return false;
28
+ const seen = vm[key] || (vm[key] = new WeakSet());
29
+ if (seen.has(event)) return true;
30
+ seen.add(event);
31
+ return false;
32
+ }
2
33
  export default {
34
+ beforeDestroy() {
35
+ this.stopDialogSync();
36
+ clearTimeout(this._times);
37
+ this.clearNode();
38
+ },
3
39
  props: {
4
40
  beautifyTable: { default: false, type: Boolean }, // 美化表格,修改了样式
5
41
  showDialogIcon: { default: true, type: Boolean }, // 是否显示操作字段的上下移动按钮(侧滑框)
@@ -95,9 +131,10 @@ export default {
95
131
  },
96
132
  // 打开自定义字段框
97
133
  plDialogOpens() {
98
- this._times = null;
99
- // 打开时同步一次最新 dialogData(替代 deep watcher,避免每次变更都深拷贝)
100
- this.newDialogData = JSON.parse(JSON.stringify(this.dialogData));
134
+ if (this._dialogUnwatch) return;
135
+ this._dialogDraft = createDialogDraft(this.dialogData);
136
+ this.newDialogData = this._dialogDraft.draft.slice();
137
+ this._dialogUnwatch = this.$watch("dialogData", () => this.syncDialogDraft(), { deep: true });
101
138
  this.$refs.plDialog.style.width = 300 + "px";
102
139
  this._times = setTimeout(() => {
103
140
  this.plDialogFals = true;
@@ -113,31 +150,43 @@ export default {
113
150
  },
114
151
  // 关闭自定义字段框(取消选择)
115
152
  closeModal() {
153
+ this.stopDialogSync();
116
154
  this.plDialogFals = false;
117
155
  clearTimeout(this._times);
118
156
  this.$refs.plDialog.style.width = 0 + "px";
119
- this.aBox.style.display = "none";
120
157
  this.clearNode();
121
158
  this.newDialogData = JSON.parse(JSON.stringify(this.dialogData));
122
159
  },
123
160
  // 确认按钮
124
161
  confirmField() {
162
+ this.syncDialogDraft();
163
+ this.stopDialogSync();
125
164
  this.$emit("show-field", this.newDialogData);
126
165
  this.plDialogFals = false;
127
166
  clearTimeout(this._times);
128
167
  this.$refs.plDialog.style.width = 0 + "px";
129
- this.aBox.style.display = "none";
130
168
  this.clearNode();
131
169
  },
132
170
  // 重置按钮
133
171
  reset() {
172
+ this.syncDialogDraft();
173
+ this.stopDialogSync();
134
174
  this.$emit("reset", this.newDialogData);
135
175
  this.plDialogFals = false;
136
176
  clearTimeout(this._times);
137
177
  this.$refs.plDialog.style.width = 0 + "px";
138
- this.aBox.style.display = "none";
139
178
  this.clearNode();
140
179
  },
180
+ syncDialogDraft() {
181
+ if (!this._dialogDraft) return;
182
+ this._dialogDraft = mergeDialogDraft(this._dialogDraft, this.dialogData, this.newDialogData);
183
+ this.newDialogData = this._dialogDraft.value;
184
+ },
185
+ stopDialogSync() {
186
+ if (this._dialogUnwatch) this._dialogUnwatch();
187
+ this._dialogUnwatch = null;
188
+ this._dialogDraft = null;
189
+ },
141
190
  // 修改字段名按钮事件
142
191
  amendField(item, index) {
143
192
  this.$emit("amend-field", item, index);
@@ -147,10 +196,6 @@ export default {
147
196
  // 删除节点
148
197
  let parent = this.aBox ? this.aBox.parentNode : "";
149
198
  parent && parent.removeChild(this.aBox);
150
- let doms = document.getElementsByClassName("modal-backdrop");
151
- if (doms.length > 0) {
152
- document.body.removeChild(doms[0]);
153
- }
154
199
  this.aBox = null;
155
200
  },
156
201
 
@@ -202,7 +247,7 @@ export default {
202
247
  }
203
248
  });
204
249
  // 当选择项发生变化时会触发该事件(仅在有监听者时取值,避免无监听时全表扫描)
205
- if (this.$listeners["selection-change"]) {
250
+ if (hasGridListener(this, "selection-change")) {
206
251
  const data = this.$refs.singleTable.getCheckboxRecords();
207
252
  this.$emit("selection-change", data);
208
253
  }
@@ -213,7 +258,7 @@ export default {
213
258
  if (this.$refs.singleTable) {
214
259
  this.$refs.singleTable.setAllCheckboxRow(checked);
215
260
  // 当选择项发生变化时会触发该事件(仅在有监听者时取值)
216
- if (this.$listeners["selection-change"]) {
261
+ if (hasGridListener(this, "selection-change")) {
217
262
  const data = this.$refs.singleTable.getCheckboxRecords();
218
263
  this.$emit("selection-change", data);
219
264
  }
@@ -226,7 +271,7 @@ export default {
226
271
  if (this.$refs.singleTable) {
227
272
  this.$refs.singleTable.clearCheckboxRow();
228
273
  // 当选择项发生变化时会触发该事件(仅在有监听者时取值)
229
- if (this.$listeners["selection-change"]) {
274
+ if (hasGridListener(this, "selection-change")) {
230
275
  const data = this.$refs.singleTable.getCheckboxRecords();
231
276
  this.$emit("selection-change", data);
232
277
  }
@@ -252,7 +297,8 @@ export default {
252
297
  },
253
298
  // 对 Table 进行重新布局。当 Table 或其祖先元素由隐藏切换为显示时,可能需要调用此方法
254
299
  doLayout() {
255
- this.$refs.singleTable.recalculate();
300
+ const revision = this._selectedRevision || 0;
301
+ this.refreshSelectedAfter(this.$refs.singleTable.recalculate(), revision);
256
302
  },
257
303
  // 让表格滚动条回到顶部,和左侧
258
304
  pagingScrollTopLeft(top = 0, left = 0) {
@@ -277,7 +323,8 @@ export default {
277
323
  return this.$refs.singleTable.loadColumn(data);
278
324
  },
279
325
  refreshColumn() {
280
- this.$refs.singleTable.refreshColumn();
326
+ const revision = this._selectedRevision || 0;
327
+ this.refreshSelectedAfter(this.$refs.singleTable.refreshColumn(), revision);
281
328
  },
282
329
  // 激活编辑状态
283
330
  setActiveRow(row) {
@@ -453,31 +500,34 @@ export default {
453
500
  selectAll(params) {
454
501
  // vxe 事件参数里的 records 是惰性 getter,仅在有监听者时才取值,避免每次全选都全表扫描
455
502
  if (
456
- this.$listeners["select-all"] ||
457
- this.$listeners["selection-change"]
503
+ hasGridListener(this, "select-all") ||
504
+ hasGridListener(this, "selection-change")
458
505
  ) {
459
506
  const data =
460
507
  params && typeof params.records === "function"
461
508
  ? params.records()
462
- : this.$refs.singleTable.getCheckboxRecords();
509
+ : params && Array.isArray(params.records)
510
+ ? params.records : this.$refs.singleTable.getCheckboxRecords();
463
511
  this.$emit("select-all", data);
464
512
  // 当选择项发生变化时会触发该事件
465
513
  this.$emit("selection-change", data);
466
514
  }
515
+ bridgeStoppedClick(this, params, true);
467
516
  },
468
517
  // 当用户手动勾选数据行的 Checkbox 时触发的事件
469
518
  plSelect(params) {
470
519
  const { row, records } = params || {};
471
520
  // vxe 事件参数里的 records 是惰性 getter,仅在有监听者时才取值,避免每次勾选都全表扫描
472
- if (this.$listeners["select"] || this.$listeners["selection-change"]) {
521
+ if (hasGridListener(this, "select") || hasGridListener(this, "selection-change")) {
473
522
  const data =
474
523
  typeof records === "function"
475
524
  ? records()
476
- : this.$refs.singleTable.getCheckboxRecords();
525
+ : Array.isArray(records) ? records : this.$refs.singleTable.getCheckboxRecords();
477
526
  this.$emit("select", data, row);
478
527
  // 当选择项发生变化时会触发该事件
479
528
  this.$emit("selection-change", data);
480
529
  }
530
+ bridgeStoppedClick(this, params, false);
481
531
  },
482
532
  // 只对 type=radio 有效,当手动勾选并且值发生改变时触发的事件
483
533
  radioChange({
@@ -488,13 +538,16 @@ export default {
488
538
  columnIndex,
489
539
  $columnIndex,
490
540
  cell,
541
+ $event,
491
542
  }) {
492
543
  this.$emit("radio-change", row, column);
544
+ bridgeStoppedClick(this, { row, column, cell, $event }, false);
493
545
  },
494
546
  // 当表格的排序条件发生变化的时候会触发该事件
495
- sortChange({ column, property, order }) {
496
- let objs = { column, prop: property, order };
547
+ sortChange({ column, property, field, order, $event }) {
548
+ let objs = { column, prop: property === undefined ? field : property, order };
497
549
  this.$emit("sort-change", objs);
550
+ bridgeStoppedClick(this, { column, $event }, true);
498
551
  },
499
552
  // 当表格的当前行发生变化的时候会触发该事件
500
553
  currentChange({ row }) {
@@ -521,15 +574,32 @@ export default {
521
574
  $columnIndex,
522
575
  $event,
523
576
  });
577
+ bridgeStoppedClick(this, { row, column, $event }, false);
524
578
  },
525
579
  // 当表格的筛选条件发生变化的时候会触发该事件
526
- filterChange({ column, property, values, datas, filters, $event }) {
580
+ filterChange({ column, property, field, values, datas, filters, $event }) {
581
+ const supplied = typeof filters === "function" ? filters() : filters;
582
+ const table = this.$refs.singleTable;
583
+ const columns = table && table.getTableColumn ? table.getTableColumn().visibleColumn : null;
584
+ // The legacy wrapper reports every visible filterable column, including
585
+ // those with no selection. Keep the new kernel's checked-only API intact.
586
+ const compatibleFilters = columns ? columns.filter(item => item.filters && item.filters.length).map(item => {
587
+ const checked = item.filters.filter(option => option.checked);
588
+ const existing = (supplied || []).find(entry => entry.column === item);
589
+ return Object.assign({}, existing, {
590
+ column: item,
591
+ field: item.field || item.property,
592
+ property: item.property || item.field,
593
+ values: checked.map(option => option.value),
594
+ datas: checked.map(option => option.data),
595
+ });
596
+ }) : supplied;
527
597
  this.$emit("filter-change", {
528
598
  column,
529
- property,
599
+ property: property === undefined ? field : property,
530
600
  values,
531
601
  datas,
532
- filters,
602
+ filters: compatibleFilters,
533
603
  $event,
534
604
  });
535
605
  },
@@ -544,6 +614,10 @@ export default {
544
614
  cell,
545
615
  $event,
546
616
  }) {
617
+ // VXE dispatches this from mouseover, which also bubbles when moving
618
+ // between descendants. The legacy wrapper exposes mouseenter semantics.
619
+ const relatedTarget = $event && $event.relatedTarget;
620
+ if (cell && relatedTarget && relatedTarget.nodeType && cell.contains(relatedTarget)) return;
547
621
  this.$emit("cell-mouse-enter", row, column, cell, $event);
548
622
  },
549
623
  // 当单元格 hover 退出时会触发该事件
@@ -570,6 +644,7 @@ export default {
570
644
  cell,
571
645
  $event,
572
646
  }) {
647
+ if (repeatedClick(this, "_cellClickEvents", $event)) return;
573
648
  this.$emit("cell-click", row, column, cell, $event);
574
649
  // row-click 当某一行被点击时会触发该事件 row, event, column
575
650
  // 只有当点击的单元格不是复选框才触发行事件!
@@ -606,6 +681,7 @@ export default {
606
681
  columnIndex,
607
682
  $event,
608
683
  }) {
684
+ if (repeatedClick(this, "_headerClickEvents", $event)) return;
609
685
  this.$emit("header-click", column, $event);
610
686
  },
611
687
  // 当某一列的表头被鼠标右键点击时触发该事件 column, $event
@@ -686,9 +762,39 @@ export default {
686
762
  $columnIndex,
687
763
  });
688
764
  },
765
+ // elx-grid 扩展事件:鼠标或键盘切换当前选中单元格时触发
766
+ editCurrentlyActive({ row, column, cell }) {
767
+ this._selectedRevision = (this._selectedRevision || 0) + 1;
768
+ const table = this.$refs.singleTable;
769
+ const targetCell =
770
+ cell ||
771
+ (table && table.getCellElement
772
+ ? table.getCellElement(row, column)
773
+ : null);
774
+ this.$emit("edit-currently-active", {
775
+ row,
776
+ column,
777
+ cell: targetCell,
778
+ });
779
+ },
780
+ // Only public wrapper refreshes participate; no global VXE hooks or
781
+ // private editStore access. Preserve the legacy undefined method return.
782
+ refreshSelectedAfter(completion, revision = this._selectedRevision || 0) {
783
+ Promise.resolve(completion).then(() => this.$nextTick()).then(() => {
784
+ if (this._isDestroyed || this._isBeingDestroyed ||
785
+ revision !== (this._selectedRevision || 0) ||
786
+ !hasGridListener(this, "edit-currently-active")) return;
787
+ const table = this.$refs.singleTable;
788
+ const selected = table && table.getSelectedCell ? table.getSelectedCell() : null;
789
+ if (!selected) return;
790
+ const cell = table.getCellElement(selected.row, selected.column);
791
+ if (cell) this.editCurrentlyActive(Object.assign({}, selected, { cell }));
792
+ }).catch(error => console.error("[UxGrid] Selected cell refresh failed", error));
793
+ },
689
794
  // 当树节点展开或收起时会触发该事件
690
795
  toggleTreeExpandEv(row) {
691
796
  this.$emit("toggle-tree-expand", row);
797
+ bridgeStoppedClick(this, row, false);
692
798
  },
693
799
  // 键盘按下事件
694
800
  keydown({ $event }) {
@@ -700,7 +806,9 @@ export default {
700
806
  },
701
807
  // vxe 后续重新加载/刷新数据并渲染完成后触发
702
808
  dataRendered(params) {
809
+ const revision = this._selectedRevision || 0;
703
810
  this.$emit("data-rendered", params);
811
+ this.refreshSelectedAfter(undefined, revision);
704
812
  },
705
813
  },
706
814
  };
@@ -0,0 +1,75 @@
1
+ import XEUtils from "xe-utils";
2
+
3
+ // Keep the source snapshot separate from the editable draft. Only an open
4
+ // dialog owns this state; closed grids do not traverse dialogData.
5
+ export function createDialogDraft(source) {
6
+ return { source: source.slice(), baseline: XEUtils.clone(source, true), draft: XEUtils.clone(source, true) };
7
+ }
8
+
9
+ export function mergeDialogDraft(previous, source, draft) {
10
+ const keyOf = item => {
11
+ for (const field of ["id", "field", "prop", "key"]) {
12
+ if (item[field] !== undefined && item[field] !== null) return field + ":" + item[field];
13
+ }
14
+ return null;
15
+ };
16
+ const matchIndices = (items, originals) => {
17
+ const indices = items.map(() => -1);
18
+ const used = new Set();
19
+ const assign = (index, oldIndex) => {
20
+ if (oldIndex >= 0 && !used.has(oldIndex)) {
21
+ indices[index] = oldIndex;
22
+ used.add(oldIndex);
23
+ }
24
+ };
25
+ // Reserve every surviving reference before considering positional fallback:
26
+ // a new item inserted at index 0 must not take the old index of a later A.
27
+ items.forEach((item, index) => {
28
+ assign(index, originals.findIndex((entry, oldIndex) => entry === item && !used.has(oldIndex)));
29
+ });
30
+ items.forEach((item, index) => {
31
+ const key = keyOf(item);
32
+ if (indices[index] < 0 && key !== null) {
33
+ assign(index, previous.baseline.findIndex((entry, oldIndex) => keyOf(entry) === key && !used.has(oldIndex)));
34
+ }
35
+ });
36
+ items.forEach((item, index) => {
37
+ if (indices[index] < 0 && keyOf(item) === null &&
38
+ index < previous.baseline.length && keyOf(previous.baseline[index]) === null) {
39
+ assign(index, index);
40
+ }
41
+ });
42
+ return indices;
43
+ };
44
+ const draftIndices = matchIndices(draft, previous.draft);
45
+ const sourceIndices = matchIndices(source, previous.source);
46
+ const incoming = source.map((item, index) => {
47
+ const oldIndex = sourceIndices[index];
48
+ const draftIndex = draftIndices.indexOf(oldIndex);
49
+ const value = XEUtils.clone(item, true);
50
+ if (oldIndex >= 0 && draftIndex >= 0) {
51
+ const base = previous.baseline[oldIndex];
52
+ const edited = draft[draftIndex];
53
+ // A local field edit wins a simultaneous parent change to that field.
54
+ new Set(Object.keys(base).concat(Object.keys(edited))).forEach(field => {
55
+ if (!XEUtils.isEqual(base[field], edited[field])) {
56
+ if (Object.prototype.hasOwnProperty.call(edited, field)) value[field] = XEUtils.clone(edited[field], true);
57
+ else delete value[field];
58
+ }
59
+ });
60
+ }
61
+ return { oldIndex, value };
62
+ });
63
+ const reordered = draftIndices.some((index, position) => index !== position);
64
+ let nextDraft = incoming.map(entry => entry.value);
65
+ if (reordered) {
66
+ const ordered = draftIndices.filter(index => index >= 0)
67
+ .map(index => incoming.find(entry => entry.oldIndex === index)).filter(Boolean);
68
+ const retained = new Set(ordered);
69
+ nextDraft = ordered.concat(incoming.filter(entry => !retained.has(entry))).map(entry => entry.value);
70
+ }
71
+ // Store draft references in source order so subsequent drag operations can
72
+ // still be matched even when the item does not declare a stable key.
73
+ return { source: source.slice(), baseline: XEUtils.clone(source, true),
74
+ draft: incoming.map(entry => entry.value), value: nextDraft };
75
+ }