导航:修复顶栏隐藏/唤回在滚动徘徊时的抽搐

根因:隐藏/唤回是单事件方向判定——滚动事件里下滑 4px 就藏、往上一有
回弹就现身。拖动页面在阈值附近徘徊时(触控板噪声 / 惯性回弹 / 滚动条
微调都会产生正负几十像素的事件),顶栏每次都被翻转,吸顶头(标题 +
切换 tabs + 发布盒顶部)跟着一起上下滑动——即站主截图里的抽搐。

修复:改成「同向累计迟滞」——滚动事件按方向累计净滚动量(acc),
同向持续累计、反向从新方向重新累计,小幅往复正负抵消:

- 累计下滑 40px(且 y > 120,滚出页首区)→ 隐藏
- 隐藏状态下累计上滑 60px → 唤回
- 滚回页首(y ≤ 80)或菜单打开时强制显示(不变)

实测:在阈值附近以 ±70px 快速往复 1.1 秒,翻转 0 次、顶栏稳定;
持续滚动(下滑 → 隐藏、上滑 81px → 唤回、再下滑 → 再隐藏)状态
切换全部正确。prefers-reduced-motion 下过渡照旧禁用。
This commit is contained in:
Sakurasan
2026-09-27 17:06:15 +08:00
parent 34f0faedcc
commit 08250b58ef
+18 -8
View File
@@ -27,26 +27,36 @@ function isOn(l) {
return l.to === '/' ? route.path === '/' : route.path.startsWith(l.to) return l.to === '/' ? route.path === '/' : route.path.startsWith(l.to)
} }
// 下滑藏顶栏、上滑唤回。dead zone 滤掉手指微抖;滚回页首(没滚出顶栏多远) // 下滑藏顶栏、上滑唤回。迟滞用「同向累计」:往复拖动时正负抵消,
// 或菜单开着时强制显示 —— 纸片锚在顶栏下面,顶栏藏了纸片会悬空。 // 持续同向滚动超过阈值才切换状态——之前的单事件方向判定
// 上滑唤回要累计上移 40px 才算数:页面加载后字体/内容稳定时高度会收缩, // (下滑 4px 就藏、回弹就现身)在阈值附近徘徊时会抽搐。
// 浏览器把滚动位置回弹几十像素,那种「假上滑」不该把顶栏拉回来。 // 滚回页首(y ≤ 80)或菜单开着时强制显示 —— 纸片锚在顶栏下面,
// 顶栏藏了纸片会悬空。
let lastY = typeof window === 'undefined' ? 0 : window.scrollY let lastY = typeof window === 'undefined' ? 0 : window.scrollY
let hideY = 0 let acc = 0
function onScroll() { function onScroll() {
const y = window.scrollY const y = window.scrollY
if (open.value || y <= 80) { if (open.value || y <= 80) {
hidden.value = false hidden.value = false
lastY = y lastY = y
acc = 0
return return
} }
const delta = y - lastY const delta = y - lastY
lastY = y lastY = y
if (delta > 4) { if (delta === 0) return
// 同向累计;反向则从新方向重新累计(小幅往复互相抵消)
if (acc === 0 || (delta > 0) === (acc > 0)) {
acc += delta
} else {
acc = delta
}
if (!hidden.value && acc > 80 && y > 120) {
hidden.value = true hidden.value = true
hideY = y acc = 0
} else if (delta < -4 && hideY - y > 40) { } else if (hidden.value && acc < -60) {
hidden.value = false hidden.value = false
acc = 0
} }
} }