基于Vue的跨移动端和PC端适应

18,757

需求

开发一个平台,要求在PC端和移动端上都有较好的体验。


思路

做到移动端和PC端同时适配,一般有两个大思路:

  1. 一套资源,根据判断是否是移动设备而选择加载不同的css。
  2. 两套资源,pc和mobile各一套,分开维护,在入口处进入不同的路由。

两种方式的差别体现在,前者是样式层面分为pc和mobile,后者是页面分为pc和mobile


两个做法各自的特点:
1.前者适用于两端交互和布局差别不大,交互比较简单的项目。只有一套资源,代码量少,维护起来比较简单。
2.后者则适用于两端交互方式和布局差别大,对设计要求高,拓展性要求高的项目。两套资源,代码量大,前期配置比较复杂,但是两端不相互影响,开发起来不用考虑太多。


解决方案

一套资源方案

由于目前项目要求快速开发快速落地,且两端设计稿布局差距不大。所以采用了第一种方式。实现如下:

步骤

1.判断终端设备类型。

main.js中配置,在页面加载前,判断终端设备类型。

navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)

2.拆分两套css文件。

pc采用px为单位,mobile采用rem和vw结合,并在mobile的css文件中,设置项目font-size,例如设计稿为375px的情况下,html {font-size: calc(100vw/37.5)}这时候,当移动设备可视窗口大小为375px时,html的font-size为10px,则1rem=10px。

styles结构如下:将css拆分为pc和mobile两套,每个开发人员都有自己的两套css文件。

image.png

// mobile.scss
@import './mobile/hm-mobile.scss';
@import './mobile/tf-mobile.scss';

.no-mobile {
  display: none;
}
html {
  font-size: calc(100vw/37.5);
}

// pc.scss
@import './pc/hm-pc.scss';
@import './pc/tf-pc.scss';
.no-pc {
  display: none;
}

3.加载两套css文件

通过判断终端类型,加载不同的css文件,

// main.js配置
import { _isMobile } from '@/utils/utils';
...
...
...
if (_isMobile()) {
  require('./styles/mobile.scss');
  console.log('mobile');
} else {
  console.log('pc');
  require('./styles/pc.scss');
}

需****格外注意的是,样式都写在了全局的样式文件里,在多人协同开发时,需要强调命名规范,以防命名污染,可以参考**BEM命名规范    **

为什么不使用媒体查询,靠一套CSS同时搞定PC和移动端? 作者考虑到同一套CSS会使得耦合性太高,后期两端维护起来很麻烦,并且若两端项目都要拆分起来成本增加。因此,可以在两套CSS的前提下,针对其中一端,进行响应式实现,比如针对PC端可做大中小屏的响应式,而不是直接从pc横跨到移动端的响应式。

两套资源方案

基于两套资源的思想,具体怎么实现其实有很多方法,

  1. 来自网友(配置两端分开)
  2. 这几天自己做项目使用的一套方案:


核心是通过两套资源+判断客户端类型+路由守卫进行的

步骤

1.限制路由的规范(路由守卫的依据)

  • 设置meta的type属性为pc或mobile,path规范为,pc由p_开头,移动由m_开头。
    image.png
  • 根路由采用重定位,分别指向移动端和PC端的路由,具体走哪边,由终端类型决定。
    image.png

    image.png
  • 采用按需加载的方式。

2.路由守卫

通过meta的type来对跳转的页面进行拦截,防止直接输入网址造成的跨端访问,当进行跨端访问时,强制拦截,跳转到属于本端类型的相同页面。比如当用手机访问p_index时,跳转到m_index,因此不但meta要设置,两端的页面路由也要保证有一定的规律。这里可做可不做,可以只是拦截跳转到本端首页就可以了。

image.png

3.按端类型动态添加网页meta和使用三方插件

// main.js
if (/Android|webOS|iPhone|iPod|BlackBerry|iPad/i.test(navigator.userAgent)) {
  Vue.use(VueTouch, { name: 'v-touch' });
  VueTouch.config.swipe = {
    threshold: 50
  };
  var oMeta = document.createElement('meta');
  oMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0, user-scalable=0';
  oMeta.name = 'viewport';
  document.getElementsByTagName('head')[0].appendChild(oMeta);
}

4.postcss-pxtorem排除影响

由于项目需要,pc和移动都使用rem开发,都使用了px转rem的插件,但px转rem的转换基数在两端是不同的,需要排除两端的相互影响。

//vue.config.js
const config = {
  // ...
  css: {
    extract: true,
    loaderOptions: {
      postcss: {
        plugins: [
          require('postcss-pxtorem')({
            rootValue: 192,
            exclude: /node_modules\/vant|mobile/i, // 排除mobile和vant库
            propList: ['*'],
            selectorBlackList: ['.van-'] // 排除移动端使用了vant库
          }),
          require('postcss-pxtorem')({
            rootValue: 37.5,
            exclude: 'pc', // 排除pc
            propList: ['*']
          })
        ]
      }
    }
  }
};

module.exports = config;