架构设计之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的构建配置实现最优打包策略。

相关推荐
Lingxing7 分钟前
深入浅出:从JS的new运算符到手写ES5/ES6版实现
前端·javascript·ecmascript 6
用户91858244797310 分钟前
关于vue中的scoped
前端
木木黄木木15 分钟前
炫酷的3D按钮效果实现 - CSS3高级特性应用
前端·3d·css3
木木黄木木19 分钟前
html5基于Canvas的经典打砖块游戏开发实践
前端·html·html5
顾言71619 分钟前
uniapp 和 webview 之间的通信
前端
bin915329 分钟前
DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例7,TableView15_07带边框和斑马纹的导出表格示例
前端·javascript·vue.js·ecmascript·deepseek
木木黄木木1 小时前
html5炫酷3D立体文字效果实现详解
前端·3d·html5
我认不到你1 小时前
油候插件、idea、VsCode插件推荐(自用)
java·前端·vscode·react.js·typescript·编辑器·intellij-idea
Mr_sun.1 小时前
Day20-前端Web案例——部门管理
前端
烂蜻蜓1 小时前
巧用 VSCode 开启 Vue 开发之旅
ide·vue.js·vscode