打造vuecli3+element后台管理系统(五)几个小技巧,让你的后台系统在不同版本浏览器兼容性更好__Vue.js
发布于 3 年前 作者 banyungong 1114 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

当你的后台系统写好,给测试大大验收的时候。会发现他甩了一堆兼容性bug给你,在ie中打不开页面啦、在360浏览器火狐ie布局混乱啦、输入框怎么有难看的黄色背景啦、电话输入框怎么有丑陋的箭头啦、字体溢出了啦等等等等…

在开发时我们都习惯在google浏览器进行调试,总所周知,google浏览器的对css3、html5、es6等的支持是完全没有问题的,所以我们会忽略了其实在其他浏览器对这些新特性不够支持的问题,下面介绍我在开发后台系统中使用的一些插件和一些小技巧,来让你的后台系统尽可能多的向下向外兼容多版本浏览器~

一、用rem代替px

许多后台系统都要求要做成响应式的,虽然我们用的elementUI框架已经在响应式上面做了出色的处理,但是也只能解决一部分的问题。所以我们需要使用rem。

1.1 什么是rem

rem是CSS3新增的相对长度单位,是指相对于根元素html的font-size计算值的大小。简单可理解为屏幕宽度的百分比。

但是!但是!问题来了,那就是我们其实用px开发习惯了,要改成rem一时半会缓不过来,加上还要换算是吧。所以用rem还挺烦的。接下来主角就登场了,安利大家几个插件,能够将你项目中的px转换成rem,还可以自定义换算基数等。

1.2 使用lib-flexible & px2rem自动转换px为rem,解决响应式问题

1.2-1 引入lib-flexible 和 px2rem
npm install --save lib-flexible
npm install --save-dev px2rem-loader postcss-plugin-px2rem

postcss-plugin-px2rem 是为了在使用less或者sass的情况下也可以正常转换

1.2-2 删除或注释index.html中的 <meta name="viewport" content="width=device-width,initial-scale=1.0"> 标签

使用lib-flexible插件,他会自动生成meta name="viewport"的标签,所以我们需要把原来有的删除掉。自动生成标签之后,lib-flexible会自动设置html的font-size为屏幕宽度除以10,也就是1rem等于html根节点的font-size,如果你的设计稿宽度是750px,那font-size就会被设置为75px

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!-- <meta name="viewport" content="width=device-width,initial-scale=1.0"> -->
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>vuecli3-ele-admin-template</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but vuecli3-ele-admin-template doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>
1.2-3 入口文件引入lib-flexible

在main.js全局引入lib-flexible

// 使用lib-flexible来解决移动端适配
import 'lib-flexible'
1.2-4 新增配置

在vue.config.js新增px2rem的配置

const path = require('path')

function resolve(dir) {
  return path.join(__dirname, dir)
}

module.exports = {
  publicPath: '/',
  outputDir: 'dist', // 输出文件目录
  assetsDir: 'assets', // 静态资源文件夹
  productionSourceMap: false,
  devServer: {
    port: 9566, // 端口号
    open: true,
    proxy: null // 设置代理
  },
  // 新增内容
  css: {
    loaderOptions: {
      sass: { // 如果用的是less就改成less
        javascriptEnabled: true
      },
      postcss: {
        plugins: [
          require('postcss-plugin-px2rem')({
            rootValue: 54, // 换算基数,默认100,自行根据效果调整。
            mediaQuery: false, // (布尔值)允许在媒体查询中转换px。
            minPixelValue: 3 // 设置要替换的最小像素值默认0,这里表示大于3px会被转rem。
          })
        ]
      }
    }
  },
  // 新增结束
  chainWebpack: config => {
    // 新增内容
    config.module
      .rule('css')
      .test(/\.css$/)
      .oneOf('vue')
      .resourceQuery(/\?vue/)
      .use('px2rem')
      .loader('px2rem-loader')
      .options({
        remUnit: 54
      })
    // 新增结束

    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons'))
      .end()

    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
  }
}
1.2-5 康康postcss-plugin-px2rem的配置项

官方文档给出的配置项有这么多:

{
  rootValue: 100,
  unitPrecision: 5,
  propWhiteList: [],
  propBlackList: [],
  exclude:false,
  selectorBlackList: [],
  ignoreIdentifier: false,
  replace: true,
  mediaQuery: false,
  minPixelValue: 0
}

