umy-ui-table 1.2.4 → 1.2.5

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 (59) 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 +784 -0
  38. package/packages/ux-grid/src/grid-height.js +65 -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-renderer-contracts.cjs +246 -0
  46. package/packages/ux-grid/test/browser-renderer-entry.js +129 -0
  47. package/packages/ux-grid/test/browser-resize-contracts.cjs +150 -0
  48. package/packages/ux-grid/test/compatibility.cjs +176 -0
  49. package/packages/ux-grid/test/contracts.cjs +281 -0
  50. package/packages/ux-grid/test/delivery.cjs +103 -0
  51. package/packages/ux-grid/test/integration.cjs +132 -0
  52. package/packages/ux-grid/test/real-kernel-contracts.cjs +335 -0
  53. package/packages/ux-grid/test/real-kernel-events.cjs +233 -0
  54. package/packages/ux-grid/test/renderer-boundaries.cjs +165 -0
  55. package/packages/ux-grid/test/ui-components.cjs +103 -0
  56. package/tools/locale/format.js +1 -1
  57. package/tools/locale/index.js +1 -7
  58. package/tools/mixins/locale.js +1 -1
  59. package/tools/utils/util.js +1 -1
@@ -0,0 +1,65 @@
1
+ import ResizeObserver from "resize-observer-polyfill";
2
+
3
+ export function hasGridHeight(value) {
4
+ return value !== undefined && value !== null && value !== "";
5
+ }
6
+
7
+ // Measure the configured limit in the root's actual grid/flex position. Size
8
+ // containment excludes table content from intrinsic sizing during measurement.
9
+ export function resolveGridHeight(value, root, isMax = false) {
10
+ if (!hasGridHeight(value)) return null;
11
+ if (typeof value === "number") return Number.isFinite(value) ? Math.max(0, value) : null;
12
+ const css = String(value).trim();
13
+ if (/^\d+(?:\.\d+)?(?:px)?$/i.test(css)) return Number.parseFloat(css);
14
+ if (!root || !root.parentElement || !root.getClientRects().length) return null;
15
+ const view = root.ownerDocument.defaultView;
16
+ const width = view.getComputedStyle(root).width;
17
+ const saved = root.style.cssText;
18
+ try {
19
+ const style = root.style;
20
+ style.removeProperty("height");
21
+ style.setProperty("height", css === "auto" ? "100%" : css, "important");
22
+ if (!style.height) return null;
23
+ style.setProperty("width", width, "important");
24
+ style.setProperty("min-height", "0", "important");
25
+ style.setProperty("max-height", isMax ? (css === "auto" ? "100%" : css) : "none", "important");
26
+ // A configured ceiling is not the space assigned by flex. Match numeric
27
+ // maxHeight semantics; restore the user's real flex rules in finally.
28
+ if (isMax) style.setProperty("flex", "none", "important");
29
+ style.setProperty("contain", "size", "important");
30
+ style.setProperty("overflow", "hidden", "important");
31
+ const size = Number.parseFloat(view.getComputedStyle(root).height);
32
+ if (size === 0 && (css === "auto" || css.indexOf("%") !== -1)) return null;
33
+ return Number.isFinite(size) && size >= 0 ? size : null;
34
+ } finally {
35
+ root.style.cssText = saved;
36
+ }
37
+ }
38
+
39
+ export function getGridHeightInset(root) {
40
+ if (!root) return 0;
41
+ const style = root.ownerDocument.defaultView.getComputedStyle(root);
42
+ return style.boxSizing === "border-box"
43
+ ? ["paddingTop", "paddingBottom", "borderTopWidth", "borderBottomWidth"]
44
+ .reduce((sum, key) => sum + (Number.parseFloat(style[key]) || 0), 0)
45
+ : 0;
46
+ }
47
+
48
+ export function observeGridHeight(vm) {
49
+ const root = vm.$el;
50
+ if (!root || !root.parentElement) return () => {};
51
+ const observer = new ResizeObserver(() => vm.scheduleHeight());
52
+ observer.observe(root.parentElement);
53
+ observer.observe(root);
54
+ // Pagination can appear/disappear after mount; updated() reconnects when its
55
+ // element identity changes. Root observation also covers hidden -> visible.
56
+ const pager = vm.$refs.myPagination;
57
+ if (pager) observer.observe(pager);
58
+ const view = root.ownerDocument.defaultView;
59
+ const onResize = () => vm.scheduleHeight();
60
+ if (view) view.addEventListener("resize", onResize);
61
+ return () => {
62
+ observer.disconnect();
63
+ if (view) view.removeEventListener("resize", onResize);
64
+ };
65
+ }
@@ -0,0 +1,14 @@
1
+ import VxeGrid from "vxe-table/lib/grid";
2
+
3
+ // The upstream columns watcher queues loadColumn in nextTick. A wrapper can
4
+ // be destroyed before that callback runs, after its table refs are released.
5
+ // Keep this cancellation local to UxGrid; active calls retain kernel semantics.
6
+ export default {
7
+ extends: VxeGrid,
8
+ methods: {
9
+ loadColumn(...args) {
10
+ if (this._isDestroyed || this._isBeingDestroyed) return Promise.resolve();
11
+ return VxeGrid.methods.loadColumn.apply(this, args);
12
+ },
13
+ },
14
+ };
@@ -0,0 +1,42 @@
1
+ import { VxeUI } from "vxe-table/lib/ui";
2
+ import zhCN from "vxe-table/lib/locale/lang/zh-CN";
3
+ import XEUtils from "xe-utils";
4
+
5
+ // Core setConfig deep-merges arrays by index. Restore pre-existing arrays
6
+ // exactly after merging defaults (including empty arrays and nested arrays).
7
+ function restoreConfigArrays(target, source) {
8
+ Object.keys(source).forEach(key => {
9
+ const value = source[key];
10
+ if (Array.isArray(value)) {
11
+ target[key] = XEUtils.clone(value, true);
12
+ } else if (XEUtils.isPlainObject(value) && target[key]) {
13
+ restoreConfigArrays(target[key], value);
14
+ }
15
+ });
16
+ }
17
+
18
+ // Register only missing UI dependencies. Importing PC UI initializes shared
19
+ // defaults, so preserve existing application config and icon customizations.
20
+ if (!VxeUI.getComponent("VxeTooltip") || !VxeUI.getComponent("VxeLoading")) {
21
+ const config = XEUtils.clone(VxeUI.getConfig(), true);
22
+ const icons = Object.assign({}, VxeUI.getIcon());
23
+ try {
24
+ if (!VxeUI.getComponent("VxeTooltip")) {
25
+ VxeUI.component(require("vxe-pc-ui/lib/tooltip/src/tooltip").default);
26
+ }
27
+ if (!VxeUI.getComponent("VxeLoading")) {
28
+ VxeUI.component(require("vxe-pc-ui/lib/loading/src/loading").default);
29
+ }
30
+ } finally {
31
+ VxeUI.setConfig(config);
32
+ restoreConfigArrays(VxeUI.getConfig(), config);
33
+ VxeUI.setIcon(icons);
34
+ }
35
+ }
36
+
37
+ // Initialize fresh consumers without replacing an application's chosen language
38
+ // or translator. An already registered Chinese dictionary is retained as well.
39
+ if (!VxeUI.getLanguage() && !VxeUI.getConfig().i18n) {
40
+ if (!VxeUI.hasLanguage("zh-CN")) VxeUI.setI18n("zh-CN", zhCN);
41
+ VxeUI.setLanguage("zh-CN");
42
+ }
@@ -34,18 +34,20 @@
34
34
  :expand-config="expandConfig"
