zjk
2026-09-29 54dcf0a82e7490fa58b1c056d5c0b9cb739c2931
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
const VCONSOLE_QUERY_KEY = 'vconsole'
const VCONSOLE_STORAGE_KEY = '__ENABLE_VCONSOLE__'
const VCONSOLE_SCRIPT_URL = 'https://cdn.jsdelivr.net/npm/vconsole@3.15.1/dist/vconsole.min.js'
 
let vConsoleBootstrapped = false
 
/**
 * 仅在 H5 环境按需启用 vConsole,方便 iOS 真机排查分享页问题。
 * 开启方式:
 * 1. 链接追加 ?vconsole=1 或 &vconsole=1
 * 2. 开启后会写入 localStorage,后续刷新页面仍保持开启
 * 3. 链接追加 ?vconsole=0 可关闭
 */
export function initH5DebugPanel() {
    if (typeof window === 'undefined' || vConsoleBootstrapped) {
        return
    }
    const debugFlag = resolveDebugFlag()
    if (!debugFlag) {
        return
    }
    vConsoleBootstrapped = true
    bindGlobalDebugEvents()
    loadVConsoleScript()
}
 
function resolveDebugFlag() {
    const queryValue = getQueryParamValue(VCONSOLE_QUERY_KEY)
    if (queryValue === '1') {
        safeSetStorage(VCONSOLE_STORAGE_KEY, '1')
        return true
    }
    if (queryValue === '0') {
        safeRemoveStorage(VCONSOLE_STORAGE_KEY)
        return false
    }
    return safeGetStorage(VCONSOLE_STORAGE_KEY) === '1'
}
 
function bindGlobalDebugEvents() {
    window.addEventListener('error', (event) => {
        const error = event.error
        console.error('[h5-debug] window error:', {
            message: event.message,
            source: event.filename,
            line: event.lineno,
            column: event.colno,
            stack: error && error.stack ? error.stack : '',
        })
    })
    window.addEventListener('unhandledrejection', (event) => {
        console.error('[h5-debug] unhandled rejection:', event.reason)
    })
}
 
function loadVConsoleScript() {
    if (window.VConsole) {
        createVConsoleInstance()
        return
    }
    const existingScript = document.querySelector(`script[data-debug-tool="${VCONSOLE_QUERY_KEY}"]`)
    if (existingScript) {
        existingScript.addEventListener('load', createVConsoleInstance, { once: true })
        return
    }
    const script = document.createElement('script')
    script.src = VCONSOLE_SCRIPT_URL
    script.async = true
    script.setAttribute('data-debug-tool', VCONSOLE_QUERY_KEY)
    script.onload = createVConsoleInstance
    script.onerror = () => {
        console.error('[h5-debug] vConsole 加载失败:', VCONSOLE_SCRIPT_URL)
    }
    document.head.appendChild(script)
}
 
function createVConsoleInstance() {
    if (!window.VConsole || window.__h5VConsoleInstance) {
        return
    }
    window.__h5VConsoleInstance = new window.VConsole()
    console.log('[h5-debug] vConsole 已启用')
}
 
function getQueryParamValue(key) {
    const searchValue = readQueryValue(window.location.search, key)
    if (searchValue) {
        return searchValue
    }
    const hashQuery = String(window.location.hash || '').split('?')[1] || ''
    return readQueryValue(hashQuery, key)
}
 
function readQueryValue(queryText, key) {
    if (typeof queryText !== 'string' || !queryText) {
        return ''
    }
    const normalizedQuery = queryText.replace(/^[?#&]/, '')
    if (!normalizedQuery) {
        return ''
    }
    const pairs = normalizedQuery.split('&')
    for (const pair of pairs) {
        if (!pair) {
            continue
        }
        const splitIndex = pair.indexOf('=')
        const rawKey = splitIndex >= 0 ? pair.slice(0, splitIndex) : pair
        if (safeDecode(rawKey) !== key) {
            continue
        }
        const rawValue = splitIndex >= 0 ? pair.slice(splitIndex + 1) : ''
        return safeDecode(rawValue).trim()
    }
    return ''
}
 
function safeDecode(value) {
    try {
        return decodeURIComponent(String(value || '').replace(/\+/g, ' '))
    } catch (error) {
        return String(value || '')
    }
}
 
function safeGetStorage(key) {
    try {
        return window.localStorage.getItem(key)
    } catch (error) {
        return ''
    }
}
 
function safeSetStorage(key, value) {
    try {
        window.localStorage.setItem(key, value)
    } catch (error) {
        // 忽略存储异常,避免影响页面正常使用。
    }
}
 
function safeRemoveStorage(key) {
    try {
        window.localStorage.removeItem(key)
    } catch (error) {
        // 忽略存储异常,避免影响页面正常使用。
    }
}