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) {
|
// 忽略存储异常,避免影响页面正常使用。
|
}
|
}
|