35
35
  :keyboard-config="keyboardConfig"
36
36
  :mouse-config="mouseConfig"
37
+ :menu-config="{ enabled: true, header: { options: [] }, body: { options: [] }, footer: { options: [] } }"
37
38
  :checkbox-config="checkboxConfig"
38
39
  :tree-config="treeConfig"
39
40
  :sort-config="sortConfig"
40
41
  :show-header="showHeader"
41
42
  :show-overflow="showOverflow"
43
+ :tooltip-config="{}"
42
44
  :footer-method="footerMethod"
43
45
  :show-header-overflow="showHeaderOverflow"
44
46
  :show-footer-overflow="showFooterOverflow"
45
47
  :highlight-current-row="highlightCurrentRow"
46
48
  :highlight-hover-row="highlightHoverRow"
47
49
  :row-class-name="rowClassName"
48
- :cell-class-name="cellClassName"
50
+ :cell-class-name="renderCellClassName"
49
51
  :header-row-class-name="headerRowClassName"
50
52
  :header-cell-class-name="headerCellClassName"
51
53
  :header-row-style="headerRowStyle"
@@ -70,6 +72,7 @@
70
72
  @edit-closed="editClosed"
71
73
  @edit-actived="editActived"
72
74
  @edit-disabled="editDisabled"
