相关推荐recommended
Vue 移动端、PC 端适配
作者:mmseoamin日期:2023-11-30

        Vue 移动端、PC 端适配可以使用 lib-flexible、amfe-flexible、postcss-pxtorem、postcss-px2rem 和 postcss-px-to-viewport 这几个插件。

Vue 移动端、PC 端适配,Vue 移动端、PC 端适配,第1张

        lib-flexible 是淘宝手机前端开发团队开发出来的一个开源插件,会自动在 html 的 head 中添加一个 的标签,同时会自动设置 html 的 font-size 为屏幕宽度除以10。

        amfe-flexible 是 lib-flexible 的升级版本,使用 vw 作为布局单位,从底层根本上解决了不同尺寸屏幕的适配问题,因为每个屏幕的百分比是固定的、可预测、可控制的。

        postcss-pxtorem 和 postcss-px2rem 插件,用于将 px 单位转化为 rem。可以和 lib-flexible 搭配使用。

        postcss-px-to-viewport 插件用于将 px 单位转化为 vw, vh, vmin, vmax 单位。可以和 amfe-flexible 搭配使用。

移动端

方案1:lib-flexible & postcss-pxtorem

        1. 安装依赖 lib-flexible:

npm install lib-flexible --save

        2. 在 main.js 中导入依赖:

import 'lib-flexible/flexible'

        3、安装依赖 postcss-pxtorem:

npm install postcss-pxtorem@5.0.0 --save-dev

        4、配置 postcss-pxtorem:

Vue 移动端、PC 端适配,Vue 移动端、PC 端适配,第2张

        vue-cli2:在根目录中的 postcss.config.js (没有新建即可),添加如下代码:

module.exports = {
    plugins: {
    "postcss-pxtorem": {
      rootValue: 37.5, // lib-flexible 将屏幕分成10份(10rem),这里设置表示设计图宽度为10*37.5=375px
      unitPrecision: 5, // 保留rem小数点多少位
      propList: ['*', '!border'], // 存储将被转换的属性列表,'!font-size' 即不对字体进行rem转换
      selectorBlackList: ['.radius'], // 要忽略并保留为px的选择器,例如fs-xl类名,里面有关px的样式将不被转换,支持正则写法。
      replace: true,
      mediaQuery: false, //(布尔值)媒体查询( @media screen 之类的)中不生效
      minPixelValue: 4, // 设置要替换的最小像素值,px小于4的不会被转换
      exclude: /(node_module)/,  //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
    }
  }
}

        vue-cli3:在根目录中 vue.config.js (没有新建即可),添加如下代码:

