架构设计之pc和手机应用适配方案

业务背景

领导想使用同一个链接,实现pc打开是web应用,手机打开是一个H5应用

解决方案

以下是基于Vue和Node.js的混合策略详细实现方案,结合服务端设备识别与前端动态适配:

架构设计

bash 复制代码
项目结构
├── server/                  # Node.js服务端
│   ├── middleware/
│   │   └── deviceDetect.js # 设备检测中间件
│   └── server.js           # 主服务
├── src/                    # Vue前端
│   ├── layouts/
│   │   ├── Mobile.vue      # 移动端布局
│   │   └── Desktop.vue    # PC端布局
│   ├── router/
│   │   └── dynamicRoutes.js # 动态路由
│   ├── App.vue
│   └── main.js
└── 其他标准Vue项目结构

分步实现

一、服务端设备检测(Node.js)

ini 复制代码
// server/middleware/deviceDetect.js
const mobileDetect = (req, res, next) => {
  const ua = req.headers['user-agent'];
  
  // 使用正则检测常见移动设备
  const isMobile = /Mobile|Android|iP(hone|od)|IEMobile|BlackBerry/.test(ua);
  
  // 将设备类型注入请求对象
  req.deviceType = isMobile ? 'mobile' : 'desktop';
  next();
};

module.exports = mobileDetect;

二、Express服务配置

ini 复制代码
// server/server.js
const express = require('express');
const path = require('path');
const deviceDetect = require('./middleware/deviceDetect');
const app = express();

// 使用设备检测中间件
app.use(deviceDetect);

// 注入设备类型到HTML模板
app.get('/', (req, res) => {
  const template = `
  <!DOCTYPE html>
  <html>
    <head>
      <title>混合适配示例</title>
      <script>
        window.__DEVICE_TYPE__ = '${req.deviceType}'; // 注入设备类型
      </script>
    </head>
    <body>
      <div id="app"></div>
      <script src="/dist/build.js"></script>
    </body>
  </html>
  `;
  
  res.send(template);
});

// 静态资源托管
app.use(express.static(path.join(__dirname, '../dist')));

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

三、Vue前端动态适配

xml 复制代码
<!-- src/App.vue -->
<template>
  <div id="app">
    <component :is="currentLayout">
      <router-view/>
    </component>
  </div>
</template>

<script>
export default {
  computed: {
    currentLayout() {
      return this.$store.state.deviceType === 'mobile' 
        ? 'MobileLayout' 
        : 'DesktopLayout';
    }
  },
  created() {
    // 初始化设备类型
    this.$store.commit('SET_DEVICE_TYPE', window.__DEVICE_TYPE__);
    
    // 添加窗口监听实现响应式切换
    window.addEventListener('resize', this.handleResize);
  },
  methods: {
    handleResize() {
      const isMobile = window.innerWidth <= 768;
      this.$store.commit('SET_DEVICE_TYPE', isMobile ? 'mobile' : 'desktop');
    }
  }
}
</script>

四、Vuex状态管理

typescript 复制代码
// src/store/index.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    deviceType: 'desktop' // 默认值
  },
  mutations: {
    SET_DEVICE_TYPE(state, type) {
      state.deviceType = type;
    }
  }
});

五、动态路由配置

ini 复制代码
// src/router/dynamicRoutes.js
export const createRoutes = (deviceType) => {
  const baseRoutes = [
    {
      path: '/',
      component: () => deviceType === 'mobile' 
        ? import('@/views/MobileHome.vue') 
        : import('@/views/DesktopHome.vue')
    }
  ];

  return deviceType === 'mobile' 
    ? [...baseRoutes, ...mobileSpecificRoutes]
    : [...baseRoutes, ...desktopSpecificRoutes];
};

六、响应式布局组件

xml 复制代码
<!-- src/layouts/Mobile.vue -->
<template>
  <div class="mobile-layout">
    <nav-bar position="bottom"/>
    <transition name="slide">
      <keep-alive>
        <router-view/>
      </keep-alive>
    </transition>
  </div>
</template>

<style scoped>
.mobile-layout {
  max-width: 768px;
  margin: 0 auto;
}
</style>
xml 复制代码
<!-- src/layouts/Desktop.vue -->
<template>
  <div class="desktop-layout">
    <side-bar/>
    <main-content>
      <router-view/>
    </main-content>
  </div>
