// 屏幕适配工具类 - 解决小程序滚动条问题 // 基于2024年最新的微信小程序最佳实践 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; console.log('屏幕适配器初始化成功:', this.adaptationInfo); return this.adaptationInfo; } catch (error) { console.error('屏幕适配器初始化失败:', error); // 使用兜底方案 this.fallbackInit(); return this.adaptationInfo; } } // 获取窗口信息(新API) getWindowInfo() { return new Promise((resolve) => { try { const windowInfo = wx.getWindowInfo(); resolve(windowInfo); } catch (error) { console.warn('getWindowInfo失败,使用兜底方案:', error); resolve({ windowWidth: 375, windowHeight: 667, pixelRatio: 2, safeArea: { top: 44, bottom: 0, left: 0, right: 375 } }); } }); } // 获取设备信息(新API) getDeviceInfo() { return new Promise((resolve) => { try { const deviceInfo = wx.getDeviceInfo(); resolve(deviceInfo); } catch (error) { console.warn('getDeviceInfo失败,使用兜底方案:', error); resolve({ platform: 'unknown', system: 'unknown', model: 'unknown' }); } }); } // 获取应用基础信息(新API) getAppBaseInfo() { return new Promise((resolve) => { try { const appBaseInfo = wx.getAppBaseInfo(); resolve(appBaseInfo); } catch (error) { console.warn('getAppBaseInfo失败,使用兜底方案:', error); resolve({ version: '1.0.0', language: 'zh_CN' }); } }); } // 兜底初始化 fallbackInit() { try { this.systemInfo = wx.getSystemInfoSync(); this.calculateAdaptation(); this.isInitialized = true; } catch (error) { console.error('兜底初始化也失败,使用硬编码默认值:', error); this.useDefaultValues(); } } // 计算适配信息 calculateAdaptation() { const { windowWidth, windowHeight, safeArea, pixelRatio = 2 } = this.systemInfo; // 计算安全区域 const statusBarHeight = safeArea ? safeArea.top : 44; const safeAreaBottom = safeArea ? (windowHeight - safeArea.bottom) : 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 navBarHeight = statusBarHeight + menuButtonHeight + menuButtonTop * 2; // 计算可用高度(解决滚动条问题的关键) const usableHeight = windowHeight; const contentHeight = usableHeight - statusBarHeight - safeAreaBottom; // 设备类型判断 const deviceType = this.detectDeviceType(windowWidth, windowHeight); this.adaptationInfo = { // 基础信息 windowWidth, windowHeight, pixelRatio, // 安全区域 statusBarHeight, safeAreaBottom, safeAreaTop: statusBarHeight, safeAreaLeft: safeArea ? safeArea.left : 0, safeAreaRight: safeArea ? (windowWidth - safeArea.right) : 0, // 导航栏信息 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 Pro Max系列 else if (width <= 428 && 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; } const info = this.getAdaptationInfo(); // 🔥 设置页面数据 - 使用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 })); // 应用CSS变量到页面 this.applyCSSVars(); console.log('页面适配应用成功:', pageInstance.route || 'unknown'); } // 应用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) => { console.log('窗口大小变化:', 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(); // 导出实例和类 module.exports = { ScreenAdapter, screenAdapter, // 便捷方法 async init() { return await screenAdapter.init(); }, getAdaptationInfo() { return screenAdapter.getAdaptationInfo(); }, applyToPage(pageInstance) { return screenAdapter.applyToPage(pageInstance); }, onWindowResize(callback) { return screenAdapter.onWindowResize(callback); }, getPageConfig() { return screenAdapter.getPageConfig(); } };