umy-ui-table 1.2.3 → 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 +136 -29
  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 +225 -44
  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
+ }
@@ -21,7 +21,8 @@
21
21
  :border="beautifyTable ? false : border"
22
22
  :scroll-y="scrollYConfig"
23
23
  :scroll-x="scrollXConfig"
24
- context-menu
24
+ :virtual-y-config="computedVirtualYConfig"
25
+ :virtual-x-config="computedVirtualXConfig"
25
26
  :stripe="stripe"
26
27
  :row-key="rowKey"
27
28
  :column-key="columnKey"
@@ -33,18 +34,20 @@
33
34
  :expand-config="expandConfig"
34
35
  :keyboard-config="keyboardConfig"
35
36
  :mouse-config="mouseConfig"
37
+ :menu-config="{ enabled: true, header: { options: [] }, body: { options: [] }, footer: { options: [] } }"
36
38
  :checkbox-config="checkboxConfig"
37
39
  :tree-config="treeConfig"
38
40
  :sort-config="sortConfig"
39
41
  :show-header="showHeader"
40
42
  :show-overflow="showOverflow"
43
+ :tooltip-config="{}"
41
44
  :footer-method="footerMethod"
42
45
  :show-header-overflow="showHeaderOverflow"
43
46
  :show-footer-overflow="showFooterOverflow"
44
47
  :highlight-current-row="highlightCurrentRow"
45
- :highlight-hover-row="highlightCurrentRow"
48
+ :highlight-hover-row="highlightHoverRow"
46
49
  :row-class-name="rowClassName"
47
- :cell-class-name="cellClassName"
50
+ :cell-class-name="renderCellClassName"
48
51
  :header-row-class-name="headerRowClassName"
49
52
  :header-cell-class-name="headerCellClassName"
50
53
  :header-row-style="headerRowStyle"
@@ -69,14 +72,17 @@
69
72
  @edit-closed="editClosed"
70
73
  @edit-actived="editActived"
71
74
  @edit-disabled="editDisabled"
75
+ @cell-selected="editCurrentlyActive"
72
76
  @toggle-tree-expand="toggleTreeExpandEv"
73
77
  @toggle-row-expand="expChang"
74
78
  @keydown="keydown"
75
- @edit-currently-active="editCurrentlyActive"
76
79
  @scroll="tableBodyScroll"
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,22 +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
+ });
214
+ },
215
+ // vxe3 新接口:优先使用 virtualYConfig/virtualXConfig,不存在时回退到兼容 scrollY/scrollX
216
+ computedVirtualYConfig() {
217
+ if (this.virtualYConfig) return this.virtualYConfig;
218
+ return this.scrollYConfig;
219
+ },
220
+ computedVirtualXConfig() {
221
+ if (this.virtualXConfig) return this.virtualXConfig;
222
+ return this.scrollXConfig;
201
223
  },
202
224
  plTableHeight() {
203
- if (this.height) {
204
- return {
205
- height: this.height + "px",
206
- };
207
- } else if (this.maxHeight) {
208
- const maxHeight = parseHeight(this.maxHeight);
209
- if (typeof maxHeight === "number") {
210
- return {
211
- "max-height": this.maxHeight + "px",
212
- };
213
- }
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" } : {};
214
230
  }
215
- 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 };
216
235
  },
217
236
  },
218
237
  watch: {
@@ -234,14 +253,23 @@ export default {
234
253
  immediate: true,
235
254
  handler() {
236
255
  this.setHeight();
256
+ this.scheduleHeight();
237
257
  },
238
258
  },
239
259
  maxHeight: {
240
260
  immediate: true,
241
261
  handler() {
242
262
  this.setHeight();
263
+ this.scheduleHeight();
243
264
  },
244
265
  },
266
+ paginationShow: "scheduleHeight",
267
+ layout: "scheduleHeight",
268
+ pagerCount: "scheduleHeight",
269
+ pageSizes: "scheduleHeight",
270
+ total: "scheduleHeight",
271
+ newPageSize: "scheduleHeight",
272
+ newcurrentPage: "scheduleHeight",
245
273
  },
