feat: 一体机适配
This commit is contained in:
297
stores/useScreenStore.js
Normal file
297
stores/useScreenStore.js
Normal file
@@ -0,0 +1,297 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
// 屏幕检测管理器类
|
||||
class ScreenDetectionManager {
|
||||
constructor() {
|
||||
this.WIDE_SCREEN_CSS_ID = 'wide-screen-css';
|
||||
this.WIDE_SCREEN_CSS_PATH = '../common/wide-screen.css';
|
||||
this.resizeTimer = null;
|
||||
this.resizeListeners = [];
|
||||
this.cssLink = null;
|
||||
}
|
||||
|
||||
// 获取屏幕宽度
|
||||
getScreenWidth() {
|
||||
if (typeof window === 'undefined') return 0;
|
||||
|
||||
// 优先使用 uni.getSystemInfo
|
||||
if (typeof uni !== 'undefined' && uni.getSystemInfo) {
|
||||
return new Promise((resolve) => {
|
||||
uni.getSystemInfo({
|
||||
success: (res) => {
|
||||
const width = res.screenWidth || res.windowWidth || window.innerWidth;
|
||||
resolve(width);
|
||||
},
|
||||
fail: () => {
|
||||
resolve(this.getWindowWidth());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(this.getWindowWidth());
|
||||
}
|
||||
|
||||
// 备用方案:使用 window 对象
|
||||
getWindowWidth() {
|
||||
if (typeof window === 'undefined') return 0;
|
||||
return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||
}
|
||||
|
||||
// 检测折叠屏
|
||||
checkVisualViewport() {
|
||||
if (window.visualViewport?.segments?.length > 1) {
|
||||
return {
|
||||
foldable: true,
|
||||
count: window.visualViewport.segments.length - 1
|
||||
}
|
||||
}
|
||||
else {
|
||||
return {
|
||||
foldable: false,
|
||||
count: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 动态加载 CSS
|
||||
loadWideScreenCSS() {
|
||||
if (typeof window === 'undefined' || this.cssLink) return null;
|
||||
|
||||
try {
|
||||
this.cssLink = document.createElement('link');
|
||||
this.cssLink.id = this.WIDE_SCREEN_CSS_ID;
|
||||
this.cssLink.rel = 'stylesheet';
|
||||
this.cssLink.href = this.WIDE_SCREEN_CSS_PATH;
|
||||
|
||||
// 添加加载成功/失败监听
|
||||
this.cssLink.onload = () => {
|
||||
console.log('🎨 宽屏 CSS 文件加载成功');
|
||||
};
|
||||
|
||||
this.cssLink.onerror = () => {
|
||||
console.error('❌ 宽屏 CSS 文件加载失败');
|
||||
this.cssLink = null;
|
||||
};
|
||||
|
||||
document.head.appendChild(this.cssLink);
|
||||
return this.cssLink;
|
||||
} catch (error) {
|
||||
console.error('加载 CSS 失败:', error);
|
||||
this.cssLink = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除 CSS
|
||||
removeWideScreenCSS() {
|
||||
if (this.cssLink && this.cssLink.parentNode) {
|
||||
try {
|
||||
this.cssLink.parentNode.removeChild(this.cssLink);
|
||||
this.cssLink = null;
|
||||
console.log('🗑️ 宽屏 CSS 文件已移除');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('移除 CSS 失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新 CSS 状态
|
||||
updateWideScreenCSS(isWideScreen) {
|
||||
if (isWideScreen) {
|
||||
return this.loadWideScreenCSS();
|
||||
} else {
|
||||
return this.removeWideScreenCSS();
|
||||
}
|
||||
}
|
||||
//显示/隐藏默认tabbar
|
||||
updateTabbar(isWideScreen){
|
||||
if(isWideScreen) uni.hideTabBar()
|
||||
else uni.showTabBar()
|
||||
}
|
||||
|
||||
// 添加 resize 监听器
|
||||
addResizeListener(callback, delay = 250) {
|
||||
if (typeof window === 'undefined') return () => {};
|
||||
|
||||
const handler = () => {
|
||||
clearTimeout(this.resizeTimer);
|
||||
this.resizeTimer = setTimeout(() => {
|
||||
callback();
|
||||
}, delay);
|
||||
};
|
||||
|
||||
window.addEventListener('resize', handler);
|
||||
this.resizeListeners.push({ callback, handler });
|
||||
|
||||
// 返回清理函数
|
||||
return () => this.removeResizeListener(callback);
|
||||
}
|
||||
|
||||
// 移除 resize 监听器
|
||||
removeResizeListener(callback) {
|
||||
const index = this.resizeListeners.findIndex(item => item.callback === callback);
|
||||
if (index > -1) {
|
||||
const { handler } = this.resizeListeners[index];
|
||||
window.removeEventListener('resize', handler);
|
||||
this.resizeListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 创建屏幕状态 store
|
||||
const useScreenStore = defineStore('screen', () => {
|
||||
// 状态
|
||||
const screenWidth = ref(0);
|
||||
const isInitialized = ref(false);
|
||||
const isLoading = ref(false);
|
||||
const foldFeature = ref(false);
|
||||
const foldCount = ref(0);
|
||||
|
||||
|
||||
const isWideScreen = computed(() => {
|
||||
return screenWidth.value > 1080;
|
||||
});
|
||||
|
||||
// 添加屏幕分类的计算属性
|
||||
const screenCategory = computed(() => {
|
||||
const width = screenWidth.value;
|
||||
if (width <= 768) return 'mobile';
|
||||
if (width <= 1024) return 'tablet';
|
||||
if (width <= 1440) return 'desktop';
|
||||
return 'ultra-wide';
|
||||
});
|
||||
|
||||
// 添加更多响应式计算属性
|
||||
const isMobile = computed(() => screenCategory.value === 'mobile');
|
||||
const isTablet = computed(() => screenCategory.value === 'tablet');
|
||||
const isDesktop = computed(() => screenCategory.value === 'desktop' || screenCategory.value === 'ultra-wide');
|
||||
|
||||
// 管理器实例
|
||||
const manager = new ScreenDetectionManager();
|
||||
|
||||
// 初始化屏幕检测
|
||||
const initScreenDetection = async () => {
|
||||
if (isLoading.value || isInitialized.value) return;
|
||||
isLoading.value = true;
|
||||
try {
|
||||
// 检测屏幕状态
|
||||
const width = await manager.getScreenWidth();
|
||||
const { foldable, count } = manager.checkVisualViewport();
|
||||
|
||||
foldFeature.value = foldable;
|
||||
foldCount.value = count;
|
||||
screenWidth.value = width;
|
||||
isInitialized.value = true;
|
||||
|
||||
console.log(`📱 屏幕检测完成: ${width}px, 宽屏: ${isWideScreen.value}`);
|
||||
console.log(`是否为折叠屏: ${foldFeature.value},折叠屏数量:${foldCount.value}`);
|
||||
|
||||
// 根据状态加载或移除 CSS
|
||||
manager.updateWideScreenCSS(isWideScreen.value);
|
||||
manager.updateTabbar(isWideScreen.value);
|
||||
|
||||
// 设置 resize 监听
|
||||
setupResizeListener();
|
||||
return {
|
||||
screenWidth: width,
|
||||
isWideScreen: isWideScreen.value,
|
||||
foldable,
|
||||
count
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('初始化屏幕检测失败:', error);
|
||||
return null;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 手动更新屏幕状态
|
||||
const updateScreenStatus = async () => {
|
||||
try {
|
||||
const width = await manager.getScreenWidth();
|
||||
const { foldable, count } = manager.checkVisualViewport();
|
||||
|
||||
// 保存旧状态
|
||||
const oldWidth = screenWidth.value;
|
||||
const oldIsWideScreen = isWideScreen.value;
|
||||
const oldFoldable = foldFeature.value;
|
||||
const oldFoldCount = foldCount.value;
|
||||
|
||||
// 更新状态
|
||||
screenWidth.value = width;
|
||||
foldFeature.value = foldable;
|
||||
foldCount.value = count;
|
||||
|
||||
// 检查宽屏状态是否发生变化
|
||||
if (oldIsWideScreen !== isWideScreen.value) {
|
||||
console.log(`🔄 屏幕状态变化: ${oldIsWideScreen ? '宽屏' : '非宽屏'} -> ${isWideScreen.value ? '宽屏' : '非宽屏'}`);
|
||||
console.log(`屏幕宽度变化: ${oldWidth}px -> ${width}px`);
|
||||
manager.updateWideScreenCSS(isWideScreen.value);
|
||||
manager.updateTabbar(isWideScreen.value);
|
||||
}
|
||||
|
||||
// 检查折叠屏状态是否发生变化
|
||||
if (oldFoldable !== foldable || oldFoldCount !== count) {
|
||||
console.log(`折叠屏状态变化: ${oldFoldable ? '是' : '否'}->${foldable ? '是' : '否'}, 折叠数: ${oldFoldCount}->${count}`);
|
||||
}
|
||||
|
||||
return {
|
||||
screenWidth: width,
|
||||
isWideScreen: isWideScreen.value,
|
||||
foldable,
|
||||
count
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('更新屏幕状态失败:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// 设置 resize 监听
|
||||
let cleanupResizeListener = () => {};
|
||||
const setupResizeListener = () => {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
cleanupResizeListener = manager.addResizeListener(async () => {
|
||||
await updateScreenStatus();
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// 手动触发屏幕检测
|
||||
const detectScreen = () => {
|
||||
return updateScreenStatus();
|
||||
};
|
||||
|
||||
|
||||
|
||||
return {
|
||||
// 状态
|
||||
foldFeature,
|
||||
foldCount,
|
||||
screenWidth,
|
||||
isInitialized,
|
||||
isLoading,
|
||||
|
||||
// 响应式计算属性
|
||||
isWideScreen,
|
||||
screenCategory,
|
||||
isMobile,
|
||||
isTablet,
|
||||
isDesktop,
|
||||
|
||||
// 方法
|
||||
initScreenDetection,
|
||||
updateScreenStatus,
|
||||
detectScreen,
|
||||
};
|
||||
});
|
||||
|
||||
export default useScreenStore;
|
||||
Reference in New Issue
Block a user