feat(mobile): add device detection composable and placeholder view
This commit is contained in:
@@ -0,0 +1,51 @@
|
|||||||
|
// src/mobile/useDevice.ts
|
||||||
|
// 设备检测:判断当前是否移动端,结果存 localStorage 避免重复检测
|
||||||
|
|
||||||
|
const STORAGE_KEY = 'device_mode'
|
||||||
|
|
||||||
|
/** UA 关键字匹配移动设备 */
|
||||||
|
const MOBILE_UA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
|
||||||
|
|
||||||
|
/** 屏幕宽度阈值(含平板竖屏) */
|
||||||
|
const MOBILE_WIDTH = 768
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原始检测:综合 UA 和屏幕宽度判断
|
||||||
|
* - UA 命中移动设备关键字 → 手机
|
||||||
|
* - 屏宽 <= 768 → 手机
|
||||||
|
* - 否则 → 桌面
|
||||||
|
*/
|
||||||
|
function detectRaw(): 'mobile' | 'desktop' {
|
||||||
|
if (typeof navigator === 'undefined') return 'desktop'
|
||||||
|
if (MOBILE_UA.test(navigator.userAgent)) return 'mobile'
|
||||||
|
if (typeof window !== 'undefined' && window.innerWidth <= MOBILE_WIDTH) return 'mobile'
|
||||||
|
return 'desktop'
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 当前设备模式(读取 localStorage,无则检测并存入) */
|
||||||
|
export function getDeviceMode(): 'mobile' | 'desktop' {
|
||||||
|
if (typeof localStorage === 'undefined') return detectRaw()
|
||||||
|
const stored = localStorage.getItem(STORAGE_KEY)
|
||||||
|
if (stored === 'mobile' || stored === 'desktop') return stored
|
||||||
|
const detected = detectRaw()
|
||||||
|
localStorage.setItem(STORAGE_KEY, detected)
|
||||||
|
return detected
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 是否移动端(路由分流用,同步函数) */
|
||||||
|
export function isMobile(): boolean {
|
||||||
|
return getDeviceMode() === 'mobile'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动切换设备模式(设置页"切换到桌面版/手机版"用)
|
||||||
|
* 切换后需整页刷新以重新走路由解析
|
||||||
|
*/
|
||||||
|
export function setDeviceMode(mode: 'mobile' | 'desktop') {
|
||||||
|
localStorage.setItem(STORAGE_KEY, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置为自动检测(登出时调用,避免下个用户沿用上个用户的偏好) */
|
||||||
|
export function resetDeviceMode() {
|
||||||
|
localStorage.removeItem(STORAGE_KEY)
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<!-- src/views-mobile/Placeholder.vue -->
|
||||||
|
<!-- 占位页:手机端尚未实现的页面暂时显示此组件 -->
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="placeholder-page">
|
||||||
|
<van-empty description="该页面手机版开发中">
|
||||||
|
<p class="placeholder-hint">当前页面:{{ route.name }}</p>
|
||||||
|
</van-empty>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.placeholder-page {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 60vh;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-hint {
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--gg-text-muted);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user