//屏幕适配工具类 -解决小程序滚动条问题 class ScreenAdapter { constructor() { this.systemInfo = null; // 存储设备系统信息(如屏幕尺寸,像素比等) this.isInitialized = false; // 标记适配器是否已经初始化 this.deviceInfo = {}; // 存储设备详细信息(如信号,系统版本等) this.adaptationInfo = {} // 存储计算后的适配参数(如滚动区域高度,导航栏高度) } // 初始化适配器 async init() { if (this.isInitialized) { return this.adaptationInfo; } try { // 使用新的API 获取系统信息 const [windowInfo, deviceInfo, appBaseInfo] = await Promise.all([ this.getWindowInfo(), this.getDeviceInfo(), this.getAppBaseInfo() ]); // 合并系统信息 this.systemInfo = { ...windowInfo, ...deviceInfo, ...appBaseInfo } //计算适配信息 this.calculateAdaptation(); this.isInitialized = true; return this.adaptationInfo; } catch (error) { this.fallbackInit(); return this.adaptationInfo; }finally{ } } // 获取窗口信息(新API) getWindowInfo() { return new Promise((resolve) => { try { const windowInfo = wx.getWindowInfo(); resolve(windowInfo) } catch (error) { // 同步失败用异步 wx.getWindowInfo({ success: (res) => resolve(res), fail: () => { // 失败返回默认值 resolve({ windowWidth: 375, windowHeight: 667, pixelRatio: 2, statusBarHeight: 20, platform: 'android', system: 'Android 16', model: 'Unknown Device', brand: 'Unknown', safeArea: { top: 20, bottom: 667, left: 0, right: 375 } }); } }); } }) } // 获取设备信息 getDeviceInfo() { return new Promise((resolve) => { try { const deviceInfo = wx.getDeviceInfo() resolve(deviceInfo) } catch (error) { resolve( { platform: 'unknown', system: 'unknown', model: 'unknown' } ) } }) } // 获取应用基础信息 getAppBaseInfo() { return new Promise((resolve) => { try { const appBaseInfo = wx.getAppBaseInfo() resolve(appBaseInfo) } catch (error) { resolve({ version: '1.0.0', language: 'zh_CN' }) } }) } // 兜底初始化 fallbackInit() { try { // this.systemInfo = wx.getWindowInfo() this.systemInfo = this.getWindowInfo() this.calculateAdaptation() this.isInitialized = true } catch (error) { this.useDefaultValues(); } } // 计算适配信息 calculateAdaptation() { const { windowWidth, screenHeight,windowHeight, screenTop,safeArea, model, pixelRatio = 2 } = this.systemInfo; // 计算安全区域 const statusBarHeight = safeArea ? safeArea.top : 44; const safeAreaBottom = safeArea ? ((windowHeight > safeArea.bottom) ? windowHeight - safeArea.bottom : 0) : 0; // 计算胶囊按钮信息(兜底处理) let menuButtonInfo = { height: 32, top: 6, width: 87, right: 281 }; try { menuButtonInfo = wx.getMenuButtonBoundingClientRect(); } catch (error) { console.warn('获取胶囊按钮信息失败,使用默认值 :', error); } const menuButtonHeight = menuButtonInfo.height; const menuButtonTop = menuButtonInfo.top - statusBarHeight; const targetModels = ['windows', 'huawei', 'nexus', 'mac']; const lowerModel = model.toLocaleLowerCase(); const isTargetModel = targetModels.some(keyword => lowerModel.includes(keyword)); const navBarHeight = isTargetModel ? (menuButtonInfo.bottom + menuButtonTop):(menuButtonInfo.bottom + menuButtonTop*2); // 计算可用高度(解决滚动条问题的关键) const usableHeight = windowHeight; const contentHeight = usableHeight - statusBarHeight - safeAreaBottom; // 设备类型判断 const deviceType = this.detectDeviceType(windowWidth, windowHeight); this.adaptationInfo = { // 基础信息 windowWidth, windowHeight: deviceType.toLocaleLowerCase().includes('iPad') ? windowHeight : contentHeight, pixelRatio, screenHeight, // 安全区域 statusBarHeight, safeAreaBottom, safeAreaTop: statusBarHeight, // safeAreaLeft: safeArea ? safeArea.left : 0, // safeAreaRight: safeArea ? (windowWidth - safeArea.right) : 0, // safeTop: model === 'Windows' ? navBarHeight : 0, screenTop, // centerOffset: windowWidth <= 430 ? 0 : (windowWidth - 430) / 2, // 导航栏信息 navBarHeight, menuButtonHeight, menuButtonTop, menuButtonInfo, // 可用区域(解决滚动条的关键) usableHeight, contentHeight, // 设备信息 deviceType, platform: this.systemInfo.platform, // CSS变量(用于动态设置样式) cssVars: { '--window-height': windowHeight + 'px', '--window-width': windowWidth + 'px', '--status-bar-height': statusBarHeight + 'px', '--nav-bar-height': navBarHeight + 'px', '--safe-area-bottom': safeAreaBottom + 'px', '--content-height': contentHeight + 'px', '--usable-height': usableHeight + 'px' } }; } // 检测设备类型 detectDeviceType(width, height) { // iPhone SE系列 if (width <= 375 && height <= 667) { return 'iphone-se'; } // iPhone 12/13/14系列 else if (width <= 390 && height >= 844) { return 'iphone-standard'; } // iPhone 12/13/14/15 Pro Max系列 else if (width <= 430 && height >= 926) { return 'iphone-max'; } // iPad系列 else if (width >= 768) { return 'ipad'; } // Android大屏 else if (height >= 800) { return 'android-large'; } // 其他设备 else { return 'unknown'; } } // 使用默认值 useDefaultValues() { this.adaptationInfo = { windowWidth: 375, windowHeight: 667, pixelRatio: 2, statusBarHeight: 44, safeAreaBottom: 0, safeAreaTop: 44, safeAreaLeft: 0, safeAreaRight: 0, navBarHeight: 88, menuButtonHeight: 32, menuButtonTop: 6, usableHeight: 667, contentHeight: 623, deviceType: 'unknown', platform: 'unknown', cssVars: { '--window-height': '667px', '--window-width': '375px', '--status-bar-height': '44px', '--nav-bar-height': '88px', '--safe-area-bottom': '0px', '--content-height': '623px', '--usable-height': '667px' } }; this.isInitialized = true; } // 获取适配信息 getAdaptationInfo() { if (!this.isInitialized) { console.warn('屏幕适配器未初始化,返回默认值'); this.useDefaultValues(); } return this.adaptationInfo; } // 为页面设置适配样式(解决滚动条的核心方法) applyToPage(pageInstance) { if (!pageInstance) { console.error('页面实例为空'); return; } try { const info = this.getAdaptationInfo(); console.log('应用适配信息到页面:', info); // 🔥 设置页面数据 - 使用Object.assign替代扩展运算符 pageInstance.setData(Object.assign({}, info, { // 兼容旧版本的字段名 windowHeight: info.windowHeight, windowWidth: info.windowWidth, statusBarHeight: info.statusBarHeight, navBarHeight: info.navBarHeight, safeAreaBottom: info.safeAreaBottom, menuButtonHeight: info.menuButtonHeight, menuButtonTop: info.menuButtonTop })); } catch (error) { console.error('应用适配信息到页面失败:', error); // 不抛出错误,避免影响页面加载 } } // 应用CSS变量 applyCSSVars() { if (!this.adaptationInfo.cssVars) return; try { // 在小程序中,我们通过设置页面数据来传递这些值 // CSS变量将通过页面数据在WXML中使用 const pages = getCurrentPages(); const currentPage = pages[pages.length - 1]; if (currentPage) { currentPage.setData({ screenCSSVars: this.adaptationInfo.cssVars }); } } catch (error) { console.error('应用CSS变量失败:', error); } } // 监听窗口大小变化(横竖屏切换等) onWindowResize(callback) { wx.onWindowResize((res) => { // 重新计算适配信息 this.systemInfo.windowWidth = res.size.windowWidth; this.systemInfo.windowHeight = res.size.windowHeight; this.calculateAdaptation(); if (callback && typeof callback === 'function') { callback(this.adaptationInfo); } }); } // 获取推荐的页面配置 getPageConfig() { return { // 禁用页面滚动,防止出现滚动条 disableScroll: true, // 背景色 backgroundColor: '#f8f9fa', // 导航栏样式 navigationBarBackgroundColor: '#667eea', navigationBarTextStyle: 'white' }; } } // 创建全局实例 const screenAdapter = new ScreenAdapter(); // 便捷方法 async function init(self) { try { await screenAdapter.init(); screenAdapter.applyToPage(self); // onWindowResize 是监听器,不需要 await screenAdapter.onWindowResize(() => { try { screenAdapter.applyToPage(self); } catch (error) { console.error('窗口大小变化时应用适配信息失败:', error); } }); } catch (error) { console.error('初始化屏幕信息出错了', error); // 即使初始化失败,也尝试应用默认值 try { screenAdapter.applyToPage(self); } catch (e) { console.error('应用默认适配信息失败:', e); } } } // 导出实例和类 module.exports = { init };