</template>

增强功能实现

1. 设备类型同步策略

scss 复制代码
// 在路由跳转时保持设备标识
router.beforeEach((to, from, next) => {
  if (to.query.deviceType) {
    store.commit('SET_DEVICE_TYPE', to.query.deviceType);
  }
  next();
});

2. 混合检测策略

javascript 复制代码
// 综合检测方法
function getDeviceType() {
  // 服务端注入的优先级最高
  if (window.__DEVICE_TYPE__) return window.__DEVICE_TYPE__;
  
  // 前端补充检测
  return window.innerWidth <= 768 || 'ontouchstart' in window 
    ? 'mobile' 
    : 'desktop';
}

3. 按需加载优化

less 复制代码
// 动态加载组件优化
Vue.component('AsyncComponent', () => ({
  component: import(`@/components/${store.state.deviceType}/Component.vue`),
  loading: LoadingComponent,
  delay: 200
}));

部署配置

Nginx层设备识别(可选)

bash 复制代码
server {
  listen 80;
  
  location / {
    # 设备识别前置处理
    if ($http_user_agent ~* '(mobile|android|iphone)') {
      set $device_type 'mobile';
    }
    
    proxy_set_header X-Device-Type $device_type;
    proxy_pass http://localhost:3000;
  }
}

测试方案

  1. 设备模拟测试
scss 复制代码
// 使用Jest测试不同设备类型
describe('设备适配测试', () => {
  test('移动端布局渲染', () => {
    store.commit('SET_DEVICE_TYPE', 'mobile');
    const wrapper = mount(App);
    expect(wrapper.find('.mobile-layout').exists()).toBe(true);
  });
});
  1. 端到端测试
dart 复制代码
// 使用Cypress进行真实设备测试
describe('端到端测试', () => {
  it('在移动设备显示正确布局', () => {
    cy.viewport('iphone-x')
      .visit('/')
      .get('.mobile-nav').should('be.visible');
  });
});

优化建议

  1. 缓存策略
arduino 复制代码
// 服务端添加Vary头
res.setHeader('Vary', 'User-Agent');
  1. 渐进增强
xml 复制代码
<!-- 核心内容直出 -->
<noscript>
  <div class="core-content">
    <!-- 基础HTML内容 -->
  </div>
</noscript>
  1. 性能监控
javascript 复制代码
// 添加设备类型到性能统计
window.performance.mark('deviceType', store.state.deviceType);

这种混合方案实现了:

  • 首屏服务端精准设备识别
  • 前端动态响应式适配
  • 代码逻辑与UI的分离维护
  • SEO友好性
  • 平滑的过渡动画
  • 设备类型状态同步

可根据实际需求选择在服务端渲染(SSR)或客户端渲染(CSR)模式下使用,建议搭配Vue CLI的构建配置实现最优打包策略。

相关推荐
怕浪猫5 小时前
FDE 如何正确解决现场项目工程性的问题
前端·后端·ai编程
西瓜太郎12345 小时前
外层模型卡片与分组详情成功率不一致,应该怎么排查?
前端·typescript·go·软件工程·react
GreenTea5 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
毕业设计7038 小时前
(免费领源码) 基于微信小程序的预制菜商城的设计与实现25172-java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
vue.js·python·mysql·微信小程序·pycharm·微信开发者工具·推荐算法
xifangge20258 小时前
AGENTS.md 怎么写?涵盖 Java、Python、Vue、Go 的 8 套开箱即用模板
java·vue.js·python
几何心凉8 小时前
没有万能模型:我用 AiiOnly Token Plan,把多款大模型的长处拼进同一个项目
前端
kyriewen8 小时前
Claude Code 的额度今天缩水了17%——官方公告上写的是"永久提高25%"
前端·ai编程·claude
雪芽蓝域zzs9 小时前
vue解构平铺VS对象包裹
前端·javascript·vue.js
风骏时光牛马10 小时前
从零到实战,完整AI学习路线
前端
三十而立洋10 小时前
深入理解 Monorepo:子包安装依赖
前端·前端工程化