优化返回顶部图标
This commit is contained in:
parent
f3d7bca84c
commit
c732f72d08
@ -3,8 +3,13 @@
|
|||||||
<div
|
<div
|
||||||
v-if="visible"
|
v-if="visible"
|
||||||
class="back-to-top-btn"
|
class="back-to-top-btn"
|
||||||
@click="scrollToTop"
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
:aria-label="t('Back to top')"
|
||||||
:title="t('Back to top')"
|
:title="t('Back to top')"
|
||||||
|
@click="scrollToTop"
|
||||||
|
@keydown.enter="scrollToTop"
|
||||||
|
@keydown.space.prevent="scrollToTop"
|
||||||
>
|
>
|
||||||
<!-- SVG 圆形进度条 -->
|
<!-- SVG 圆形进度条 -->
|
||||||
<svg class="progress-ring" viewBox="0 0 48 48">
|
<svg class="progress-ring" viewBox="0 0 48 48">
|
||||||
@ -109,9 +114,7 @@ const getScrollInfo = (container: Element | Window): { scrollTop: number; scroll
|
|||||||
|
|
||||||
// 滚动到顶部
|
// 滚动到顶部
|
||||||
const scrollToTop = () => {
|
const scrollToTop = () => {
|
||||||
const containers = registeredContainers.value.length > 0
|
const containers = registeredContainers.value
|
||||||
? registeredContainers.value
|
|
||||||
: findScrollContainers()
|
|
||||||
|
|
||||||
containers.forEach(container => {
|
containers.forEach(container => {
|
||||||
if (container === window) {
|
if (container === window) {
|
||||||
@ -129,43 +132,54 @@ const scrollToTop = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 使用 requestAnimationFrame 优化滚动处理性能
|
||||||
|
let rafId: number | null = null
|
||||||
|
|
||||||
// 处理滚动事件
|
// 处理滚动事件
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
const containers = registeredContainers.value.length > 0
|
// 使用 requestAnimationFrame 节流,避免过度计算
|
||||||
? registeredContainers.value
|
if (rafId !== null) {
|
||||||
: findScrollContainers()
|
|
||||||
|
|
||||||
if (containers.length === 0) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查所有容器,取最大滚动值和总高度
|
rafId = requestAnimationFrame(() => {
|
||||||
let maxScrollTop = 0
|
const containers = registeredContainers.value
|
||||||
let maxProgress = 0
|
|
||||||
|
|
||||||
containers.forEach(container => {
|
|
||||||
const info = getScrollInfo(container)
|
|
||||||
const scrollTop = info.scrollTop
|
|
||||||
const maxScroll = info.scrollHeight - info.clientHeight
|
|
||||||
|
|
||||||
if (scrollTop > maxScrollTop) {
|
if (containers.length === 0) {
|
||||||
maxScrollTop = scrollTop
|
rafId = null
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算当前容器的滚动进度
|
// 检查所有容器,取最大滚动值和总高度
|
||||||
if (maxScroll > 0) {
|
let maxScrollTop = 0
|
||||||
const progress = Math.min(scrollTop / maxScroll, 1)
|
let maxProgress = 0
|
||||||
if (progress > maxProgress) {
|
|
||||||
maxProgress = progress
|
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(() => {
|
onMounted(() => {
|
||||||
@ -192,6 +206,12 @@ onUnmounted(() => {
|
|||||||
container.removeEventListener('scroll', handleScroll)
|
container.removeEventListener('scroll', handleScroll)
|
||||||
})
|
})
|
||||||
registeredContainers.value = []
|
registeredContainers.value = []
|
||||||
|
|
||||||
|
// 取消待处理的 requestAnimationFrame
|
||||||
|
if (rafId !== null) {
|
||||||
|
cancelAnimationFrame(rafId)
|
||||||
|
rafId = null
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -219,6 +239,15 @@ onUnmounted(() => {
|
|||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
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 {
|
.progress-ring {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user