1、 一般来说大屏项目主要是两方面的工作:
-
前期的自适应适配
-
根据ui设计稿绘制图表,调整细节
2、 适配方案分析
目前网上常见的方案共有以下三种:
1、vw/vh:就是按照设计稿的尺寸,将px按比例计算转为vw和vh(可以使用插件,但是这样实现的效果和rem差不多),然后对每个图表都需要单独做字体、间距、位移的适配。
它的优点是:
1.可以动态计算图表的宽高,字体等,灵活性较高
2.当屏幕比例跟 ui 稿不一致时,不会出现两边留白情况。
它的缺点是:每个图表都需要单独做字体、间距、位移的适配,比较麻烦。
2、scale:它是通过 scale 属性,根据屏幕大小,对图表进行整体的等比缩放。
优点是:
1.代码量少,适配简单。
2.一次处理后不需要在各个图表中再去单独适配。
缺点是:
1.因为是根据 ui 稿等比缩放,当大屏跟 ui 稿的比例不一样时,会出现周边留白情况
2.当缩放比例过大时候,字体会有一点点模糊。
3.当缩放比例过大时候,事件热区会偏移。
3、rem:指的首先获得 rem 的基准值,动态的计算html根元素的font-size,其次根据rem基准值大小,把设计稿的px单位转化为rem单位(此处可以使用插件自动转换),最后图表自动调整和图表字体、间距、位移等的自适应。
缺点:
1、因为是根据 ui 稿等比缩放,当大屏跟 ui 稿的比例不一样时,会出现周边留白情况
2、图表需要单个做字体、间距、位移的适配
3、适配较复杂
3、 方案选取:
如果是固定屏幕尺寸,选择scale比较简单;也可以选择rem。如果需要兼容不同比例的大屏,并且在不同比例的大屏中都有好的效果,不能留白,可以采用vw/vh的方案。
4、代码实现:
1、scale方案:
//第一步:scale适配方案js代码
export const handleScreenAuto = () => {
const designDraftWidth = 2560; //设计稿的宽度
const designDraftHeight = 1440; //设计稿的高度
// 根据屏幕的变化适配的比例
const scale =
document.documentElement.clientWidth /
document.documentElement.clientHeight <
designDraftWidth / designDraftHeight
? document.documentElement.clientWidth / designDraftWidth
: document.documentElement.clientHeight / designDraftHeight;
// 缩放比例
document.querySelector(
'.layout',
).style.transform = `scale(${scale}) translate(-50%, -50%)`;
}
//第二步:在App.vue中引入
<template>
<div id="app">
<div class="layout">
<router-view />
</div>
</div>
</template>
<script>
import { handleScreenAuto } from "@/utils/handleScreenAuto";
export default {
mounted() {
// 初始化自适应 ----在刚显示的时候就开始适配一次
handleScreenAuto();
// 绑定自适应函数 ---防止浏览器栏变化后不再适配
window.onresize = () => handleScreenAuto();
},
deleted() {
window.onresize = null;
},
};
</script>
<style lang="scss">
#app {
height: 100%;
width: 100%;
.layout {
background-color: black;
display: inline-block;
width: 2560px; //这是设计稿的宽度
height: 1440px; //这是设计稿的高度
transform-origin: 0 0;
position: absolute;
left: 50%;
top: 50%;
}
}
</style>
2、rem方案:
//第一步:rem.js适配文件
(function init(screenRatioByDesign = 16 / 9) {
let docEle = document.documentElement
function setHtmlFontSize() {
var screenRatio = docEle.clientWidth / docEle.clientHeight;
var fontSize = (
screenRatio > screenRatioByDesign
? (screenRatioByDesign / screenRatio)
: 1
) * docEle.clientWidth / 10;
docEle.style.fontSize = fontSize.toFixed(3) + "px";
// console.log(docEle.style.fontSize);
}
setHtmlFontSize()
window.addEventListener('resize', setHtmlFontSize)
})()
//第二步:把 页面中的px转换成rem
//npm i @njleonzhang/postcss-px-to-rem -D
//创建.postcssrc.js配置文件
module.exports = {
plugins: {
autoprefixer: {},
"@njleonzhang/postcss-px-to-rem": {
unitToConvert: 'px', // (String) 要转换的单位,默认是 px。
widthOfDesignLayout: 3840, // (Number) 设计布局的宽度。
unitPrecision: 3, // (Number) 允许 rem 单位增长到的十进制数字.
selectorBlackList: ['.ignore', '.hairlines'], // (Array) 要忽略并保留为 px 的选择器.
minPixelValue: 1, // (Number) 设置要替换的最小像素值.
mediaQuery: false // (Boolean) 允许在媒体查询中转换 px.
}
}
}
//第三步: Echarts图表字体、间距自适应
export const fitChartSize = (size, defalteWidth = 3840) => {
let clientWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
if (!clientWidth) return size;
let scale = (clientWidth / defalteWidth);
return Number((size * scale).toFixed(6));
}
/*
第四步:屏幕变化后,图表自动调整:
这种使用方式有个弊端,就是屏幕尺寸发生变化后,需要手动刷新一下才能完成自适应调整,可以使用echarts的resize()这个方法解决。
*/
window.addEventListener("resize", () => {
this.myChart.setOption(this.option, true);
this.myChart.resize();
});
},
//还有一个问题:字体、间距的大小也必须刷新后才能自适应,使用resize()这个方法是无效的,我采用了下面这种办法解决。
window.addEventListener("resize", () => {
this.myChart.dispose();
this.init();
});
3、vw、vh方案:
第一种使用插件的方式:(效果和rem方案差不多)
//第一步:引入 postcss-px-to-viewport,然后配置postcss.config.js
npm install postcss-px-to-viewport --save-dev
module.exports = {
plugins: {
'postcss-px-to-viewport': {
unitToConvert: "px", // 要转化的单位
viewportWidth: 3840, // UI设计稿的宽度
unitPrecision: 6, // 转换后的精度,即小数点位数
propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw selectorBlackList: ["wrap"], // 指定不转换为视窗单位的类名,
minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
replace: true, // 是否转换后直接更换属性值
exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
}
}
}
//第二步: 给Echarts每个图表做适配
export const fitChartSize = (size, defalteWidth = 3840) => {
let clientWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
if (!clientWidth) return size;
let scale = (clientWidth / defalteWidth);
return Number((size * scale).toFixed(6));
}
/*
第三步:屏幕变化后,图表自动调整:
这种使用方式有个弊端,就是屏幕尺寸发生变化后,需要手动刷新一下才能完成自适应调整,可以使用echarts的resize()这个方法解决。
*/
window.addEventListener("resize", () => {
this.myChart.setOption(this.option, true);
this.myChart.resize();
});
},
//还有一个问题:字体、间距的大小也必须刷新后才能自适应,使用resize()这个方法是无效的,我采用了下面这种办法解决。
window.addEventListener("resize", () => {
this.myChart.dispose();
this.init();
});
第二种手动 px 转 vw,px 转 vh 的方式:(可适配不同比例的大屏)
//第一步:配置util.scss
// 使用 scss 的 math 函数,https://sass-lang.com/documentation/breaking-changes/slash-div
@use "sass:math";
// 默认设计稿的宽度
$designWidth: 3840;
// 默认设计稿的高度
$designHeight: 2160;
// px 转为 vw 的函数
@function vw($px) {
@return math.div($px, $designWidth) * 100vw;
}
// px 转为 vh 的函数
@function vh($px) {
@return math.div($px, $designHeight) * 100vh;
}
//第二步:在vue.congfig.js全局配置 utils.scss
module.exports = {
publicPath: "",
configureWebpack: {
name: "app name",
resolve: {
alias: {
"@": resolve("src"),
},
},
},
css: {
// 全局配置 utils.scss,详细配置参考 vue-cli 官网
loaderOptions: {
sass: {
prependData: `@import "@/styles/utils.scss";`,
},
},
},
};
//第三步:在vue中使用
<template>
<div class="box">
</div>
</template>
<script>
export default{
name: "Box",
}
</script>
<style lang="scss" scoped="scoped">
/*
直接使用 vw 和 vh 函数,将像素值传进去,得到的就是具体的 vw vh 单位
*/
.box{
width: vw(300);
height: vh(100);
font-size: vh(16);
background-color: black;
margin-left: vw(10);
margin-top: vh(10);
border: vh(2) solid red;
}
</style>
//第四步: 给Echarts每个图表做适配
export const fitChartSize = (size, defalteWidth = 3840) => {
let clientWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
if (!clientWidth) return size;
let scale = (clientWidth / defalteWidth);
return Number((size * scale).toFixed(6));
}
/*
第五步:屏幕变化后,图表自动调整:
这种使用方式有个弊端,就是屏幕尺寸发生变化后,需要手动刷新一下才能完成自适应调整,可以使用echarts的resize()这个方法解决。
*/
window.addEventListener("resize", () => {
this.myChart.setOption(this.option, true);
this.myChart.resize();
});
},
//还有一个问题:字体、间距的大小也必须刷新后才能自适应,使用resize()这个方法是无效的,我采用了下面这种办法解决。
window.addEventListener("resize", () => {
this.myChart.dispose();
this.init();
});
参考资料:一次搞懂数据大屏适配方案 (vw vh、rem、scale) - 掘金