bb7e2c04c8
移除未使用的 Lenis 类型导入以简化代码 在 htmlAttrs 中添加 lang 属性配置
70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
import { onBeforeUnmount, watch, type Ref, isRef, unref, computed } from 'vue'
|
|
import { useNuxtApp, useHead } from '#imports'
|
|
|
|
// 全局模块级变量,用于记录锁定请求的次数,解决多组件并发锁定的竞态问题
|
|
let lenisLockCount = 0
|
|
|
|
export const usePageScrollLock = (isLocked: Ref<boolean> | boolean) => {
|
|
const nuxtApp = useNuxtApp()
|
|
// 由于 $lenis 是从 client 插件中注入的,SSR 期间可能为 undefined
|
|
// 而且在 setup 期间解构可能拿不到最新的值,我们改为在函数内部动态获取
|
|
|
|
// SSR 和 CSR 都支持:自动将 class 注入到 HTML 标签上
|
|
useHead({
|
|
htmlAttrs: {
|
|
class: computed(() => unref(isLocked) ? 'is-home-intro-active' : ''),
|
|
lang: 'zh-CN',
|
|
},
|
|
})
|
|
|
|
let currentlyLocked = false
|
|
|
|
const updateLock = (locked: boolean) => {
|
|
// 防止重复触发相同状态
|
|
if (locked === currentlyLocked) return
|
|
currentlyLocked = locked
|
|
|
|
// Lenis 控制仅在客户端有效,不需要依赖 $lenis 立即存在
|
|
if (import.meta.client) {
|
|
if (locked) {
|
|
lenisLockCount++
|
|
// 只有第一个锁请求时,才真正停止 Lenis 并滚动到顶部
|
|
if (lenisLockCount === 1) {
|
|
document.documentElement.classList.add('is-home-intro-active')
|
|
// 注意:需要在这里动态获取 $lenis,因为此时 client 插件才可能挂载完成
|
|
const lenisInstance = nuxtApp.$lenis
|
|
if (lenisInstance) {
|
|
lenisInstance.scrollTo(0, { immediate: true })
|
|
lenisInstance.stop()
|
|
}
|
|
}
|
|
} else {
|
|
lenisLockCount = Math.max(0, lenisLockCount - 1)
|
|
// 只有当所有锁请求都释放时,才重新启动 Lenis
|
|
if (lenisLockCount === 0) {
|
|
document.documentElement.classList.remove('is-home-intro-active')
|
|
// 同理,动态获取
|
|
const lenisInstance = nuxtApp.$lenis
|
|
if (lenisInstance) {
|
|
lenisInstance.start()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 监听 Ref 变化,或立即处理 boolean 值
|
|
if (isRef(isLocked)) {
|
|
watch(isLocked, updateLock, { immediate: true })
|
|
} else {
|
|
updateLock(isLocked)
|
|
}
|
|
|
|
// 组件卸载时安全释放当前持有的锁
|
|
onBeforeUnmount(() => {
|
|
if (currentlyLocked) {
|
|
updateLock(false)
|
|
}
|
|
})
|
|
}
|