/** * H5与小程序通信桥接工具函数库 * 提供统一的小程序原生功能调用接口 */ // 全局变量 window.H5_PAGE_NAME = window.H5_PAGE_NAME || 'default' /** * 设置当前页面名称 * @param {string} pageName 页面名称 */ function setPageName(pageName) { window.H5_PAGE_NAME = pageName } /** * 检查微信小程序环境 * @returns {boolean} 是否在微信小程序环境 */ function checkEnvironment() { return typeof wx !== 'undefined' && wx.miniProgram } /** * 解析URL参数(兼容性处理) * @param {string} search URL查询字符串 * @returns {Object} 参数对象 */ function parseUrlParams(search) { const params = {} if (search) { search.substring(1).split('&').forEach(param => { const [key, value] = param.split('=') if (key && value) { params[decodeURIComponent(key)] = decodeURIComponent(value) } }) } return params } /** * 检查是否有返回的结果数据 * @param {Function} onResult 结果处理回调 */ function checkResult(onResult) { const search = window.location.search console.log('🔍 检查URL参数:', search) if (search) { const params = parseUrlParams(search) console.log('🔍 解析的参数:', params) if (params.result) { try { const resultData = JSON.parse(decodeURIComponent(params.result)) console.log('🔍 解析的结果数据:', resultData) // 调用回调处理结果 if (onResult) { onResult(resultData) } } catch (error) { console.error('解析结果数据失败:', error) } } else { console.log('🔍 URL中没有result参数') } } else { console.log('🔍 URL中没有查询参数') } } /** * 调用小程序原生功能 * @param {string} action 操作类型 * @param {string} message 消息描述 * @param {Object} data 附加数据 */ function callNative(action, message = '', data = null) { if (!checkEnvironment()) { console.error('❌ 不在微信小程序环境') return } const params = { action: action, message: message || '', source: window.H5_PAGE_NAME } // 处理附加数据 if (data && typeof data === 'object') { try { const jsonString = JSON.stringify(data) params.data = encodeURIComponent(jsonString) console.log('📦 数据编码:', { original: data, json: jsonString, encoded: params.data }) } catch (error) { console.error('❌ JSON序列化失败:', error) return } } // 构建URL参数 const queryParts = [] Object.keys(params).forEach(key => { if (params[key] !== undefined && params[key] !== null) { if (key === 'data') { queryParts.push(`${key}=${params[key]}`) } else { queryParts.push(`${key}=${encodeURIComponent(params[key])}`) } } }) const controllerUrl = `/pages/common/h5-controller?${queryParts.join('&')}` console.log('🎛️ 跳转到控制器:', controllerUrl) // 调用微信小程序API,添加降级处理 wx.miniProgram.navigateTo({ url: controllerUrl, success: (res) => { console.log('✅ 成功跳转到控制器',res) }, fail: (err) => { console.error('❌ 控制器调用失败,尝试降级方案:', err) // 降级方案:使用URL参数通信(兼容老版本webview) fallbackUrlCommunication(action, message, data) } }) } /** * 降级通信方案:通过URL参数与webview通信 * @param {string} action 操作类型 * @param {string} message 消息描述 * @param {Object} data 附加数据 */ function fallbackUrlCommunication(action, message = '', data = null) { console.log('🔄 使用降级通信方案') const params = { h5_action: action, h5_message: message, timestamp: Date.now() } // 如果有额外数据,编码后添加 if (data && typeof data === 'object') { try { params.h5_data = encodeURIComponent(JSON.stringify(data)) } catch (error) { console.error('❌ 数据编码失败:', error) } } // 保留原有的非指令参数 const currentParams = parseUrlParams(window.location.search) Object.keys(currentParams).forEach(key => { if (!key.startsWith('h5_') && !key.startsWith('mp_') && key !== 'timestamp') { params[key] = currentParams[key] } }) // 构建新URL const baseUrl = `${window.location.origin}${window.location.pathname}` const queryParts = [] Object.keys(params).forEach(key => { if (params[key] !== undefined && params[key] !== null) { queryParts.push(`${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`) } }) const url = `${baseUrl}?${queryParts.join('&')}` console.log('🔄 降级跳转URL:', url) // 使用location.href触发webview的load事件 window.location.href = url } /** * 扫码 * @param {string} message 消息描述 * @returns {Promise} 调用结果 */ function scanCode(message = '扫描二维码') { return callNative('scanCode', message) } /** * 选择图片 * @param {string} message 消息描述 * @returns {Promise} 调用结果 */ function chooseImage(message = '选择图片') { return callNative('chooseImage', message) } /** * 拨打电话 * @param {string} phoneNumber 电话号码 * @param {string} message 消息描述 * @returns {Promise} 调用结果 */ function makePhoneCall(phoneNumber, message = '拨打电话') { return callNative('makePhoneCall', message, { phoneNumber }) } /** * 设置存储 * @param {string} key 存储键 * @param {*} value 存储值 * @param {string} message 消息描述 * @returns {Promise} 调用结果 */ function setStorage(key, value, message = '设置存储数据') { return callNative('setStorage', message, { key, value }) } /** * 获取存储 * @param {string} key 存储键 * @param {string} message 消息描述 * @returns {Promise} 调用结果 */ function getStorage(key, message = '获取存储数据') { return callNative('getStorage', message, { key }) } /** * 返回小程序 * @param {string} message 消息描述 * @returns {Promise} 调用结果 */ function goBack(message = '返回小程序') { return callNative('goBack', message) } /** * 页面跳转 * @param {string} page 目标页面 * @param {Object} params 跳转参数 */ function navigateTo(page, params = {}) { const queryString = Object.keys(params).length > 0 ? '?' + Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&') : '' window.location.href = `./${page}.html${queryString}` } /** * 保存数据到localStorage * @param {string} key 存储键 * @param {*} data 存储数据 */ function saveData(key, data) { try { const storageKey = `h5_${window.H5_PAGE_NAME}_${key}` localStorage.setItem(storageKey, JSON.stringify(data)) console.log('💾 数据已保存:', storageKey) } catch (error) { console.error('保存数据失败:', error) } } /** * 从localStorage加载数据 * @param {string} key 存储键 * @param {*} defaultValue 默认值 * @returns {*} 加载的数据 */ function loadData(key, defaultValue = null) { try { const storageKey = `h5_${window.H5_PAGE_NAME}_${key}` const savedData = localStorage.getItem(storageKey) if (savedData) { return JSON.parse(savedData) } } catch (error) { console.error('加载数据失败:', error) } return defaultValue } /** * 清除保存的数据 * @param {string} key 存储键 */ function clearData(key) { try { const storageKey = `h5_${window.H5_PAGE_NAME}_${key}` localStorage.removeItem(storageKey) console.log('🗑️ 数据已清除:', storageKey) } catch (error) { console.error('清除数据失败:', error) } } /** * 默认的结果处理函数 * @param {Object} data 结果数据 */ function defaultResultHandler(data) { const { action, success, result, error } = data if (success) { console.log(`✅ ${action} 操作成功`, result) } else { console.error(`❌ ${action} 操作失败`, error) } } /** * 初始化页面(可选调用) * @param {string} pageName 页面名称 * @param {Function} onResult 结果处理回调,不传则使用默认处理 */ function initPage(pageName, onResult) { setPageName(pageName) checkEnvironment() // 如果没有提供自定义处理,使用默认处理 const resultHandler = onResult || defaultResultHandler checkResult(resultHandler) } // ==================== UI工具函数 ==================== /** * 显示Toast效果(H5页面UI) * @param {string} message Toast消息 * @param {number} duration 显示时长(毫秒) * @param {string} type 类型:success|error|warning|info */ function showToastEffect(message, duration = 2000, type = 'success') { const colors = { success: 'rgba(40, 167, 69, 0.9)', error: 'rgba(220, 53, 69, 0.9)', warning: 'rgba(255, 193, 7, 0.9)', info: 'rgba(23, 162, 184, 0.9)' } const toast = document.createElement('div') toast.textContent = message toast.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: ${colors[type] || colors.success}; color: white; padding: 12px 24px; border-radius: 8px; z-index: 9999; font-size: 14px; pointer-events: none; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); ` document.body.appendChild(toast) setTimeout(() => { if (toast.parentNode) { toast.parentNode.removeChild(toast) } }, duration) } /** * 显示加载中效果 * @param {string} message 加载消息 * @returns {Function} 关闭加载的函数 */ function showLoading(message = '加载中...') { const loading = document.createElement('div') loading.innerHTML = `