优化返回顶部图标

This commit is contained in:
jingrow 2025-11-02 03:16:34 +08:00
parent f3d7bca84c
commit c732f72d08

View File

@ -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;