75
+ @cell-selected="editCurrentlyActive"
73
76
  @toggle-tree-expand="toggleTreeExpandEv"
74
77
  @toggle-row-expand="expChang"
75
78
  @keydown="keydown"
@@ -77,6 +80,9 @@
77
80
  @init-rendered="initRendered"
78
81
  @data-rendered="dataRendered"
79
82
  >
83
+ <template v-for="(_, name) in forwardedScopedSlots()" v-slot:[name]="params">
84
+ <slot :name="name" v-bind="params" />
85
+ </template>
80
86
  <!--无数据布局-->
81
87
  <template slot="empty">
82
88
  <slot name="empty">{{ emptyText }}</slot>
@@ -146,13 +152,15 @@ import draggable from "vuedraggable";
146
152
  import ElPagination from "../../pagination";
147
153
  import ElCheckbox from "../../checkbox";
148
154
  import ElButton from "../../button";
155
+ import "./element-renderer";
149
156
  // 直接用 vxe-table@3.22.9 的 VxeGrid 作内核(替代原 umy-table 内置的 elx-grid)
150
157
  // 注意:VxeGrid 3.x 不渲染默认插槽(renderTable 仅透传 scopedSlots,不渲染 children),
151
158
  // 所以槽位式 <ux-table-column> 不会被其内部表格收集;这里在组件内解析这些槽位列 vnode,
152
159
  // 转成 columns 配置后经 :columns 交给 VxeGrid,从而兼容原有的 <ux-table-column> 写法
153
- import VxeGrid from "vxe-table/lib/grid";
160
+ import VxeGrid from "./grid-kernel";
154
161
  import uxGridMixin from "../mixins";
155
- import { parseHeight, isArrayFn } from "../../utils/common";
162
+ import { isArrayFn } from "../../utils/common";
163
+ import { hasGridHeight, resolveGridHeight, getGridHeightInset, observeGridHeight } from "./grid-height";
156
164
 
157
165
  export default {
158
166
  name: "UxGrid",
@@ -169,6 +177,7 @@ export default {
169
177
  newHeight: null, // 表格高度
170
178
  newMaxHeight: null, // 表格最大高度
171
179
  slotColumns: [], // 由槽位式 <ux-table-column> 解析出的列配置(无 columns prop 时使用)
180
+ slotFormatterRevision: 0,
172
181
  };
173
182
  },
174
183
  computed: {
@@ -187,7 +196,9 @@ export default {
187
196
  ) {
188
197
  return Object.assign({}, this.scrollY, { enabled: false });
189
198
  }
190
- return this.scrollY;
199
+ return Object.assign({}, this.scrollY, {
200
+ enabled: this.scrollY && this.scrollY.enabled !== undefined ? this.scrollY.enabled : true,
201
+ });
191
202
  },
192
203
  scrollXConfig() {
193
204
  const propsData = this.$options.propsData || {};
@@ -197,45 +208,30 @@ export default {
197
208
  ) {
198
209
  return Object.assign({}, this.scrollX, { enabled: false });
199
210
  }
200
- return this.scrollX;
211
+ return Object.assign({}, this.scrollX, {
212
+ enabled: this.scrollX && this.scrollX.enabled !== undefined ? this.scrollX.enabled : true,
213
+ });
201
214
  },
