关于vue 在pc端的页面适配做一个比较详细的汇总
因为之前自己用的都是vue2 + webpack 所以对于这个的适配比较熟练 后来又用到了vue3+ vite, 两者关于pc端页面适配的流程差别不大,下面做一个汇总 (萌新笔记)
1. vue2 + webpake
首先需要安装两个插件 (也可以只安装第一个,具体原因下面说 )
npm install postcss-px2rem --save-dev
表示将px转换为rem 因为我用的这个pc端适配的方法核心原理是rem转换
npm i lib-flexible --save-dev
这个是阿里用来做设备适配的一个插件,但是当设备宽度较大时,他就会恒定根标签的font-size为54px,所以我们可以一会对这个js文件进行修改,或者是直接自己在其他目录下新建一个,引用自己新建的就好。
安装之后的第一件事就是找到我们的flexible.js 文件,进行修改,这里我可以我直接发源码就好了,这个也是参考了网上的一些代码,(我自己一开始肯定写不出来的,后来看了很久才看明白也是,就是借鉴使用)
我们可以在这个位置找到flexble.js 在node_module中找到这个文件
进入之后进行修改 修改为一下代码
;(function(win, lib) {
var doc = win.document;
var docEl = doc.documentElement;
var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
var dpr = 0;
var scale = 0;
var tid;
var flexible = lib.flexible || (lib.flexible = {});
if (metaEl) {
console.warn('将根据已有的meta标签来设置缩放比例');
var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
if (match) {
scale = parseFloat(match[1]);
dpr = parseInt(1 / scale);
}
} else if (flexibleEl) {
var content = flexibleEl.getAttribute('content');
if (content) {
var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
if (initialDpr) {
dpr = parseFloat(initialDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
if (maximumDpr) {
dpr = parseFloat(maximumDpr[1]);
scale = parseFloat((1 / dpr).toFixed(2));
}
}
}
if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
docEl.setAttribute('data-dpr', dpr);
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
// width = 540 * dpr;
//变更
width = width * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
if (doc.readyState === 'complete') {
doc.body.style.fontSize = 12 * dpr + 'px';
} else {
doc.addEventListener('DOMContentLoaded', function(e) {
doc.body.style.fontSize = 12 * dpr + 'px';
}, false);
}
refreshRem();
flexible.dpr = win.dpr = dpr;
flexible.refreshRem = refreshRem;
flexible.rem2px = function(d) {
var val = parseFloat(d) * this.rem;
if (typeof d === 'string' && d.match(/rem$/)) {
val += 'px';
}
return val;
}
flexible.px2rem = function(d) {
var val = parseFloat(d) / this.rem;
if (typeof d === 'string' && d.match(/px$/)) {
val += 'rem';
}
return val;
}
})(window, window['lib'] || (window['lib'] = {}));
其实核心部分就是修改了这里
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
// width = 540 * dpr;
//变更
width = width * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
之前的js 中,不适用与pc设备,只使用与移动设备,对于pc端来讲,html的font-size会被固定为54px,而1rem是等于这个大小的,所以对于pc端来讲就会失去意义,我们设置之后就是,该数值会恒定为设备宽度的1/10,这个就是使用rem的老前辈们的习惯,将这些完成以后,我们可以在main.js中引入我们写好的js,如果是修改原文件,就直接
import 'lib-flexible'
如果是你是自己新建的,就引入自己的。
然后我们可以开始一个小实验测试一下。(使用rem)
这里我随便创建一个盒子(id:test) 然后加上样式
#test{
width: 5rem;
height: 5rem;
background-color: red;
}
我们看一下效果
因为我们的宽度为5rem(1rem=1/10总宽度) 所以对应的盒子宽度为设备一半,那我们修改设备宽度看一下结果
可以看到盒子可以自适应的改变自己的宽度(还是总设备的一半),原理就是每次设备宽度修改,flexblie.js会帮助我们修改根标签的font-size 导致1rem总是等于视口宽度1/10
但是现在的问题是 我们不能总是写rem,因为拿到的设计图一般是px的,自己计算的话
T rem=(N px/ M ) (1rem=Mpx) 这显然很麻烦 所以就用上了我们第一个插件 , 这个插件的作用就是将px转换为rem 这个是webpack打包时loader会发挥的作用,这个就不细谈了。
用法比较简单,首先打开自己的vue.config.js,在最外面的目录(与package.json同级),如果没有的话就自己创建一个。
打开之后加入如下代码
const px2rem = require('postcss-px2rem')
const postcss = px2rem({
remUnit: 192 // 基准值
})
module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [
postcss
]
}
}
},
devServer: {
port: 3000
},
}
最后那个devServer是我自己改的端口可以无视掉,需要注意的就是前面的remUnit=192 ,表示1rem=192px 因为我们普遍的设计图为1920*1080 所以1/10宽度为192
全都完成之后我们可以看效果,还是刚刚的盒子,现在我修改css
#test{
width: 400px;
height: 400px;
background-color: red;
}
然后看效果
修改设备宽度
可以看到盒子意见完成了自适应。以上是关于vue+webpack 使用rem适配的方法。
2. vue+vite
这个和上面的操作基本都是一样的,区别只有 vite 配置时不要再vue.config.js中使用第一个插件,这是webpack的使用方法,vite我们需要再同一层级下创建postcss.config.js
然后加入一下代码
const px2rem = require('postcss-px2rem')
const postcss = px2rem({
remUnit: 190 // 基准值
})
module.exports = {
plugins: {
postcss
}
}
就可以同样的完成pc端的适配,效果与1中相同。
一些注意事项:
1. 内联样式中的px是无法被适配为rem的
例如
2. 直接按上述方法使用可能会对第三方ui 例如element-ui的显示造成影响
这里提供再postcss中的另一种写法
module.exports = {
"plugins": {
"postcss-pxtorem": {
rootValue: 192,
propList: ['*'],
selectorBlackList: [
'ant'
]
}
}
}
这样写的话就可以避免对ui库的影响 如果用的是webpack 直接在px2rem-loader属性里加上除去node_modules即可
exclude:/node_modules/
(纯萌新笔记)