upload project

This commit is contained in:
unknown 2025-12-27 17:16:03 +08:00
commit 06961cae04
422 changed files with 110626 additions and 0 deletions

369
utils/screen-adapter.js Normal file
View 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
};