refactor(composables): 改进页面滚动锁定逻辑并修复潜在问题

确保在客户端插件加载完成后再获取 Lenis 实例
修复组件卸载时可能的状态不一致问题
将 useHead 配置整合到 usePageScrollLock 中
This commit is contained in:
2026-04-27 02:51:45 +08:00
parent a353322454
commit dba0c18001
3 changed files with 23 additions and 22 deletions
+17 -9
View File
@@ -6,8 +6,10 @@ import type Lenis from 'lenis'
let lenisLockCount = 0
export const usePageScrollLock = (isLocked: Ref<boolean> | boolean) => {
const { $lenis } = useNuxtApp() as ReturnType<typeof useNuxtApp> & { $lenis?: Lenis }
const nuxtApp = useNuxtApp()
// 由于 $lenis 是从 client 插件中注入的,SSR 期间可能为 undefined
// 而且在 setup 期间解构可能拿不到最新的值,我们改为在函数内部动态获取
// SSR 和 CSR 都支持:自动将 class 注入到 HTML 标签上
useHead({
htmlAttrs: {
@@ -22,16 +24,18 @@ export const usePageScrollLock = (isLocked: Ref<boolean> | boolean) => {
if (locked === currentlyLocked) return
currentlyLocked = locked
// Lenis 控制仅在客户端有效
// Lenis 控制仅在客户端有效,不需要依赖 $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()
// 注意:需要在这里动态获取 $lenis,因为此时 client 插件才可能挂载完成
const lenisInstance = (nuxtApp as any).$lenis
if (lenisInstance) {
lenisInstance.scrollTo(0, { immediate: true })
lenisInstance.stop()
}
}
} else {
@@ -39,8 +43,10 @@ export const usePageScrollLock = (isLocked: Ref<boolean> | boolean) => {
// 只有当所有锁请求都释放时,才重新启动 Lenis
if (lenisLockCount === 0) {
document.documentElement.classList.remove('is-home-intro-active')
if ($lenis) {
$lenis.start()
// 同理,动态获取
const lenisInstance = (nuxtApp as any).$lenis
if (lenisInstance) {
lenisInstance.start()
}
}
}
@@ -56,6 +62,8 @@ export const usePageScrollLock = (isLocked: Ref<boolean> | boolean) => {
// 组件卸载时安全释放当前持有的锁
onBeforeUnmount(() => {
updateLock(false)
if (currentlyLocked) {
updateLock(false)
}
})
}