246
274
  created() {
247
275
  this.newPageSize = this.pageSize;
@@ -252,32 +280,114 @@ export default {
252
280
  updated() {
253
281
  // 处理 <ux-table-column v-if> 动态增减列的场景
254
282
  this.syncSlotColumns();
283
+ this.connectHeightObserver();
255
284
  },
256
285
  mounted() {
257
286
  this.$ready = true;
287
+ this.connectHeightObserver();
288
+ this.setHeight();
258
289
  // VxeGrid 原生支持 columns prop(mounted 自动 loadColumn + watch 响应变化),无需手动 loadColumn
259
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
+ },
260
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
+ },
261
317
  // 解析默认插槽里的 <ux-table-column> vnode,转成 VxeGrid 的 columns 配置
262
318
  syncSlotColumns() {
263
319
  // columns prop 优先;仅在未传 columns 时解析槽位列
264
320
  if (this.columns && this.columns.length) return;
265
321
  try {
266
322
  const slotVnodes = (this.$slots.default || []).filter(
267
- (vnode) => vnode && vnode.componentOptions
323
+ (vnode) => this.isColumnVNode(vnode)
268
324
  );
269
- // 用稳定签名比对,避免仅插槽函数引用变化时反复赋值导致渲染循环
325
+ // 比较父组件提供的 vnode;自身更新不会改变这些引用,避免渲染循环。
270
326
  const sig = this.columnsSig(slotVnodes);
271
327
  if (sig === this._slotColumnsSig) return;
272
328
  this._slotColumnsSig = sig;
273
- 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
+ }
274
379
  } catch (e) {
275
- // 解析异常时保持现状,避免渲染循环
380
+ console.error("[UxGrid] 无法解析槽位列", e);
276
381
  }
277
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
+ },
278
388
  // 把单个 <ux-table-column> vnode 转成列配置(支持嵌套分组列)
279
389
  vnodeToColumn(vnode) {
280
- if (!vnode || !vnode.componentOptions) return null;
390
+ if (!this.isColumnVNode(vnode)) return null;
281
391
  const { propsData = {}, children } = vnode.componentOptions;
282
392
  const scopedSlots = (vnode.data && vnode.data.scopedSlots) || {};
283
393
  const column = Object.assign({}, propsData);
@@ -290,25 +400,48 @@ export default {
290
400
  }
291
401
  if (children && children.length) {
292
402
  const nested = [];
403
+ const normalSlots = {};
293
404
  children.forEach((child) => {
294
405
  const sub = this.vnodeToColumn(child);
295
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
+ }
296
413
  });
297
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
+ });
298
419
  }
299
420
  return column;
300
421
  },
301
- // 生成槽位列的稳定签名(忽略函数引用差异,按值比较)
302
- 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
+ };
303
434
  const fnReplacer = (key, val) =>
304
- typeof val === "function" ? "[fn]" : val;
435
+ typeof val === "function" ? `[fn:${referenceId(val)}]` : val;
305
436
  const describe = (vnode) => {
306
- 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)}`;
307
439
  const { propsData = {}, children } = vnode.componentOptions;
308
- const slotKeys = Object.keys(
309
- (vnode.data && vnode.data.scopedSlots) || {}
310
- ).join(",");
311
- 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);
312
445
  if (children && children.length) {
313
446
  const childSigs = [];
314
447
  children.forEach((child) => {
@@ -340,21 +473,69 @@ export default {
340
473
  arr[index1] = arr.splice(index2, 1, arr[index1])[0];
341
474
  return arr;
342
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
+ },
343
507
  // 设置表格高度
344
508
  setHeight() {
345
- if (!this.$ready && this.paginationShow)
346
- return Vue.nextTick(() => this.setHeight());
347
- const { myPagination } = this.$refs;
348
- if (this.height) {
349
- this.newHeight =
350
- parseHeight(this.height) -
351
- (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;
352
516
  this.newMaxHeight = null;
353
- } else if (this.maxHeight) {
354
- this.newMaxHeight =
355
- parseHeight(this.maxHeight) -
356
- (myPagination ? myPagination.offsetHeight : 0);
517
+ } else if (hasGridHeight(this.maxHeight)) {
518
+ this.newMaxHeight = tableHeight;
519
+ this.newHeight = null;
520
+ } else {
357
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
+ }
358
539
  }
359
540
  },
360
541
  },