diff --git a/apps/jingrow/frontend/src/app/layouts/BackToTop.vue b/apps/jingrow/frontend/src/app/layouts/BackToTop.vue index a922ddd..4f7d46d 100644 --- a/apps/jingrow/frontend/src/app/layouts/BackToTop.vue +++ b/apps/jingrow/frontend/src/app/layouts/BackToTop.vue @@ -3,8 +3,13 @@
@@ -109,9 +114,7 @@ const getScrollInfo = (container: Element | Window): { scrollTop: number; scroll // 滚动到顶部 const scrollToTop = () => { - const containers = registeredContainers.value.length > 0 - ? registeredContainers.value - : findScrollContainers() + const containers = registeredContainers.value containers.forEach(container => { if (container === window) { @@ -129,43 +132,54 @@ const scrollToTop = () => { }) } +// 使用 requestAnimationFrame 优化滚动处理性能 +let rafId: number | null = null + // 处理滚动事件 const handleScroll = () => { - const containers = registeredContainers.value.length > 0 - ? registeredContainers.value - : findScrollContainers() - - if (containers.length === 0) { + // 使用 requestAnimationFrame 节流,避免过度计算 + if (rafId !== null) { return } - // 检查所有容器,取最大滚动值和总高度 - let maxScrollTop = 0 - let maxProgress = 0 - - containers.forEach(container => { - const info = getScrollInfo(container) - const scrollTop = info.scrollTop - const maxScroll = info.scrollHeight - info.clientHeight + rafId = requestAnimationFrame(() => { + const containers = registeredContainers.value - if (scrollTop > maxScrollTop) { - maxScrollTop = scrollTop + if (containers.length === 0) { + rafId = null + return } - // 计算当前容器的滚动进度 - if (maxScroll > 0) { - const progress = Math.min(scrollTop / maxScroll, 1) - if (progress > maxProgress) { - maxProgress = progress + // 检查所有容器,取最大滚动值和总高度 + let maxScrollTop = 0 + let maxProgress = 0 + + containers.forEach(container => { + const info = getScrollInfo(container) + const scrollTop = info.scrollTop + const maxScroll = info.scrollHeight - info.clientHeight + + if (scrollTop > maxScrollTop) { + maxScrollTop = scrollTop } - } + + // 计算当前容器的滚动进度 + if (maxScroll > 0) { + const progress = Math.min(scrollTop / maxScroll, 1) + if (progress > maxProgress) { + maxProgress = progress + } + } + }) + + // 更新滚动进度 + scrollProgress.value = maxProgress + + // 根据最大滚动值判断是否显示按钮 + visible.value = maxScrollTop > SCROLL_THRESHOLD + + rafId = null }) - - // 更新滚动进度 - scrollProgress.value = maxProgress - - // 根据最大滚动值判断是否显示按钮 - visible.value = maxScrollTop > SCROLL_THRESHOLD } onMounted(() => { @@ -192,6 +206,12 @@ onUnmounted(() => { container.removeEventListener('scroll', handleScroll) }) registeredContainers.value = [] + + // 取消待处理的 requestAnimationFrame + if (rafId !== null) { + cancelAnimationFrame(rafId) + rafId = null + } }) @@ -219,6 +239,15 @@ onUnmounted(() => { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); } +.back-to-top-btn:focus { + outline: 2px solid #22c55e; + outline-offset: 2px; +} + +.back-to-top-btn:focus:not(:focus-visible) { + outline: none; +} + .progress-ring { position: absolute; top: 0;