修复: 虚拟滚动 IO 卸载分支 height=0 时 minHeight fallback 防 slot 塌 0 重叠(P0)

This commit is contained in:
2026-06-17 23:33:28 +08:00
parent 36cde88b80
commit 8abcd567a6

View File

@@ -69,9 +69,14 @@ export function useAiVirtualScroll(options: AiVirtualScrollOptions) {
// 卸载前:把实测高度锁到 sentinel 的 minHeight,防内容移除后 sentinel 塌成 0
// → scrollHeight 不变 → isNearBottom/scrollToBottom/回到底部计算零感知。
// 内容重新挂载时 RO 会把真实高度回填,registerSentinel 复挂时清 minHeight 由真实高度接管。
// 防御(P0):RO 首次回调前 item 已被 IO 判不可见时 meta.height===0,直接不设 minHeight
// → sentinel 塌 0 高 → 下条消息上浮重叠。此处兜底:height>0 用实测值,
// height===0 用 el.offsetWidth 量得的实际渲染高度(此时 el 仍在 DOM),仍<=0 则用固定 40px。
const meta = itemMeta.get(key)
if (meta && meta.height > 0 && meta.el.isConnected) {
meta.el.style.minHeight = `${meta.height}px`
if (meta && meta.el.isConnected) {
const measured = meta.height > 0 ? meta.height : (meta.el.offsetHeight || 0)
const placeholder = measured > 0 ? measured : 40
meta.el.style.minHeight = `${placeholder}px`
}
next.delete(key); changed = true
}
@@ -98,9 +103,12 @@ export function useAiVirtualScroll(options: AiVirtualScrollOptions) {
const prev = itemMeta.get(key)
if (el instanceof HTMLElement) {
el.dataset.vscrollKey = key
// 复用上次实测高度作为初始 inline 占位(再次挂载时先占位,内容挂载后 RO 再校准)
// 复用上次实测高度作为初始 inline 占位(再次挂载时先占位,内容挂载后 RO 再校准)
// 防御(P0):首次挂载(无 prev / RO 未回填)h<=0 时若不设占位,sentinel 首帧塌 0 高 →
// 列表首次渲染时下条上浮重叠。此处用保守默认 40px 占位,RO 回调后用真实高度覆盖。
const h = prev?.height ?? 0
if (h > 0) el.style.minHeight = `${h}px`
const placeholder = h > 0 ? h : 40
el.style.minHeight = `${placeholder}px`
itemMeta.set(key, { el, height: h })
ensureObserver()
io?.observe(el)