我们目前只用到了三个 那么这些都是啥意思呢,一起来康康

  • rootValue 转换基数,类型可以是Number也可以是Object,默认是100
    • 如果你传的是一个Object,例如 { px: 50, rpx: 100 } ,那么就意味着,在换算的时候,如果遇上单位是px那换算基数是50,如果遇上rpx那么换算基数是100
  • unitPrecision 单位精度,Number类型,简单的说就是转换之后的rem要保留几位小数,默认保留5位的哈
  • propWhiteList 转换的白名单,Array类型,里面包含了可以被转换的css属性
    • 默认是个空数组哦, 意思就是不用呗,就是说css里所有的属性,都可以进行转换
    • 里面的属性值必须精确匹配,使用了白名单之后,意味着只有白名单里头的属性可以转换了。感觉这个白名单会比较少用到的说
  • propWhiteList 转换的黑名单,和白名单相反嘛,黑名单里头的css属性是不会进行转换的
  • exclude 排除的文件夹,是正则表达式。比如说写了/(node_module)/,就是说(node_module)中的样式文件不进行替换,这文件夹里能有啥,就是你引的插件嘛。排除这个文件夹的意思就是不对你引入的UI框架的样式进行单位转换。
  • selectorBlackList 选择器黑名单,Array类型。和上面那个属性黑名单大同小异,不同的是这里忽略转换的依据是css选择器。
    • 如果是[‘body’],数组元素是单纯的字符串,意思就是排除class为body的转换,即忽略.body下的所有属性的转换。
    • 如果是[/^body$/]酱的,数组元素是一个正则表达式,他排除的就是body标签,即忽略body标签下的所有属性的转换。
  • ignoreIdentifier 默认是false,也可以是String类型,当是某个css属性名的时候,意思就是忽略这个属性的转换。如果你想忽略的属性只有那么一个,而不是一连串的时候,就可以用它。当启用这个的时候,replace会自动变成true的哈
  • replace 默认是true,Boolean类型,表示直接替换包含REM的规则,而不是添加回调函数
  • mediaQuery Boolean类型,默认是false,表示是否允许在[@media](/user/media)查询中进行转换
  • minPixelValue Number类型,表示开始转换的最小值,默认是0,意思就是大于0px的长度都进行转换

细心的小伙伴发现我这里的rootValue转换基数设置的是54,为什么涅?你运行项目,然后F12,会发现根元素html的font-size是54px。为什么!为什么明明前面说的是宽度除以10啊,我特喵的pc端宽度是1080啊,不应该是font-size:108px么???

想知道答案的小伙伴就要去看看伟大的lib-flexible的源码啦,lib-flexible里头有这么一段代码:

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;
}

pc端的dpr是1,width / dpr肯定是大于540的,所以lib-flexible会默认使用540px这个宽度,然后将屏幕宽度除以10作为rem值,所以1rem = 54px。所以我们将rootValue转换基数设为54刚刚好


康康添加了lib-flexible & px2rem之后,页面在移动端的显示效果如何:

inPhone1

inPhone2

好的,十分优秀。

二、解决低版本ie打不开页面的问题

当你写完后台系统之后,毛闷台了喔,在线上把代码一拉一部署,测试那边说了,你这个页面我浏览器打不开啊!你过去之后发现他用的ie不知道6还是7还是8测得你的网站。那么问题来了,为什么会打不开呢?

原因就是你的项目里头用了es6的promise,ie低版本对这个的支持不是特别好,这个问题很好解决,只需要引入两个插件就可以了。对本身代码没有其他影响。

2.1 引入es6-promise & 和babel-polyfill依赖包

npm install --save es6-promise babel-polyfill

2.2 在入口文件main.js引入

// 解决低版本浏览器不支持promise问题
import 'babel-polyfill'
import Es6Promise from 'es6-promise'
Es6Promise.polyfill()

2.3 在vue.config.js新增配置

    // 。。。此处省略n个字符。。。
    config.module
      .rule('icons')
      .test(/\.svg$/)
      .include.add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
    // 新增配置
    config.entry.app = ['babel-polyfill', './src/main.js']
    // 新增结束
  }
}

三、使用autoprefixer让css属性自动增加兼容前缀

很多时候,像flexBox或者transform这样样式,在不同浏览器下面有不同的写法,正常来说我们每次用到其中一个的时候都需要写这么长一大串:

<style lang="scss">
.flex-box {
    display: -webkit-box;
    display: -moz-box;
    display: -webkit-flex;
    display: -moz-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-justify-content: center;
    -webkit-box-pack: center;
    -moz-justify-content: center;
    -moz-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    -webkit-align-items: center;
    -webkit-box-align: center;
    -moz-align-items: center;
    -moz-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    -webkit-box-direction: normal;
    -webkit-box-orient: vertical;
    -webkit-flex-direction: column;
    -moz-flex-direction: column;
    -moz-box-orient: vertical;
    -ms-flex-direction: column;
    flex-direction: column;
}
</style>

晕,我只是想要用一下flex布局啊。。

经过评论区小伙伴的提醒,这里有一个很棒的插件可以使用,他可以自动给你的项目增加兼容前缀,需要添加的浏览器兼容前缀由你自由配置。我们只需:

3.1安装autoprefixer依赖

cnpm install --save-dev autoprefixer

3.2在vue.config.js引入

