|
|
|
|
@ -123,6 +123,10 @@ const estimatedHeaderHeight = ref<number | undefined>(undefined);
@@ -123,6 +123,10 @@ const estimatedHeaderHeight = ref<number | undefined>(undefined);
|
|
|
|
|
let miniTableResizeObserver: ResizeObserver | null = null; |
|
|
|
|
let lastMiniTableHeight = 0; |
|
|
|
|
|
|
|
|
|
// Track if table is visible in viewport - only probe when visible |
|
|
|
|
const isInViewport = ref(false); |
|
|
|
|
let viewportObserver: IntersectionObserver | null = null; |
|
|
|
|
|
|
|
|
|
// Header height constant |
|
|
|
|
|
|
|
|
|
type TimestampValue = |
|
|
|
|
@ -285,9 +289,10 @@ function estimateTableRowHeight() {
@@ -285,9 +289,10 @@ function estimateTableRowHeight() {
|
|
|
|
|
// Observe miniTableRef instead of myTableRef - only re-probe if mini-table's rendered height changes |
|
|
|
|
// This avoids unnecessary re-probing during window resize when container width changes but row heights stay same |
|
|
|
|
onMounted(() => { |
|
|
|
|
// Resize handler - only re-probe if the mini-table's actual height changed |
|
|
|
|
// Resize handler - only re-probe if the mini-table's actual height changed AND table is visible |
|
|
|
|
const handleResize = lodash.debounce(async () => { |
|
|
|
|
if (!shouldUseProbeRow.value || miniTableData.value.length === 0) { |
|
|
|
|
// Skip if not using probe, no data, or not visible in viewport |
|
|
|
|
if (!shouldUseProbeRow.value || miniTableData.value.length === 0 || !isInViewport.value) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -315,16 +320,43 @@ onMounted(() => {
@@ -315,16 +320,43 @@ onMounted(() => {
|
|
|
|
|
estimatedRowHeight.value = newRow; |
|
|
|
|
estimatedHeaderHeight.value = newHeader; |
|
|
|
|
}); |
|
|
|
|
}, 200); |
|
|
|
|
}, 50); |
|
|
|
|
|
|
|
|
|
// Observe miniTableRef for height changes |
|
|
|
|
// The mini-table's height only changes when column widths cause text to wrap |
|
|
|
|
// During typical window resize with fixed-height content, height stays same → no re-probe |
|
|
|
|
// ResizeObserver for mini-table height changes |
|
|
|
|
miniTableResizeObserver = new ResizeObserver(() => { |
|
|
|
|
handleResize(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
if (miniTableRef.value) { |
|
|
|
|
// IntersectionObserver to track viewport visibility |
|
|
|
|
// Only attach ResizeObserver when table is visible, detach when off-screen |
|
|
|
|
// This saves CPU for tables scrolled out of view |
|
|
|
|
viewportObserver = new IntersectionObserver( |
|
|
|
|
(entries) => { |
|
|
|
|
const entry = entries[0]; |
|
|
|
|
isInViewport.value = entry.isIntersecting; |
|
|
|
|
|
|
|
|
|
if (entry.isIntersecting) { |
|
|
|
|
// Table became visible - reconnect ResizeObserver |
|
|
|
|
if (miniTableRef.value && miniTableResizeObserver) { |
|
|
|
|
miniTableResizeObserver.observe(miniTableRef.value); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Table went off-screen - disconnect ResizeObserver to save CPU |
|
|
|
|
// Heights are cached, so no need to keep observing |
|
|
|
|
if (miniTableResizeObserver) { |
|
|
|
|
miniTableResizeObserver.disconnect(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
{ threshold: 0 } // Trigger as soon as any part is visible |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
if (myTableRef.value) { |
|
|
|
|
viewportObserver.observe(myTableRef.value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Initial observation of mini-table if already in viewport |
|
|
|
|
if (miniTableRef.value && isInViewport.value && miniTableResizeObserver) { |
|
|
|
|
miniTableResizeObserver.observe(miniTableRef.value); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
@ -335,6 +367,10 @@ onUnmounted(() => {
@@ -335,6 +367,10 @@ onUnmounted(() => {
|
|
|
|
|
miniTableResizeObserver.disconnect(); |
|
|
|
|
miniTableResizeObserver = null; |
|
|
|
|
} |
|
|
|
|
if (viewportObserver) { |
|
|
|
|
viewportObserver.disconnect(); |
|
|
|
|
viewportObserver = null; |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const containerStyle = computed(() => { |
|
|
|
|
|