feat(幕布): 一划到底改为整个幕布可见区生效
原先按距底 0.6 屏判断;改为由 InterselectionObserver 的幕布可见标志决定:滑到底后往上滑一点、幕布没离开视线时,再往下滑仍会滑到底 减弱动态效果下不接管滚动
This commit is contained in:
1 parent
fab527db6c
commit
ede01786cb
1 file changed
+13
-5
@@ -463,8 +463,7 @@ const CURTAIN_DASH_FALLBACK = 7.2
|
||||
/** 幕布露出这么多比例即起笔 */
|
||||
const CURTAIN_DRAW_AT = 0.6
|
||||
|
||||
/** 一划到底:距页面底部不足这么多屏时,下一次向下滑动直接滑到底 */
|
||||
const CURTAIN_GLIDE_ZONE = 0.6
|
||||
/** 一划到底:只要幕布还露在视口里(即 footer 之后那一段),再一次向下滑动就直接滑到底 */
|
||||
const CURTAIN_GLIDE_MS = 1100
|
||||
|
||||
const curtainSvg = ref<SVGSVGElement | null>(null)
|
||||
@@ -472,6 +471,10 @@ const curtainGroup = ref<SVGGElement | null>(null)
|
||||
const curtainSpacer = ref<HTMLElement | null>(null)
|
||||
const curtainDrawn = ref(false)
|
||||
|
||||
/** 幕布(末尾占位区)是否还在视口里。它就是"footer 之后"那段区域:
|
||||
* 用户滑到底后往上滑一点、幕布没离开视线,此时再往下滑仍要一划到底 */
|
||||
let curtainOnScreen = false
|
||||
|
||||
/** v-for 里的 <text> 引用,setupCurtain 要逐个量身定位 */
|
||||
const letterEls: (SVGTextElement | null)[] = []
|
||||
function setLetterEl(el: Element | ComponentPublicInstance | null, index: number): void {
|
||||
@@ -527,6 +530,8 @@ function watchCurtain(): void {
|
||||
curtainObserver = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
// 幕布在不在视线里,决定"一划到底"生不生效
|
||||
curtainOnScreen = entry.isIntersecting
|
||||
if (entry.isIntersecting && entry.intersectionRatio >= CURTAIN_DRAW_AT) {
|
||||
curtainDrawn.value = true
|
||||
} else if (!entry.isIntersecting) {
|
||||
@@ -539,14 +544,17 @@ function watchCurtain(): void {
|
||||
curtainObserver.observe(spacer)
|
||||
}
|
||||
|
||||
/** 一划到底:幕布已露头(距底不足 0.6 屏)时再一次向下滑动,就直接滑到底,
|
||||
* 省得用户在最后半屏里一点点蹭;顺带让描边动画在整块幕布前完整播完 */
|
||||
/** 一划到底:幕布还露在视口里时(footer 之后那一段,含滑到底后往上滑一点、幕布没离开视线的情况),
|
||||
* 再一次向下滑动就直接滑到底,省得用户在最后半屏里一点点蹭;
|
||||
* 顺带让描边动画在整块幕布前完整播完 */
|
||||
function glideToBottom(): void {
|
||||
if (prefersReducedMotion.matches) return // 减弱动态效果下不接管滚动
|
||||
if (!curtainOnScreen) return // 幕布已离开视线(还在上面正文里),不插手
|
||||
const now = performance.now()
|
||||
if (now < curtainGlideUntil) return
|
||||
const doc = document.documentElement
|
||||
const remaining = doc.scrollHeight - window.scrollY - window.innerHeight
|
||||
if (remaining <= 0 || remaining > window.innerHeight * CURTAIN_GLIDE_ZONE) return
|
||||
if (remaining <= 0) return // 已经在最底,没什么可滑的
|
||||
curtainGlideUntil = now + CURTAIN_GLIDE_MS + 300
|
||||
const top = doc.scrollHeight
|
||||
const lenis = lenisRef?.value
|
||||
|
||||
Reference in new issue
Block a user