11/**
22 * 全局滚动状态管理(单例模式)
33 * 所有组件共享同一个滚动检测,避免重复监听
4+ * 支持 window scroll 和 OverlayScrollbars
45 */
56
67import { onBeforeUnmount , onMounted , readonly , ref } from 'vue'
78
9+ import { OVERLAY_SCROLL_STATE_CHANGE } from '~/constants/globalEvents'
10+ import emitter from '~/utils/mitt'
11+
812// 全局状态(单例)
913const isScrolling = ref ( false )
1014let scrollTimeout : ReturnType < typeof setTimeout > | null = null
1115let listenerCount = 0
12- let isListenerAttached = false
16+ let isWindowListenerAttached = false
17+ let isOverlayListenerAttached = false
1318
14- // 滚动处理函数 (单例)
15- function handleScroll ( ) {
19+ // Window滚动处理函数 (单例)
20+ function handleWindowScroll ( ) {
1621 isScrolling . value = true
1722
1823 if ( scrollTimeout ) {
@@ -24,14 +29,30 @@ function handleScroll() {
2429 } , 150 )
2530}
2631
32+ // OverlayScrollbars滚动状态处理函数(单例)
33+ function handleOverlayScrollState ( scrolling : boolean ) {
34+ isScrolling . value = scrolling
35+
36+ // 如果滚动结束,清理可能存在的 timeout
37+ if ( ! scrolling && scrollTimeout ) {
38+ clearTimeout ( scrollTimeout )
39+ scrollTimeout = null
40+ }
41+ }
42+
2743// 添加监听器(引用计数)
2844function addScrollListener ( ) {
2945 listenerCount ++
3046
3147 // 只在第一次添加时绑定事件
32- if ( ! isListenerAttached ) {
33- window . addEventListener ( 'scroll' , handleScroll , { passive : true } )
34- isListenerAttached = true
48+ if ( ! isWindowListenerAttached ) {
49+ window . addEventListener ( 'scroll' , handleWindowScroll , { passive : true } )
50+ isWindowListenerAttached = true
51+ }
52+
53+ if ( ! isOverlayListenerAttached ) {
54+ emitter . on ( OVERLAY_SCROLL_STATE_CHANGE , handleOverlayScrollState )
55+ isOverlayListenerAttached = true
3556 }
3657}
3758
@@ -40,9 +61,17 @@ function removeScrollListener() {
4061 listenerCount --
4162
4263 // 当所有组件都卸载时,移除事件监听
43- if ( listenerCount <= 0 && isListenerAttached ) {
44- window . removeEventListener ( 'scroll' , handleScroll )
45- isListenerAttached = false
64+ if ( listenerCount <= 0 ) {
65+ if ( isWindowListenerAttached ) {
66+ window . removeEventListener ( 'scroll' , handleWindowScroll )
67+ isWindowListenerAttached = false
68+ }
69+
70+ if ( isOverlayListenerAttached ) {
71+ emitter . off ( OVERLAY_SCROLL_STATE_CHANGE , handleOverlayScrollState )
72+ isOverlayListenerAttached = false
73+ }
74+
4675 listenerCount = 0
4776
4877 if ( scrollTimeout ) {
0 commit comments