feat(pc): 详情页增加吸顶返回列表按钮,首页按筛选签名恢复滚动位置

This commit is contained in:
yml2213
2026-08-15 10:42:09 +08:00
parent a25486201c
commit fbd59ed19f
4 changed files with 176 additions and 2 deletions
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { RouterLink, useRoute, useRouter } from 'vue-router'
import { RouterLink, onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
import {
defaultAWRecycleConfig,
defaultHomeAnnouncements,
@@ -164,6 +164,7 @@ async function loadHome() {
publishOptions.value = emptyListingPublishOptions
} finally {
loading.value = false
restorePcHomeScroll()
}
}
@@ -268,6 +269,63 @@ function buildDesktopHomeQueryValues(): Record<string, HomeQueryValue> {
}
}
// ========== PC 首页滚动位置持久化 ==========
// 详情页返回/浏览器后退时,首页列表异步加载导致页面高度不足,
// vue-router 的 savedPosition 恢复会被浏览器钳制到错误位置,
// 因此按「筛选签名」显式保存/恢复滚动位置,确保回到上次筛选的位置。
const pcHomeScrollStorageKey = 'hfb.home.scroll.desktop'
function savePcHomeScroll() {
try {
window.sessionStorage.setItem(
pcHomeScrollStorageKey,
JSON.stringify({ signature: desktopHomeStateSignature(), top: window.scrollY })
)
} catch {
// sessionStorage 不可用时忽略,仅损失滚动恢复
}
}
function restorePcHomeScroll() {
let savedTop = 0
let savedSignature = ''
try {
const raw = window.sessionStorage.getItem(pcHomeScrollStorageKey)
if (raw) {
const parsed = JSON.parse(raw) as { signature?: string; top?: number }
if (typeof parsed.signature === 'string' && typeof parsed.top === 'number') {
savedSignature = parsed.signature
savedTop = parsed.top
}
}
} catch {
return
}
// 仅当返回时的筛选条件与离开时一致才恢复,避免把滚动带到别的筛选结果上
if (savedTop <= 0 || savedSignature !== desktopHomeStateSignature()) return
let attempts = 0
const apply = () => {
const maxTop = Math.max(0, document.documentElement.scrollHeight - window.innerHeight)
if (savedTop <= maxTop) {
window.scrollTo({ top: savedTop })
return
}
// 首页无限滚动分页:已渲染高度不足时继续加载一页后重试,尽量恢复到位
if (attempts < 5 && hasMoreListings.value && !loadingMore.value) {
attempts += 1
void loadListingsPage(false).then(() => requestAnimationFrame(apply))
} else {
window.scrollTo({ top: maxTop })
}
}
requestAnimationFrame(apply)
}
onBeforeRouteLeave(() => {
savePcHomeScroll()
})
syncHomeQuery()
loadHome()
</script>