upload project
This commit is contained in:
commit
06961cae04
422 changed files with 110626 additions and 0 deletions
369
utils/screen-adapter.js
Normal file
369
utils/screen-adapter.js
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
//屏幕适配工具类 -解决小程序滚动条问题
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue