以下是路由切换方案的完整代码实现,补充了之前省略的部分:
一、完整目录结构
plaintext
bash
src/
├── router/
│ ├── index.js # 主路由配置
│ ├── mobileRoutes.js # 移动端路由
│ └── pcRoutes.js # PC端路由
├── views/
│ ├── mobile/ # 移动端视图
│ │ ├── Home.vue
│ │ ├── Product.vue
│ │ └── Cart.vue
│ └── pc/ # PC端视图
│ ├── Home.vue
│ ├── Product.vue
│ └── Cart.vue
├── utils/
│ ├── device.js # 设备检测工具
│ └── storage.js # 本地存储工具
├── App.vue
└── main.js # 入口文件
二、核心文件实现
1. 设备检测工具(utils/device.js
)
javascript
javascript
// 检测设备类型
export function detectDevice() {
// 方案1: 通过User-Agent检测
const userAgent = navigator.userAgent.toLowerCase();
const isMobile = /mobile|android|iphone|ipad|phone/i.test(userAgent);
// 方案2: 通过屏幕尺寸检测(处理平板等特殊情况)
const isSmallScreen = window.innerWidth < 768;
return isMobile || isSmallScreen ? 'mobile' : 'pc';
}
// 监听屏幕变化
export function setupDeviceWatcher(callback) {
const updateDevice = () => {
const device = detectDevice();
callback(device);
};
window.addEventListener('resize', updateDevice);
updateDevice(); // 初始化检测
// 返回清理函数
return () => window.removeEventListener('resize', updateDevice);
}
2. 移动端路由(router/mobileRoutes.js
)
javascript
javascript
export const mobileRoutes = [
{
path: '/',
name: 'MobileHome',
component: () => import('@/views/mobile/Home.vue'),
meta: { device: 'mobile' }
},
{
path: '/product/:id',
name: 'MobileProduct',
component: () => import('@/views/mobile/Product.vue'),
meta: { device: 'mobile' }
},
{
path: '/cart',
name: 'MobileCart',
component: () => import('@/views/mobile/Cart.vue'),
meta: { device: 'mobile', requiresAuth: true }
},
{
path: '/login',
name: 'MobileLogin',
component: () => import('@/views/mobile/Login.vue'),
meta: { device: 'mobile' }
}
];
3. PC 端路由(router/pcRoutes.js
)
javascript
javascript
export const pcRoutes = [
{
path: '/',
name: 'PcHome',
component: () => import('@/views/pc/Home.vue'),
meta: { device: 'pc' }
},
{
path: '/product/:id',
name: 'PcProduct',
component: () => import('@/views/pc/Product.vue'),
meta: { device: 'pc' }
},
{
path: '/cart',
name: 'PcCart',
component: () => import('@/views/pc/Cart.vue'),
meta: { device: 'pc', requiresAuth: true }
},
{
path: '/login',
name: 'PcLogin',
component: () => import('@/views/pc/Login.vue'),
meta: { device: 'pc' }
}
];
4. 主路由配置(router/index.js
)
javascript
javascript
import { createRouter, createWebHistory } from 'vue-router';
import { mobileRoutes } from './mobileRoutes';
import { pcRoutes } from './pcRoutes';
import { detectDevice } from '@/utils/device';
// 创建基础路由(公共路由)
const commonRoutes = [
{
path: '/404',
name: 'NotFound',
component: () => import('@/views/NotFound.vue')
},
{
path: '/:pathMatch(.*)*',
redirect: '/404'
}
];
const router = createRouter({
history: createWebHistory(),
routes: commonRoutes // 初始只包含公共路由
});
// 初始化路由
export function initRouter() {
const device = detectDevice();
const routes = device === 'mobile' ? mobileRoutes : pcRoutes;
// 清空现有路由(保留commonRoutes)
router.matcher = createRouter({
history: createWebHistory(),
routes: commonRoutes
}).matcher;
// 添加设备专属路由
routes.forEach(route => {
router.addRoute(route);
});
return device;
}
// 路由守卫:防止设备与路由不匹配
router.beforeEach((to, from, next) => {
const currentDevice = detectDevice();
// 检查目标路由是否存在且匹配当前设备
const isRouteExists = router.getRoutes().some(
route => route.name === to.name
);
if (!isRouteExists) {
// 路由不存在,重定向到对应设备的首页
const homeRoute = currentDevice === 'mobile'
? { name: 'MobileHome' }
: { name: 'PcHome' };
next(homeRoute);
} else {
next();
}
});
export default router;
5. 入口文件(main.js
)
javascript
ini
import { createApp } from 'vue';
import App from './App.vue';
import router, { initRouter } from './router';
import { setupDeviceWatcher } from './utils/device';
// 初始化路由
const currentDevice = initRouter();
const app = createApp(App);
app.use(router);
app.mount('#app');
// 监听设备变化,必要时刷新页面
setupDeviceWatcher(newDevice => {
if (newDevice !== currentDevice) {
// 简单方案:刷新页面
window.location.reload();
// 高级方案:动态替换路由(需更复杂实现)
// initRouter();
// router.push({ name: newDevice === 'mobile' ? 'MobileHome' : 'PcHome' });
}
});
三、关键实现说明
1. 路由动态管理
- 初始化:在应用启动时根据设备类型加载对应路由
- 重置机制 :通过替换
router.matcher
彻底清除旧路由 - 守卫检查:确保用户不会访问与设备不匹配的路由
2. 设备检测策略
- 双重检测:结合 User-Agent 和屏幕尺寸
- 响应式监听:监听窗口变化,支持设备旋转时的路由更新
3. 组件实现示例(移动端首页)
vue
xml
<!-- views/mobile/Home.vue -->
<template>
<div class="mobile-home">
<!-- 移动端专属布局 -->
<header class="mobile-header">
<h1>移动版首页</h1>
<button @click="goToCart">购物车 ({{ cartCount }})</button>
</header>
<main class="mobile-content">
<ProductList :products="products" />
</main>
<footer class="mobile-footer">
<nav>
<a href="/">首页</a>
<a href="/category">分类</a>
<a href="/cart">购物车</a>
<a href="/profile">我的</a>
</nav>
</footer>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import ProductList from '@/components/mobile/ProductList.vue';
export default {
components: {
ProductList
},
setup() {
const cartCount = ref(0);
const products = ref([]);
onMounted(() => {
// 获取商品列表和购物车数据
fetchProducts();
updateCartCount();
});
const goToCart = () => {
router.push({ name: 'MobileCart' });
};
return {
cartCount,
products,
goToCart
};
}
};
</script>
四、补充说明
-
错误处理:
- 添加了 404 页面和路由不存在时的重定向逻辑
- 路由守卫确保用户不会访问与设备不匹配的页面
-
性能优化:
- 使用路由懒加载(
() => import(...)
)减少初始加载时间 - 设备类型检测结果可缓存到 localStorage 避免重复计算
- 使用路由懒加载(
-
用户体验:
-
提供了设备旋转时的处理方案(刷新页面或动态更新路由)
-
路由切换时可添加过渡动画减少白屏感
-
这个方案实现了严格的设备隔离,确保只有对应端的代码会被加载和执行,适合两端功能差异较大的应用场景。
很好,把组件切换也加进去,两者整理下再输出,做下对比
以下是基于 Vue 的路由切换 和组件切换两种适配方案的完整对比,包含目录结构、实现代码、优缺点分析:
一、路由切换方案
1. 目录结构
plaintext
bash
src/
├── router/
│ ├── index.js # 主路由配置
│ ├── mobileRoutes.js # 移动端路由
│ └── pcRoutes.js # PC端路由
├── views/
│ ├── mobile/ # 移动端视图
│ │ ├── Home.vue
│ │ └── Product.vue
│ └── pc/ # PC端视图
│ ├── Home.vue
│ └── Product.vue
├── utils/
│ ├── device.js # 设备检测工具
│ └── storage.js # 本地存储工具
└── main.js # 入口文件
2. 核心代码
javascript
javascript
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import { mobileRoutes } from './mobileRoutes'
import { pcRoutes } from './pcRoutes'
import { detectDevice } from '@/utils/device'
const router = createRouter({
history: createWebHistory(),
routes: [] // 动态加载
})
export function initRouter() {
const device = detectDevice()
const routes = device === 'mobile' ? mobileRoutes : pcRoutes
// 重置路由
router.matcher = createRouter({
history: createWebHistory()
}).matcher
routes.forEach(route => router.addRoute(route))
return device
}
// main.js
import { initRouter } from './router'
// 初始化前完成路由设置
initRouter()
createApp(App).use(router).mount('#app')
二、组件切换方案
1. 目录结构
plaintext
bash
src/
├── router/
│ └── index.js # 统一路由配置
├── views/
│ ├── Home.vue # 统一入口视图
│ └── Product.vue # 统一入口视图
├── components/
│ ├── DeviceDetector.vue # 设备检测组件
│ ├── mobile/ # 移动端组件
│ └── pc/ # PC端组件
├── utils/
│ └── device.js # 设备检测工具
└── main.js # 入口文件
2. 核心代码
javascript
javascript
// router/index.js
const routes = [
{
path: '/',
component: () => import('@/views/Home.vue')
},
{
path: '/product/:id',
component: () => import('@/views/Product.vue')
}
]
// DeviceDetector.vue
<template>
<component :is="currentComponent" />
</template>
<script>
import { defineComponent, ref, onMounted } from 'vue'
import { detectDevice } from '@/utils/device'
export default defineComponent({
props: {
mobileComponent: { type: Object, required: true },
pcComponent: { type: Object, required: true }
},
setup(props) {
const currentComponent = ref(null)
onMounted(() => {
const device = detectDevice()
currentComponent.value = device === 'mobile'
? props.mobileComponent
: props.pcComponent
})
return { currentComponent }
}
})
</script>
// views/Home.vue
<template>
<DeviceDetector
:mobileComponent="mobileHome"
:pcComponent="pcHome"
/>
</template>
<script>
import DeviceDetector from '@/components/DeviceDetector.vue'
import MobileHome from '@/components/mobile/Home.vue'
import PcHome from '@/components/pc/Home.vue'
export default {
components: {
DeviceDetector
},
setup() {
return {
mobileHome: MobileHome,
pcHome: PcHome
}
}
}
</script>
三、方案对比
维度 | 路由切换方案 | 组件切换方案 |
---|---|---|
核心逻辑 | 在路由初始化时决定加载哪套路由 | 在组件渲染时决定显示哪个子组件 |
切换时机 | 路由导航前(无组件渲染) | 组件挂载后(可能有短暂渲染) |
资源加载 | 仅加载当前设备所需资源 | 可能同时加载多端资源 |
用户体验 | 切换需刷新页面(有白屏) | 平滑切换(无感知) |
适用场景 | 两端功能差异大,需严格资源隔离 | 两端功能相似,仅 UI 布局不同 |