202
215
  // vxe3 新接口:优先使用 virtualYConfig/virtualXConfig,不存在时回退到兼容 scrollY/scrollX
203
216
  computedVirtualYConfig() {
204
217
  if (this.virtualYConfig) return this.virtualYConfig;
205
- const propsData = this.$options.propsData || {};
206
- if (
207
- this.spanMethod &&
208
- !(propsData.virtualYConfig && propsData.virtualYConfig.enabled !== undefined)
209
- ) {
210
- return Object.assign({}, this.scrollY, { enabled: false });
211
- }
212
- return this.scrollY;
218
+ return this.scrollYConfig;
213
219
  },
214
220
  computedVirtualXConfig() {
215
221
  if (this.virtualXConfig) return this.virtualXConfig;
216
- const propsData = this.$options.propsData || {};
217
- if (
218
- this.spanMethod &&
219
- !(propsData.virtualXConfig && propsData.virtualXConfig.enabled !== undefined)
220
- ) {
221
- return Object.assign({}, this.scrollX, { enabled: false });
222
- }
223
- return this.scrollX;
222
+ return this.scrollXConfig;
224
223
  },
225
224
  plTableHeight() {
226
- if (this.height) {
227
- return {
228
- height: this.height + "px",
229
- };
230
- } else if (this.maxHeight) {
231
- const maxHeight = parseHeight(this.maxHeight);
232
- if (typeof maxHeight === "number") {
233
- return {
234
- "max-height": this.maxHeight + "px",
235
- };
236
- }
225
+ const property = hasGridHeight(this.height) ? "height" : "max-height";
226
+ let value = property === "height" ? this.height : this.maxHeight;
227
+ if (!hasGridHeight(value)) return {};
228
+ if (typeof value === "number") {
229
+ return Number.isFinite(value) ? { [property]: Math.max(0, value) + "px" } : {};
237
230
  }
238
- return {};
231
+ value = String(value).trim();
232
+ // Keep the original CSS basis for flex/grid. Only the kernel receives
233
+ // the measured pixels; writing them here would redistribute flex space.
234
+ return { [property]: value === "auto" ? "100%" : /^\d+(?:\.\d+)?$/.test(value) ? value + "px" : value };
239
235
  },
240
236
  },
241
237
  watch: {
@@ -257,14 +253,23 @@ export default {
257
253
  immediate: true,
258
254
  handler() {
259
255
  this.setHeight();
256
+ this.scheduleHeight();
260
257
  },
261
258
  },
262
259
  maxHeight: {
263
260
  immediate: true,
264
261
  handler() {
265
262
  this.setHeight();
263
+ this.scheduleHeight();
266
264
  },
267
265
  },
266
+ paginationShow: "scheduleHeight",
267
+ layout: "scheduleHeight",
268
+ pagerCount: "scheduleHeight",
269
+ pageSizes: "scheduleHeight",
270
+ total: "scheduleHeight",
271
+ newPageSize: "scheduleHeight",
272
+ newcurrentPage: "scheduleHeight",
268
273
  },
