Skip to content

Commit 567c15d

Browse files
committed
fix: 修复 useIsMobile 的抖动问题
现在移动端判定会: - 忽略 VS Code webview/iframe 隐藏时的尺寸变化 - 忽略 0 宽这类无效 viewport - 在 matchMedia / resize 后延迟 120ms 再确认真实宽度 这样 tab 切走再回来时,不会因为短暂小宽度进入 mobile 分支,也就不会把日志分析桌面布局卸载再重新加载
1 parent 5398499 commit 567c15d

1 file changed

Lines changed: 43 additions & 3 deletions

File tree

src/composables/useIsMobile.ts

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,52 @@ import { ref } from 'vue'
22
import type { Ref } from 'vue'
33

44
const MOBILE_BREAKPOINT = '(max-width: 768px)'
5+
const MOBILE_BREAKPOINT_WIDTH = 768
6+
const LAYOUT_STABILIZE_DELAY_MS = 120
57

68
const mediaQuery = window.matchMedia(MOBILE_BREAKPOINT)
7-
const isMobile = ref(mediaQuery.matches)
89

9-
mediaQuery.addEventListener('change', (e) => {
10-
isMobile.value = e.matches
10+
const readViewportWidth = (): number | null => {
11+
const candidates = [
12+
window.visualViewport?.width,
13+
window.innerWidth,
14+
document.documentElement?.clientWidth,
15+
].filter((value): value is number => typeof value === 'number' && Number.isFinite(value))
16+
17+
const width = Math.max(0, ...candidates)
18+
return width > 0 ? width : null
19+
}
20+
21+
const readStableMobileState = (): boolean | null => {
22+
if (document.visibilityState === 'hidden') return null
23+
const width = readViewportWidth()
24+
if (width == null) return null
25+
return width <= MOBILE_BREAKPOINT_WIDTH
26+
}
27+
28+
const isMobile = ref(readStableMobileState() ?? mediaQuery.matches)
29+
let pendingUpdate: ReturnType<typeof setTimeout> | null = null
30+
31+
const commitStableMobileState = () => {
32+
pendingUpdate = null
33+
const next = readStableMobileState()
34+
if (next == null) return
35+
isMobile.value = next
36+
}
37+
38+
const scheduleStableMobileUpdate = () => {
39+
if (pendingUpdate) clearTimeout(pendingUpdate)
40+
pendingUpdate = setTimeout(commitStableMobileState, LAYOUT_STABILIZE_DELAY_MS)
41+
}
42+
43+
mediaQuery.addEventListener('change', () => {
44+
scheduleStableMobileUpdate()
45+
})
46+
47+
window.addEventListener('resize', scheduleStableMobileUpdate)
48+
window.visualViewport?.addEventListener('resize', scheduleStableMobileUpdate)
49+
document.addEventListener('visibilitychange', () => {
50+
if (document.visibilityState === 'visible') scheduleStableMobileUpdate()
1151
})
1252

1353
export function useIsMobile(): { isMobile: Ref<boolean> } {

0 commit comments

Comments
 (0)