20260820173056

This commit is contained in:
oneao committed 2026-08-20 17:30:56 +08:00
1 parent 8e75c7989a
commit 68ac5db038
24 files changed
+975 -6035

No files matched your search

@@ -55,22 +55,42 @@ const tableTheme = computed(() => props.theme ?? (appStore.darkMode ? 'dark' : '
// Tab 面板从隐藏恢复时,等到容器拥有有效尺寸再刷新虚拟滚动布局。
// rAF 将同一帧内的多次 ResizeObserver 通知合并,避免重复重排。
let refreshRafId = 0
function refreshLayout() {
function refreshLayout(xOnly = false) {
if (refreshRafId) cancelAnimationFrame(refreshRafId)
refreshRafId = requestAnimationFrame(async () => {
refreshRafId = 0
await nextTick()
tableRef.value?.initVirtualScroll?.()
// 高度未变、仅宽度变化时只重算 X 方向虚拟滚动,省掉 Y 方向重算
if (xOnly) tableRef.value?.initVirtualScrollX?.()
else tableRef.value?.initVirtualScroll?.()
await nextTick()
})
}
/* 尺寸防抖(trailing):折叠动画 / 窗口缩放 / 拖拽调宽等连续尺寸变化期间,
* ResizeObserver 每帧都会通知,但中间尺寸是瞬态的——逐帧 initVirtualScroll
* 会每帧强制 reflow 并重渲染可见行列,造成动画掉帧(如侧栏折叠时 dashboard
* 10 万单元格表格的卡顿)。这里合并通知,尺寸稳定(约 150ms 无变化)后才
* 刷新一次,与 stk-table 库 autoResize 的 200ms 防抖语义对齐(库 L4130-4133)。
* 动画期间表格仅随 CSS 拉伸,结束后一次到位。 */
const RESIZE_DEBOUNCE_MS = 150
let resizeDebounceTimer = 0
// 上次生效尺寸:用于判断是否仅宽度变化(只重算 X 方向)
let lastSize = null
let resizeObserver = null
onMounted(() => {
if (typeof ResizeObserver === 'undefined' || !rootRef.value) return
resizeObserver = new ResizeObserver(([entry]) => {
const { width, height } = entry.contentRect
if (width > 0 && height > 0) refreshLayout()
if (width <= 0 || height <= 0) return
clearTimeout(resizeDebounceTimer)
resizeDebounceTimer = setTimeout(() => {
resizeDebounceTimer = 0
const xOnly = lastSize != null && lastSize.height === height && lastSize.width !== width
lastSize = { width, height }
refreshLayout(xOnly)
}, RESIZE_DEBOUNCE_MS)
})
resizeObserver.observe(rootRef.value)
})
@@ -515,6 +535,7 @@ watch(
onBeforeUnmount(() => {
if (refreshRafId) cancelAnimationFrame(refreshRafId)
clearTimeout(resizeDebounceTimer)
resizeObserver?.disconnect()
resizeObserver = null
removeNavigationListeners()
@@ -589,6 +610,11 @@ defineExpose({
.fms-table__inner {
width: 100%;
height: 100%;
/* transform 虚拟滚动模式下,把 tbody 提升为合成层,translateY 走合成器、避免每帧重绘整表 */
.stk-tbody-main {
will-change: transform;
}
}
</style>