我正在参加「掘金·启航计划」 bytedance.feishu.cn/docx/C6QQdS…
自适应的问题
-
屏幕像素大小不同,统一表现
-
画面比例不同,统一表现
-
浏览器字体最小限制,不可能无限等比缩小
-
画面出现拉伸压缩
-
文字内容显示异常
-
画面出现空白区域
一. css缩放方案: 利用transform:scale 进行适配
大屏自适应组件 v-scale-screen
v-scale-screen使用css属性transform实现缩放效果,进行等比例计算,达到等比例缩放的效果,同时我们也支持铺满全屏,宽度等比,高度等比,等自适应方案
值得注意:
vue2请使用v-scale-screen@1.0.0版本,
vue3请使用v-scale-screen@2.0.0版本
安装
npm install v-scale-screen -save # or yarn add v-scale-screen
vue2
// main.js
import Vue from "vue";
import App from "./App.vue";
// 引入 VScaleScreen
import VScaleScreen from "v-scale-screen";
Vue.use(VScaleScreen);
Vue.config.productionTip = false;
new Vue({
render: (h) => h(App)
}).$mount("#app");
<template>
<VScaleScreen>
<img src="" alt="" />
</VScaleScreen>
</template>
<script>
export default {
name: "home",
components: {},
};
</script>
<style>
* {
margin: 0;
padding: 0;
}
</style>
vue3
//main
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#app");
<template>
<VScaleScreen>
<img src="" alt="" />
</VScaleScreen>
</template>
<script>
import VScaleScreen from "v-scale-screen";
export default {
name: "home",
components: {
VScaleScreen,
},
};
</script>
<style>
* {
margin: 0;
padding: 0;
}
</style>
二. rem方案
原理: 利用html的font-size变换,在移动端也经常使用此方法。
css 相对单位,相对于根元素的 font-size 值的大小
将设计稿的单位转化为rem单位就可以实现等比例的自适应缩放
随窗口变化响应地调整根元素font size
在utils目录下创建flexible.js, 复制下方代码。黏贴保存。
(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 > 1920) {
// 这个位置划重点 1920是设计稿的大小 如果你的设计稿是750 那么就需要将1920替换成750
width = (docEl.clientWidth / 1920) * 1920;
}
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 () {
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"] = {}));
在main.js中导入一下就行
import '@/utils/flexible'
利用vscode插件
cssrem
填写内容:
设计稿的宽度 * 0.1 = 填写的数字
1920 * 0.1 = 192
750 * 0.1 = 75
使用效果
三.postcss插件使用
postcss 一种对css编译的工具,类似babel对js的处理,通过它的插件生态来实现各种功能转换,如: autoprefixer(. 自动补全浏览器前缀), px2rem(自动将px转换为rem)
这里对px2rem配置说明如下:
postcss-plugin-px2rem: 作为postcss的经典插件之一,用于自动转换px为rem postcss-px2rem文档
1.安装
npm i postcss-plugin-px2rem -D
- 配置vue.config.js
css: {
loaderOptions: {
postcss: {
plugins: [
require('postcss-plugin-px2rem')({
rootValue: 100, //换算基数, 默认100 ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。
unitPrecision: 5, //允许REM单位增长到的十进制数字。
propWhiteList: [], //默认值是一个空数组,这意味着禁用白名单并启用所有属性。
propBlackList: [], //黑名单
exclude: /(node_module)/, //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)/ 。如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
selectorBlackList: [], //要忽略并保留为px的选择器
ignoreIdentifier: false, //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。
replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。
mediaQuery: false, //(布尔值)允许在媒体查询中转换px。
minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0
}),
]
}
}
},