module.exports = {
  css: {
    loaderOptions: {
      postcss: {
        plugins: [
          require('postcss-pxtorem')({
            rootValue: 37.5, // lib-flexible 将屏幕分成10份(10rem),这里设置表示设计图宽度为10*37.5=375px
            unitPrecision: 5,  // 保留rem小数点多少位
            propList: ['*', '!border'], // 存储将被转换的属性列表,'!font-size' 即不对字体进行rem转换
            selectorBlackList: ['.radius'], // 要忽略并保留为px的选择器,例如fs-xl类名,里面有关px的样式将不被转换,支持正则写法。
            replace: true,
            mediaQuery: false, //(布尔值)媒体查询( @media screen 之类的)中不生效
            minPixelValue: 4, // 设置要替换的最小像素值,px小于4的不会被转换
            exclude: /(node_module)/,  //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
          })
        ]
      }
    }
  }
}

        5、注意事项

  • 配置完成后注意删除掉 index.html 里的视窗 meta 标签 以便让 lib-flexible 插件帮你生成;
  • 如果某些 px 尺寸不想转换成 rem ,将 px大写即可。
    .box{
    	width:200Px;
    	height:200PX;
    }

    方案2:lib-flexible & postcss-px2rem

            1. 安装依赖 lib-flexible:

    npm install lib-flexible --save

            2. 在 main.js 中导入依赖:

    import 'lib-flexible/flexible'

            3、安装依赖 postcss-px2rem:

    npm install postcss-px2rem --save-dev

            4、配置 postcss-px2rem:

            vue-cli2:在根目录中的 postcss.config.js (没有新建即可),添加如下代码:

    Vue 移动端、PC 端适配,Vue 移动端、PC 端适配,第3张

    module.exports = {
      plugins: {
        "postcss-px2rem": {
          remUnit: 37.5  //lib-flexible 将屏幕分成10份(10rem),这里设置表示设计图宽度为10*37.5=375px
        }
      }
    }

            vue-cli3:在根目录中的 vue.config.js (没有新建即可),添加如下代码:

    module.exports = {
      css: {
        loaderOptions: {
          postcss: {
            plugins: [
              require('postcss-px2rem')({
                remUnit: 37.5  //lib-flexible 将屏幕分成10份(10rem),这里设置表示设计图宽度为10*37.5=375px
              })
            ]
          }
        }
      }
    }

            5、注意事项

    • 配置完成后注意删除掉 index.html 里的视窗 meta 标签 以便让 lib-flexible 插件帮你生成;
    • 如果某些 px 尺寸不想转换成 rem ,将 px大写即可。
      .box{
      	width:200Px;
      	height:200PX;
      }

      方案3 (推荐):amfe-flexible & postcss-px-to-viewport

              1、安装依赖 amfe-flexible:

      npm install amfe-flexible --save

              2、在 main.js 中导入依赖:

      import "amfe-flexible/index"

              3、安装依赖 postcss-px-to-viewport:

      npm install postcss-px-to-viewport --save-dev

              4、配置  postcss-px-to-viewport:

               vue-cli2:在根目录中的 postcss.config.js (没有新建即可),添加如下代码:

      module.exports = {
        plugins: {
          'postcss-px-to-viewport': {
            unitToConvert: 'px',   // 需要转换的单位
            viewportWidth: 750,    // 视口宽度,等同于设计稿宽度
            unitPrecision: 5,      // 精确到小数点后几位
            /**
            * 将会被转换的css属性列表,
            * 设置为 * 表示全部,如:['*']
            * 在属性的前面或后面设置*,如:['*position*'],*position* 表示所有包含 position 的属性,如 background-position-y
            * 设置为 !xx 表示不匹配xx的那些属性,如:['!letter-spacing'] 表示除了letter-spacing 属性之外的其他属性
            * 还可以同时使用 ! 和 * ,如['!font*'] 表示除了font-size、 font-weight ...这些之外属性之外的其他属性名头部是‘font’的属性
            * */
            propList: ['*'],
            viewportUnit: 'vw',    // 需要转换成为的单位
            fontViewportUnit: 'vw',// 需要转换称为的字体单位
            /**
            * 需要忽略的选择器,即这些选择器对应的属性值不做单位转换
            * 设置为字符串,转换器在做转换时会忽略那些选择器中包含该字符串的选择器,如:['body']会匹配到 .body-class,也就意味着.body-class对应的样式设置不会被转换
            * 设置为正则表达式,在做转换前会先校验选择器是否匹配该正则,如果匹配,则不进行转换,如[/^body$/]会匹配到 body 但是不会匹配到 .body
            */
            selectorBlackList: [],
            minPixelValue: 1,      // 最小的像素单位值
            mediaQuery: false,     // 是否转换媒体查询中设置的属性值
            replace: true,         // 替换包含vw的规则,而不是添加回退
            /**
            * 忽略一些文件,如'node_modules'
            * 设置为正则表达式,将会忽略匹配该正则的所有文件
            * 如果设置为数组,那么该数组内的元素都必须是正则表达式
            */
            exclude: [],
            landscape: false,      // 是否自动加入 @media (orientation: landscape),其中的属性值是通过横屏宽度来转换的
            landscapeUnit: 'vw',   // 横屏单位
            landscapeWidth: 1334   // 横屏宽度
          }
        }
      }

              vue-cli3:在根目录中的 vue.config.js (没有新建即可),添加如下代码:

      module.exports = {
        css: {
          loaderOptions: {
            postcss: {
              plugins: [
                require('postcss-px-to-viewport')({
                  unitToConvert: 'px',   // 需要转换的单位
                  viewportWidth: 750,    // 视口宽度,等同于设计稿宽度
                  unitPrecision: 5,      // 精确到小数点后几位
                  /**
                  * 将会被转换的css属性列表,
                  * 设置为 * 表示全部,如:['*']
                  * 在属性的前面或后面设置*,如:['*position*'],*position* 表示所有包含 position 的属性,如 background-position-y
                  * 设置为 !xx 表示不匹配xx的那些属性,如:['!letter-spacing'] 表示除了letter-spacing 属性之外的其他属性
                  * 还可以同时使用 ! 和 * ,如['!font*'] 表示除了font-size、 font-weight ...这些之外属性之外的其他属性名头部是‘font’的属性
                  * */
                  propList: ['*'],
                  viewportUnit: 'vw',    // 需要转换成为的单位
                  fontViewportUnit: 'vw',// 需要转换称为的字体单位
                  /**
                  * 需要忽略的选择器,即这些选择器对应的属性值不做单位转换
                  * 设置为字符串,转换器在做转换时会忽略那些选择器中包含该字符串的选择器,如:['body']会匹配到 .body-class,也就意味着.body-class对应的样式设置不会被转换
                  * 设置为正则表达式,在做转换前会先校验选择器是否匹配该正则,如果匹配,则不进行转换,如[/^body$/]会匹配到 body 但是不会匹配到 .body
                  */
                  selectorBlackList: [],
                  minPixelValue: 1,      // 最小的像素单位值
                  mediaQuery: false,     // 是否转换媒体查询中设置的属性值
                  replace: true,         // 替换包含vw的规则,而不是添加回退
                  /**
                  * 忽略一些文件,如'node_modules'
                  * 设置为正则表达式,将会忽略匹配该正则的所有文件
                  * 如果设置为数组,那么该数组内的元素都必须是正则表达式
                  */
                  exclude: [],
                  landscape: false,      // 是否自动加入 @media (orientation: landscape),其中的属性值是通过横屏宽度来转换的
                  landscapeUnit: 'vw',   // 横屏单位
                  landscapeWidth: 1334   // 横屏宽度
                })
              ]
            }
          }
        }
      }

       PC 端适配

             适配方法同移动端,但如果使用的是方案1和方案2,需要修改 lib-flexible 包中的 flexible.js 代码,注释掉如下的判断条件代码,让其在宽度大于540像素也适用。

      function refreshRem(){
        var width = docEl.getBoundingClientRect().width;
        // if (width / dpr > 540) {
        //     width = 540 * dpr;
        // }
        var rem = width / 10;
        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
      }

              如果需要在屏幕窗口变动时能无延迟适配窗口,可以修改 lib-flexible 包中的 flexible.js 代码:

      win.addEventListener('resize', function() {
          clearTimeout(tid);
          tid = setTimeout(refreshRem, 0);
      }, false);
      win.addEventListener('pageshow', function(e) {
          if (e.persisted) {
              clearTimeout(tid);
              tid = setTimeout(refreshRem, 0);
          }
      }, false);