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) => { const { $lenis } = useNuxtApp() as ReturnType & { $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) }) }