vue 项目rem适配不同尺寸

1,537 阅读2分钟

背景

  • 已有设备
  • ipad :1024*768
  • 安卓大屏:1920*1080
  • vue版本脚手架cli2.0
  • 已经开发了 ipad 版本,需要安卓大屏也兼容显示

问题

  • 默认按ipad尺寸开发,固定是px写死了。
  • 为了适配不同尺寸,使用了 viewport 页面压缩技术,把安卓大屏进行放大显示
  • 由于放大后,会导致部分 图片,按钮出现起毛,或模糊的情况

解决方案

思路

使用rem单位技术,动态设置 font-size达到不同设备的兼容。

具体流程

  • 使用postcss-pxtorem动态单位,把原有的ipad版本所有 px的单位,全都转为rem版本
  • 在构建的时候根据指定的宽度参数,一生成两个不同版本的rem项目
  • 通过首页的判断当前浏览器的宽度 ,动态设置html的 font-size,从而使rem动态解析对应的尺寸

缺点

  • 需要部署两套环境,为什么不能只搞一套呢?
  • 因为很多代码样式是直接写在了vue页面里面,不能通过不同的环境动态加载不同的css

集成rem流程

安装插件

npm i postcss-pxtorem -D

配置

  • 由于集成了 postcss,只需要配置.postcssrc.js .postcssrc.js
//.postcssrc.js 
//默认不设置
console.log("process.env.BUILD_DEVICE----",process.env.BUILD_DEVICE)
const deviceWidth = (process.env.BUILD_DEVICE == "bigScreen")?130:98
console.log("deviceWidth----",deviceWidth)
module.exports = {
  "plugins": {
    "postcss-import": {},
    "postcss-url": {},
    // to edit target browsers: use "browserslist" field in package.json
    "autoprefixer": {},
    //注意
    //安卓大屏使用的是 1092 * 1080,需要设置 130
    //注意装扮灵 尺寸为  1024*768,需要设置 98
    "postcss-pxtorem": {
      rootValue: deviceWidth,
      unitPrecision: 5,
      propList: ['*'],
      selectorBlackList: [],
      replace: true,
      mediaQuery: false,
      minPixelValue: 12,
    },
  }
}

package.json

//package.json
//项目启动添加 BUILD_DEVICE 设备类型 有ipad和bigScreen
 "build-dev": "cross-env RUN_TYPE=build BUILD_TYPE=dev BUILD_DEVICE=ipad npm run webpack-build", 
 "build-dev-bigScreen": "cross-env RUN_TYPE=build BUILD_TYPE=dev BUILD_DEVICE=bigScreen  npm run webpack-build",

webpack.base.conf.js //添加映射的参数

 plugins: [
    new webpack.DefinePlugin({
      'process.env.BUILD_DEVICE':JSON.stringify(process.env.BUILD_DEVICE),
    }),
  ],
  //这样才具体的业务代码 也可以正常访问 process.env.BUILD_DEVICE

使用flexible动态计算当前的rem对应的 font-size值

//rem.js
//每次页面放大缩小,加载都会重新计算对应的font-size,来影响对应rem值大小
(function flexible (window, document) {
    var docEl = document.documentElement
    var dpr = window.devicePixelRatio || 1
  
    // adjust body font size
    function setBodyFontSize () {
      if (document.body) {
        document.body.style.fontSize = (12 * dpr) + 'px'
      }
      else {
        document.addEventListener('DOMContentLoaded', setBodyFontSize)
      }
    }
    setBodyFontSize();
  
    // set 1rem = viewWidth / 10
    function setRemUnit () {
      var rem = docEl.clientWidth / 10
      docEl.style.fontSize = rem + 'px'
    }
  
    setRemUnit()
  
    // reset rem unit on page resize
    window.addEventListener('resize', setRemUnit)
    window.addEventListener('pageshow', function (e) {
      if (e.persisted) {
        setRemUnit()
      }
    })
  
    // detect 0.5px supports
    if (dpr >= 2) {
      var fakeBody = document.createElement('body')
      var testElement = document.createElement('div')
      testElement.style.border = '.5px solid transparent'
      fakeBody.appendChild(testElement)
      docEl.appendChild(fakeBody)
      if (testElement.offsetHeight === 1) {
        docEl.classList.add('hairlines')
      }
      docEl.removeChild(fakeBody)
    }
  }(window, document))

index.html 引入 rem.js

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <meta http-equiv="pragram" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
    <meta http-equiv="Expires" content="0">
    <title>XXXX</title>
  </head>
  <body>
    <div id="app"></div> 
    <script src="http://xxxxxxx:17280/commonJS/rem.js"></script>
  </body>
</html>