Files
arcticnewone/app/composables/usePageScrollLock.ts
T
virtheart ea9b7747e2 fix(首页): 修复入场动画期间滚动锁定问题
确保在 Lenis 加载完成前后都能正确锁定页面滚动
修复滚动锁定计数逻辑,避免重复操作
2026-04-27 02:42:03 +08:00

62 lines
1.8 KiB
TypeScript

import { onBeforeUnmount, watch, type Ref, isRef, unref, computed } from 'vue'
import { useNuxtApp, useHead } from '#imports'
import type Lenis from 'lenis'
// 全局模块级变量,用于记录锁定请求的次数,解决多组件并发锁定的竞态问题
let lenisLockCount = 0
export const usePageScrollLock = (isLocked: Ref<boolean> | boolean) => {
const { $lenis } = useNuxtApp() as ReturnType<typeof useNuxtApp> & { $lenis?: Lenis }
// SSR 和 CSR 都支持:自动将 class 注入到 HTML 标签上
useHead({
htmlAttrs: {
class: computed(() => unref(isLocked) ? 'is-home-intro-active' : '')
}
})
let currentlyLocked = false
const updateLock = (locked: boolean) => {
// 防止重复触发相同状态
if (locked === currentlyLocked) return
currentlyLocked = locked
// Lenis 控制仅在客户端有效
if (import.meta.client) {
if (locked) {
lenisLockCount++
// 只有第一个锁请求时,才真正停止 Lenis 并滚动到顶部
if (lenisLockCount === 1) {
document.documentElement.classList.add('is-home-intro-active')
if ($lenis) {
$lenis.scrollTo(0, { immediate: true })
$lenis.stop()
}
}
} else {
lenisLockCount = Math.max(0, lenisLockCount - 1)
// 只有当所有锁请求都释放时,才重新启动 Lenis
if (lenisLockCount === 0) {
document.documentElement.classList.remove('is-home-intro-active')
if ($lenis) {
$lenis.start()
}
}
}
}
}
// 监听 Ref 变化,或立即处理 boolean 值
if (isRef(isLocked)) {
watch(isLocked, updateLock, { immediate: true })
} else {
updateLock(isLocked)
}
// 组件卸载时安全释放当前持有的锁
onBeforeUnmount(() => {
updateLock(false)
})
}