// ...省略前面省略
css: {
    loaderOptions: {
      sass: { // 如果用的是less就改成less
        javascriptEnabled: true
      },
      postcss: {
        plugins: [
          // 新增内容
          require('autoprefixer')({}),
          // 新增结束
          require('postcss-plugin-px2rem')({
            rootValue: 54, // 换算基数,默认100,自行根据效果调整。
            mediaQuery: false, // (布尔值)允许在媒体查询中转换px。
            minPixelValue: 3 // 设置要替换的最小像素值默认0,这里表示大于3px会被转rem。
          })
        ]
      }
    }
  },
 // ...省略后面省略

3.3 在package.json中指定browserslist关键字

在package.json中新增

"browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8",
    "iOS >= 8",
    "Firefox >= 20",
    "Android >= 4.4"
  ]

接下来就是见证奇迹的时刻,重新npm run serve一下,你就发现所有兼容样式前面都加上前缀啦~


关于之前的手写mixin的方法,我还是建议大家能够多封装,不管是业务代码上还是样式代码上,这样可以增加代码的复用率,让你的代码看起来更加轻盈。像一些使用率比较多的样式块,可以使用mixin封装起来,需要时include就行啦,也是十分方便的。

举个栗子

  1. 在styles的mixin.scss文件里声明一些常用的样式块
    

    /* 背景自适应容器大小 */ @mixin bgCover($url) { background-image: url($url); background-repeat: no-repeat; background-size: cover; background-position: 0 center; }

    @mixin noData($url) { width: 100%; font-size: 14px; text-align: center; color: #666; line-height: 60px; }

  2. 在需要使用到mixin样式的页面引入,用mixin替换样式块
    
    <style lang="scss"> @import '~@/styles/mixin'; .no-data { @include noData; } </style>

四、覆盖默认样式

很多标签都有一些奇奇怪怪的默认样式,在不同的浏览器下面默认样式还不一样,为了统一性。我们需要覆盖掉默认样式。其实这一块,elementUI已经考虑到了,在styles目录下面的index.scss文件就是用来覆盖默认样式的。有需要覆盖掉的默认样式,可以在里面已有代码的基础上再新增。分享两个典型的:

4.1 覆盖掉input type=number时的箭头

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  -webkit-appearance: none;
}
input[type="number"] {
  -moz-appearance: textfield;
}

4.2 改变Placeholder文字的颜色

input::-moz-placeholder{color:rgb(204, 204, 204)} //Firefox
input::-webkit-input-placeholder{color:rgb(204, 204, 204)} //Chrome,Safari
input:-ms-input-placeholder{color:rgb(204, 204, 204)} // ie
textarea::-moz-placeholder{color:rgb(204, 204, 204)} //Firefox
textarea::-webkit-input-placeholder{color:rgb(204, 204, 204)} //Chrome,Safari
textarea:-ms-input-placeholder{color:rgb(204, 204, 204)} // ie

五、通过meta标签控制浏览器内核

国产浏览器大多是双内核,甚至更多,例如360浏览器、QQ浏览器之类。这些浏览器一般会有一个Chromium内核(极速模式。Chromiu就是Chrome使用的内核。);一个IE内核(IE模式);有的甚至还有一个修改过的IE内核(兼容模式)。

我们创建的项目,默认有一个控制切换浏览器内核的meta标签<meta http-equiv="X-UA-Compatible" content="IE=edge">运行网站的时候强制切换为该浏览器所拥有的最高版本IE内核,所以在qq浏览器或者360浏览器里头打开项目,会发现浏览器用的是IE模式或者兼容模式。

因为项目是用chrome调试的,所以在Chromium内核下拥有最优体验,我们需要用代码让浏览器能够改变一下模式。具体做法就是:

修改public目录下的index.html模板文件。

新增meta标签,告诉浏览器优先使用何种内核

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    
    <!-- 新增内容 -->
    <!-- 强制Chromium内核,作用于360浏览器、QQ浏览器等国产双核浏览器 -->
    <meta name="renderer" content="webkit"/>
    <!-- 强制Chromium内核,作用于其他双核浏览器 -->
    <meta name="force-rendering" content="webkit"/>
    <!-- 如果有安装 Google Chrome Frame 插件则强制为Chromium内核,否则强制本机支持的最高版本IE内核,作用于IE浏览器 -->
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"/>
    <!-- 新增结束 -->
    
    <!-- <meta name="viewport" content="width=device-width,initial-scale=1.0"> -->
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>vuecli3-ele-admin-template</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but vuecli3-ele-admin-template doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

清一下浏览器缓存,重新运行项目,就会发现在360浏览器、QQ浏览器下已经变成Chromium内核的极速模式了~美得很~

暂时就先想到这些啦,后面想到我再继续补充~~ 还有很多细节的东西没有详细写出来,我这里贴一下项目地址,有兴趣的可以看一看哦~

回到顶部