@@ -271,6 +271,11 @@ export const LeftSidebar = ({ onFlyTo, addMarkerEnabled, onToggleAddMarker }: Le
271271 // 视图切换动画:向左滑出,从右滑入
272272 const [ slideState , setSlideState ] = useState < 'idle' | 'exit' | 'enter' > ( 'idle' )
273273 const [ blockClicks , setBlockClicks ] = useState ( false ) // 防幽灵 click
274+ const blockClicksRef = useRef ( false ) // ref 供捕获监听器同步读取(state 有闭包延迟)
275+ const setBlockClicksSync = useCallback ( ( val : boolean ) => {
276+ blockClicksRef . current = val
277+ setBlockClicks ( val )
278+ } , [ ] )
274279 const [ displayMode , setDisplayMode ] = useState ( activeView . mode )
275280 const [ displayTripId , setDisplayTripId ] = useState ( activeView . tripId )
276281 const [ displayDayId , setDisplayDayId ] = useState ( activeView . dayId )
@@ -290,7 +295,7 @@ export const LeftSidebar = ({ onFlyTo, addMarkerEnabled, onToggleAddMarker }: Le
290295
291296 // 1. 当前内容淡出(150ms)
292297 setSlideState ( 'exit' )
293- setBlockClicks ( true )
298+ setBlockClicksSync ( true )
294299 cancelConfirmDelete ( )
295300
296301 // 2. 内容切换 + 新内容淡入
@@ -302,7 +307,7 @@ export const LeftSidebar = ({ onFlyTo, addMarkerEnabled, onToggleAddMarker }: Le
302307 requestAnimationFrame ( ( ) => {
303308 requestAnimationFrame ( ( ) => setSlideState ( 'idle' ) )
304309 } )
305- setTimeout ( ( ) => setBlockClicks ( false ) , 300 )
310+ setTimeout ( ( ) => setBlockClicksSync ( false ) , 600 )
306311 } , 150 )
307312
308313 return ( ) => { clearTimeout ( t ) }
@@ -458,8 +463,8 @@ export const LeftSidebar = ({ onFlyTo, addMarkerEnabled, onToggleAddMarker }: Le
458463 setActiveDragId ( null )
459464
460465 // 拖拽结束后短暂屏蔽点击,防止 touchend 合成的 ghost click 触发按钮
461- setBlockClicks ( true )
462- setTimeout ( ( ) => setBlockClicks ( false ) , 300 )
466+ setBlockClicksSync ( true )
467+ setTimeout ( ( ) => setBlockClicksSync ( false ) , 300 )
463468
464469 if ( ! over || active . id === over . id ) return
465470 if ( ! currentDay || ! activeView . tripId || ! activeView . dayId ) return
@@ -677,7 +682,7 @@ export const LeftSidebar = ({ onFlyTo, addMarkerEnabled, onToggleAddMarker }: Le
677682 { /* Back button */ }
678683 { displayMode === 'trip' && (
679684 < button
680- onClick = { ( ) => { setBlockClicks ( true ) ; setActiveView ( 'overview' , null , null ) } }
685+ onClick = { ( ) => { setBlockClicksSync ( true ) ; setActiveView ( 'overview' , null , null ) } }
681686 className = "mr-1 p-1 rounded-lg text-gray-500 hover:bg-white/80 hover:text-blue-600 transition-colors"
682687 title = "返回全览"
683688 >
@@ -688,7 +693,7 @@ export const LeftSidebar = ({ onFlyTo, addMarkerEnabled, onToggleAddMarker }: Le
688693 ) }
689694 { displayMode === 'day' && (
690695 < button
691- onClick = { ( ) => { setBlockClicks ( true ) ; setActiveView ( 'trip' , activeView . tripId , null ) } }
696+ onClick = { ( ) => { setBlockClicksSync ( true ) ; setActiveView ( 'trip' , activeView . tripId , null ) } }
692697 className = "mr-1 p-1 rounded-lg text-gray-500 hover:bg-white/80 hover:text-blue-600 transition-colors"
693698 title = "返回旅行"
694699 >
@@ -851,7 +856,7 @@ export const LeftSidebar = ({ onFlyTo, addMarkerEnabled, onToggleAddMarker }: Le
851856 return (
852857 < div key = { trip . id } className = "border border-gray-200 rounded-xl bg-white overflow-hidden mb-2" >
853858 < button
854- onClick = { ( ) => { setBlockClicks ( true ) ; setActiveView ( 'trip' , trip . id , null ) } }
859+ onClick = { ( ) => { setBlockClicksSync ( true ) ; setActiveView ( 'trip' , trip . id , null ) } }
855860 className = "w-full flex items-center gap-3 px-3 py-3 hover:bg-blue-50 transition-colors text-left"
856861 >
857862 < div className = "w-9 h-9 bg-blue-100 rounded-full flex items-center justify-center text-lg flex-shrink-0" > { trip . emoji ?? '✈️' } </ div >
@@ -985,7 +990,7 @@ export const LeftSidebar = ({ onFlyTo, addMarkerEnabled, onToggleAddMarker }: Le
985990 return (
986991 < React . Fragment key = { day . id } >
987992 < button
988- onClick = { ( ) => { setBlockClicks ( true ) ; setActiveView ( 'day' , activeView . tripId , day . id ) } }
993+ onClick = { ( ) => { setBlockClicksSync ( true ) ; setActiveView ( 'day' , activeView . tripId , day . id ) } }
989994 className = "w-full flex items-center gap-3 px-3 py-3 border border-gray-200 rounded-xl bg-white hover:border-blue-300 hover:bg-blue-50 transition-colors text-left"
990995 >
991996 < div className = "w-9 h-9 bg-blue-100 rounded-full flex items-center justify-center text-sm font-bold text-blue-600 flex-shrink-0" >
@@ -1290,6 +1295,14 @@ export const LeftSidebar = ({ onFlyTo, addMarkerEnabled, onToggleAddMarker }: Le
12901295 ! leftSidebar . isOpen ? 'max-lg:-translate-x-full max-lg:transition-transform max-lg:duration-200' : 'max-lg:animate-slide-in-left' ,
12911296 ) }
12921297 style = { { paddingTop : 'env(safe-area-inset-top)' , paddingBottom : 'env(safe-area-inset-bottom, 0px)' } }
1298+ onClickCapture = { ( e ) => {
1299+ // 在捕获阶段拦截 ghost click:CSS pointer-events-none 无法阻止已合成的事件,
1300+ // 用 ref(非 state)同步判断,stopPropagation + preventDefault 双重阻断
1301+ if ( blockClicksRef . current ) {
1302+ e . stopPropagation ( )
1303+ e . preventDefault ( )
1304+ }
1305+ } }
12931306 >
12941307 { renderHeader ( ) }
12951308
0 commit comments