269
274
  created() {
270
275
  this.newPageSize = this.pageSize;
@@ -275,32 +280,114 @@ export default {
275
280
  updated() {
276
281
  // 处理 <ux-table-column v-if> 动态增减列的场景
277
282
  this.syncSlotColumns();
283
+ this.connectHeightObserver();
278
284
  },
279
285
  mounted() {
280
286
  this.$ready = true;
287
+ this.connectHeightObserver();
288
+ this.setHeight();
281
289
  // VxeGrid 原生支持 columns prop(mounted 自动 loadColumn + watch 响应变化),无需手动 loadColumn
282
290
  },
291
+ activated() {
292
+ this._heightInactive = false;
293
+ this._heightLayoutSignature = null;
294
+ this.connectHeightObserver();
295
+ this.scheduleHeight();
296
+ },
297
+ deactivated() {
298
+ this._heightInactive = true;
299
+ this.disconnectHeightObserver();
300
+ },
301
+ beforeDestroy() {
302
+ this.disconnectHeightObserver();
303
+ },
283
304
  methods: {
305
+ renderCellClassName(params) {
306
+ // Every visible cell tracks this revision, including formatter cache hits.
307
+ this.slotFormatterRevision;
308
+ return typeof this.cellClassName === "function" ? this.cellClassName(params) : this.cellClassName;
309
+ },
310
+ forwardedScopedSlots() {
311
+ const slots = {};
312
+ Object.keys(this.$scopedSlots).forEach((name) => {
313
+ if (name !== "default" && name !== "empty") slots[name] = this.$scopedSlots[name];
314
+ });
315
+ return slots;
316
+ },
284
317
  // 解析默认插槽里的 <ux-table-column> vnode,转成 VxeGrid 的 columns 配置
285
318
  syncSlotColumns() {
286
319
  // columns prop 优先;仅在未传 columns 时解析槽位列
287
320
  if (this.columns && this.columns.length) return;
288
321
  try {
289
322
  const slotVnodes = (this.$slots.default || []).filter(
290
- (vnode) => vnode && vnode.componentOptions
323
+ (vnode) => this.isColumnVNode(vnode)
291
324
  );
292
- // 用稳定签名比对,避免仅插槽函数引用变化时反复赋值导致渲染循环
325
+ // 比较父组件提供的 vnode;自身更新不会改变这些引用,避免渲染循环。
293
326
  const sig = this.columnsSig(slotVnodes);
294
327
  if (sig === this._slotColumnsSig) return;
295
328
  this._slotColumnsSig = sig;
296
- this.slotColumns = slotVnodes.map((vnode) => this.vnodeToColumn(vnode));
329
+ const columns = slotVnodes.map((vnode) => this.vnodeToColumn(vnode));
330
+ // Only render callbacks may change without loading columns again. Stable
331
+ // proxies retain VXE ColumnInfo, sort, resized width and edit identity.
332
+ const structure = this.columnsSig(slotVnodes, true);
333
+ if (structure === this._slotColumnsStructure && this._slotRenderSources) {
334
+ let index = 0;
335
+ let formatterChanged = false;
336
+ const update = (items) => items.forEach((column) => {
337
+ const source = this._slotRenderSources[index++];
338
+ if (source.column.formatter !== column.formatter) formatterChanged = true;
339
+ source.column = column;
340
+ source.revision.value++;
341
+ if (column.children) update(column.children);
342
+ });
343
+ update(columns);
344
+ const grid = this.$refs && this.$refs.singleTable;
345
+ if (formatterChanged && grid && grid.clearFormatterCache) {
346
+ grid.clearFormatterCache();
347
+ // Refresh visible cell rendering, without sorting/filtering all data.
348
+ this.slotFormatterRevision++;
349
+ }
350
+ } else {
351
+ this._slotColumnsStructure = structure;
352
+ this._slotRenderSources = [];
353
+ const wrap = (items) => items.map((column) => {
354
+ const revision = Vue.observable ? Vue.observable({ value: 0 }) : { value: 0 };
355
+ const source = { column, revision };
356
+ this._slotRenderSources.push(source);
357
+ const result = Object.assign({}, column);
358
+ if (typeof column.formatter === "function") {
359
+ result.formatter = function (...args) {
360
+ source.revision.value;
361
+ return source.column.formatter.apply(this, args);
362
+ };
363
+ }
364
+ if (column.slots) {
365
+ result.slots = {};
366
+ Object.keys(column.slots).forEach((name) => {
367
+ const value = column.slots[name];
368
+ result.slots[name] = typeof value === "function" ? (...args) => {
369
+ source.revision.value;
370
+ return source.column.slots[name](...args);
371
+ } : value;
372
+ });
373
+ }
374
+ if (column.children) result.children = wrap(column.children);
375
+ return result;
376
+ });
377
+ this.slotColumns = wrap(columns);
378
+ }
297
379
  } catch (e) {
298
- // 解析异常时保持现状,避免渲染循环
380
+ console.error("[UxGrid] 无法解析槽位列", e);
299
381
  }
300
382
  },
383
+ isColumnVNode(vnode) {
384
+ const options = vnode && vnode.componentOptions;
385
+ const name = options && options.Ctor && options.Ctor.options.name;
386
+ return ["UxTableColumn", "VxeColumn", "VxeColgroup"].indexOf(name) > -1;
387
+ },
301
388
  // 把单个 <ux-table-column> vnode 转成列配置(支持嵌套分组列)
302
389
  vnodeToColumn(vnode) {
303
- if (!vnode || !vnode.componentOptions) return null;
390
+ if (!this.isColumnVNode(vnode)) return null;
304
391
  const { propsData = {}, children } = vnode.componentOptions;
305
392
  const scopedSlots = (vnode.data && vnode.data.scopedSlots) || {};
306
393
  const column = Object.assign({}, propsData);
@@ -313,25 +400,48 @@ export default {
313
400
  }
314
401
  if (children && children.length) {
315
402
  const nested = [];
403
+ const normalSlots = {};
316
404
  children.forEach((child) => {
317
405
  const sub = this.vnodeToColumn(child);
318
406
  if (sub) nested.push(sub);
407
+ else if (!child.isComment && !(child.text && !child.text.trim())) {
408
+ const name = (child.data && child.data.slot) || "default";
409
+ const nodes = normalSlots[name] || (normalSlots[name] = []);
410
+ if (child.tag === "template") nodes.push(...(child.children || []));
411
+ else nodes.push(child);
412
+ }
319
413
  });
320
414
  if (nested.length) column.children = nested;
415
+ Object.keys(normalSlots).forEach((name) => {
416
+ if (!column.slots) column.slots = {};
417
+ if (!column.slots[name]) column.slots[name] = () => normalSlots[name];
418
+ });
321
419
  }
322
420
  return column;
323
421
  },
324
- // 生成槽位列的稳定签名(忽略函数引用差异,按值比较)
325
- columnsSig(vnodes) {
422
+ // 保留函数和普通 vnode 身份,使动态 slot/formatter 和 v-for 闭包及时更新。
423
+ columnsSig(vnodes, structureOnly) {
424
+ if (!this._columnReferenceIds) {
425
+ this._columnReferenceIds = new WeakMap();
426
+ this._columnReferenceSeq = 0;
427
+ }
428
+ const referenceId = (value) => {
429
+ if (!this._columnReferenceIds.has(value)) {
430
+ this._columnReferenceIds.set(value, ++this._columnReferenceSeq);
431
+ }
432
+ return this._columnReferenceIds.get(value);
433
+ };
326
434
  const fnReplacer = (key, val) =>
327
- typeof val === "function" ? "[fn]" : val;
435
+ typeof val === "function" ? `[fn:${referenceId(val)}]` : val;
328
436
  const describe = (vnode) => {
329
- if (!vnode || !vnode.componentOptions) return "";
437
+ if (!vnode) return "";
438
+ if (!this.isColumnVNode(vnode)) return structureOnly ? `slot:${(vnode.data && vnode.data.slot) || "default"}` : `node:${referenceId(vnode)}`;
330
439
  const { propsData = {}, children } = vnode.componentOptions;
331
- const slotKeys = Object.keys(
332
- (vnode.data && vnode.data.scopedSlots) || {}
333
- ).join(",");
334
- let sig = JSON.stringify(propsData, fnReplacer) + "{" + slotKeys + "}";
440
+ const slots = (vnode.data && vnode.data.scopedSlots) || {};
441
+ const signatureProps = Object.assign({}, propsData);
442
+ if (structureOnly && typeof signatureProps.formatter === "function") signatureProps.formatter = "[formatter]";
443
+ const signatureSlots = structureOnly ? Object.keys(slots).filter((key) => key.charAt(0) !== "$").sort() : slots;
444
+ let sig = JSON.stringify([vnode.key, signatureProps, signatureSlots], fnReplacer);
335
445
  if (children && children.length) {
336
446
  const childSigs = [];
337
447
  children.forEach((child) => {
@@ -363,21 +473,69 @@ export default {
363
473
  arr[index1] = arr.splice(index2, 1, arr[index1])[0];
364
474
  return arr;
365
475
  },
476
+ // Measure after the pagination DOM has applied its new layout. Coalesce
477
+ // related prop changes and never keep retrying a not-yet-mounted instance.
478
+ scheduleHeight() {
479
+ if (!this.$ready || this._heightInactive || this._heightUpdatePending || this._isDestroyed || this._isBeingDestroyed) return;
480
+ this._heightUpdatePending = true;
481
+ this.$nextTick(() => {
482
+ this._heightUpdatePending = false;
483
+ this.setHeight();
484
+ });
485
+ },
486
+ disconnectHeightObserver() {
487
+ if (this._stopHeightObserver) this._stopHeightObserver();
488
+ this._stopHeightObserver = null;
489
+ this._heightObservedParent = null;
490
+ this._heightObservedPager = null;
491
+ },
492
+ connectHeightObserver() {
493
+ if (!this.$ready || this._heightInactive || this._isDestroyed || this._isBeingDestroyed) return;
494
+ if (!hasGridHeight(this.height) && !hasGridHeight(this.maxHeight)) {
495
+ this.disconnectHeightObserver();
496
+ return;
497
+ }
498
+ const parent = this.$el && this.$el.parentElement;
499
+ const pager = this.$refs.myPagination;
500
+ if (this._stopHeightObserver && this._heightObservedParent === parent && this._heightObservedPager === pager) return;
501
+ this.disconnectHeightObserver();
502
+ this._heightObservedParent = parent;
503
+ this._heightObservedPager = pager;
504
+ this._stopHeightObserver = observeGridHeight(this);
505
+ this.scheduleHeight();
506
+ },
366
507
  // 设置表格高度
367
508
  setHeight() {
368
- if (!this.$ready && this.paginationShow)
369
- return Vue.nextTick(() => this.setHeight());
370
- const { myPagination } = this.$refs;
371
- if (this.height) {
372
- this.newHeight =
373
- parseHeight(this.height) -
374
- (myPagination ? myPagination.offsetHeight : 0);
509
+ if (this._heightInactive || this._isDestroyed || this._isBeingDestroyed) return;
510
+ const myPagination = this.paginationShow && this.$refs && this.$refs.myPagination;
511
+ const paginationHeight = myPagination ? myPagination.offsetHeight : 0;
512
+ const total = resolveGridHeight(hasGridHeight(this.height) ? this.height : this.maxHeight, this.$el, !hasGridHeight(this.height));
513
+ const tableHeight = total === null ? null : Math.max(0, total - paginationHeight - getGridHeightInset(this.$el));
514
+ if (hasGridHeight(this.height)) {
515
+ this.newHeight = tableHeight;
375
516
  this.newMaxHeight = null;
376
- } else if (this.maxHeight) {
377
- this.newMaxHeight =
378
- parseHeight(this.maxHeight) -
379
- (myPagination ? myPagination.offsetHeight : 0);
517
+ } else if (hasGridHeight(this.maxHeight)) {
518
+ this.newMaxHeight = tableHeight;
519
+ this.newHeight = null;
520
+ } else {
380
521
  this.newHeight = null;
522
+ this.newMaxHeight = null;
523
+ this._heightLayoutSignature = null;
524
+ return;
525
+ }
526
+ const root = this.$el;
527
+ const signature = root ? root.clientWidth + ":" + !!root.getClientRects().length : null;
528
+ if (signature !== this._heightLayoutSignature) {
529
+ this._heightLayoutSignature = signature;
530
+ // Reopening a hidden/kept-alive container may retain the same height
531
+ // props. Refresh widths through the public API, respecting opt-out.
532
+ if (root && root.getClientRects().length && this.widthResize) {
533
+ this.$nextTick(() => {
534
+ if (this._heightInactive || this._isDestroyed || this._isBeingDestroyed) return;
535
+ const table = this.$refs.singleTable;
536
+ if (table && table.recalculate) table.recalculate();
537
+ });
538
+ }
381
539
  }
382
540
  },
383
541
  },