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.
- package/lib/button.js +1 -1
- package/lib/icon.js +1 -1
- package/lib/index.js +1 -1
- package/lib/locale/format.js +1 -1
- package/lib/locale/index.js +1 -72
- package/lib/mixins/locale.js +1 -1
- package/lib/theme-chalk/button.css +1 -1
- package/lib/theme-chalk/icon.css +1 -1
- package/lib/theme-chalk/iconfont.1785242763644.ttf +0 -0
- package/lib/theme-chalk/iconfont.1785242763644.woff +0 -0
- package/lib/theme-chalk/iconfont.1785242763644.woff2 +0 -0
- package/lib/theme-chalk/index.css +1 -1
- package/lib/theme-chalk/u-table.css +1 -1
- package/lib/theme-chalk/ux-grid.css +1 -1
- package/lib/u-table-column.js +1 -1
- package/lib/u-table.js +1 -1
- package/lib/umy-ui.common.js +1 -1
- package/lib/utils/util.js +1 -1
- package/lib/ux-grid.js +1 -1
- package/lib/ux-table-column.js +1 -1
- package/package.json +4 -3
- package/packages/.DS_Store +0 -0
- package/packages/input/.DS_Store +0 -0
- package/packages/pagination/.DS_Store +0 -0
- package/packages/scrollbar/.DS_Store +0 -0
- package/packages/select/.DS_Store +0 -0
- package/packages/table/.DS_Store +0 -0
- package/packages/tag/.DS_Store +0 -0
- package/packages/tools/.DS_Store +0 -0
- package/packages/tools/locale/index.js +2 -48
- package/packages/tools/utils/.DS_Store +0 -0
- package/packages/tooltip/.DS_Store +0 -0
- package/packages/u-table/.DS_Store +0 -0
- package/packages/ux-grid/.DS_Store +0 -0
- package/packages/ux-grid/mixins/index.js +133 -25
- package/packages/ux-grid/src/dialog-draft.js +75 -0
- package/packages/ux-grid/src/element-renderer.js +784 -0
- package/packages/ux-grid/src/grid-height.js +65 -0
- package/packages/ux-grid/src/grid-kernel.js +14 -0
- package/packages/ux-grid/src/setup.js +42 -0
- package/packages/ux-grid/src/ux-grid.vue +215 -57
- package/packages/ux-grid/test/browser-acceptance.cjs +192 -0
- package/packages/ux-grid/test/browser-baseline-loader.cjs +10 -0
- package/packages/ux-grid/test/browser-entry.js +242 -0
- package/packages/ux-grid/test/browser-renderer-contracts.cjs +246 -0
- package/packages/ux-grid/test/browser-renderer-entry.js +129 -0
- package/packages/ux-grid/test/browser-resize-contracts.cjs +150 -0
- package/packages/ux-grid/test/compatibility.cjs +176 -0
- package/packages/ux-grid/test/contracts.cjs +281 -0
- package/packages/ux-grid/test/delivery.cjs +103 -0
- package/packages/ux-grid/test/integration.cjs +132 -0
- package/packages/ux-grid/test/real-kernel-contracts.cjs +335 -0
- package/packages/ux-grid/test/real-kernel-events.cjs +233 -0
- package/packages/ux-grid/test/renderer-boundaries.cjs +165 -0
- package/packages/ux-grid/test/ui-components.cjs +103 -0
- package/tools/locale/format.js +1 -1
- package/tools/locale/index.js +1 -7
- package/tools/mixins/locale.js +1 -1
- 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="
|
|
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 "
|
|
160
|
+
import VxeGrid from "./grid-kernel";
|
|
154
161
|
import uxGridMixin from "../mixins";
|
|
155
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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" ?
|
|
435
|
+
typeof val === "function" ? `[fn:${referenceId(val)}]` : val;
|
|
328
436
|
const describe = (vnode) => {
|
|
329
|
-
if (!vnode
|
|
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
|
|
332
|
-
|
|
333
|
-
).
|
|
334
|
-
|
|
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 (
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
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
|
-
|
|
379
|
-
|
|
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
|
},
|