什么是数据大屏适配
数据大屏适配主要指的是确保数据大屏在不同屏幕分辨率和尺寸下能够良好地显示和运行,避免出现错位、变形或显示不全等问题。为了实现这一点,开发者需要采取一系列技术手段来确保大屏数据可视化的屏幕适配。常见的大屏适配的方案是scale、vw vh、 rem+vw vh。
本文主要介绍的是scale 和 vw vh 进行大屏适配。
视频讲解:
温馨提示:代码用的是vue3+ts+sass+vite的写法
scale 适配
什么是scale
在css中,scale是transform的一个函数,用于调整元素的大小,对元素进行缩放。
scale用法
transform: scale(x轴缩放的倍数,y轴的缩放倍数)。一般情况下,我们只输入一个值,表示x轴和y轴等比例缩放。当scale的值大于1表示放大,小于1表示缩小。
例:transform: scale(1.5) 会将元素的尺寸放大到1.5倍。
scale适配思路
-
改变内容展示区域盒子的原点位置
/**通过定位改变盒子的位置 此时盒子移动到了屏幕的右下角
position: fixed参照物是浏览器视口的宽高
比如top:50%;正值向下,负值向上,50%就是向下移动50%,也就是浏览器视口高的一半,left:50% 同理,所以盒子来到了右下角*/
position: fixed;
top: 50%;
left: 50%;
/** 此时盒子的左上角正处于屏幕正中间的位置 */
transform-origin: top left;
-
将内容展示区域盒子居中
/**
盒子通过向下移动50%向右移动50%来到了浏览器视口的右下角,此时盒子的宽高就是浏览器视口宽高的一半
让盒子向上向左移动盒子自身的一半(50%),也就是浏览器视口宽高的各25% 此时盒子居中
translate位移,参照物是盒子本身 正值向下(右)负值向上(左),
*/
transform:translate(-50%, -50%)
-
计算内容展示区域盒子放大缩小的比例
// 设计稿的宽高以实际的为准 这边以1920*1080为例
const getScale = () => {
// window.innerWidth 是js 获取浏览器视口的宽
const ww = window.innerWidth / 1920;
// window.innerHeight 是js 获取浏览器视口的高
const wh = window.innerHeight / 1080;
// ww < wh ? ww : wh 三元运算符;如果 ww 小于 wh,则结果为 ww,否则结果为 wh。
return ww < wh ? ww : wh;
};
scale适配完整代码
<script lang="ts" setup>
import { ref, onMounted, watch } from "vue";
const screen = ref();
const getScale = () => {
const ww = window.innerWidth / 1920;
const wh = window.innerHeight / 1080;
return ww < wh ? ww : wh;
};
onMounted(() => {
watch(
window.onresize,
() => {
screen.value.style.transform = `scale(${getScale()}) translate(-50%, -50%)`;
},
{
immediate: true,
}
);
});
window.onresize = () => {
screen.value.style.transform = `scale(${getScale()}) translate(-50%, -50%)`;
};
</script>
<template>
<div class="screen-container">
<div class="screen" ref="screen">
<div class="box"></div>
</div>
</div>
</template>
<style lang="scss" scoped>
.screen-container {
width: 100vw;
height: 100vh;
background: url(../assets/image/bg.png) no-repeat;
background-size: 100% 100%;
.screen {
position: fixed;
width: 600px;
height: 600px;
background-color: green;
top: 50%;
left: 50%;
transform: scale(0.3);
.box {
background-color: red;
margin-left: 20px;
width: 100px;
height: 100px;
}
}
}
</style>
vw vh 适配
vw vh 简介
vw vh是css的视口单位,1vw是屏幕视口宽度的1%,1vh是屏幕视口高度的1%。
vw vh的实现思路
当视口的宽高发生变化时,里面的盒子也需要跟着变化,在css中,单位一般是px,所以我们需要将px转换成vw和vh。
转换方式:
-
自己封装方法去转换(重点)
-
使用第三方插件去转换,如postcss-px-to-viewport
// 安装 postcss-px-to-viewport 插件
npm install postcss-px-to-viewport --save-dev
// 在vue.config.ts中配置
import { defineConfig, loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
import pxToViewport from 'postcss-px-to-viewport';
export default defineConfig(({ command, mode }) => {
css: {
postcss: {
plugins: [
pxToViewport({
unitToConvert: "px", // 要转化的单位
viewportWidth: 1920, // UI设计稿的宽度
viewportHeight: 1080,
unitPrecision: 3, // 转换后的精度,即小数点位数
propList: ["*"], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
viewportUnit: "vw", // 指定需要转换成的视窗单位,默认vw
fontViewportUnit: "vw", // 指定字体需要转换成的视窗单位,默认vw
landscapeUnit: "vh", // 横屏时使用的单位
landscapeWidth: 667, // 横屏时使用的视口宽度
selectorBlackList: [], // 指定不转换为视窗单位的类名
minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
mediaQuery: false, // 是否在媒体查询的css代码中也进行转换,默认false
replace: true, // 是否转换后直接更换属性值
landscape: false, // 是否处理横屏情况
exclude: /(\/|\\)(node_modules)(\/|\\)/, // 设置忽略文件,用正则做目录名匹配
}),
],
},
}
});
css 封装单位转换的方法
/**
单独写在一个样式文件中 style/untils.scss
*/
@use "sass:math";
/**
定义设计稿的宽高,以实际设计稿的宽高为准
*/
$designWidth:1920;
$designHeight:1080;
/**
math.div()是css中的除法
*/
@function vw($px) {
@return math.div($px , $designWidth) * 100vw;
}
@function vh($px) {
@return math.div($px , $designHeight) * 100vh;
}
@function px2font($px) {
@return math.div($px , $designWidth) * 100vw;
}
// 在vite.config.ts文件中配置成全局
import { defineConfig, loadEnv } from "vite";
export default defineConfig(({ command, mode }) => {
return {
//配置scss的全局变量
css: {
preprocessorOptions: {
scss: {
javascriptEnabled: true,
additionalData:
'@import "./src/styles/until.scss";',
},
},
},
};
});
// 在.vue文件中使用
<script setup lang="ts">
import { ref, reactive } from "vue";
</script>
<template>
<div class="screen-container">
<div class="box">
<span>嘤嘤嘤</span>
</div>
</div>
</template>
<style scoped lang="scss">
.screen-container {
width: 100vw;
height: 100vh;
background: url(../assets/image/bg.png) no-repeat;
background-size: 100% 100%;
overflow: hidden;
.box {
background-color: red;
margin: 30px;
width: vw(300);
height: vh(300);
font-size: font(30);
}
}
</style>
js 封装单位转换的方法
import { ref } from "vue";
const designWidth = ref(1920);
const designHeight = ref(1080);
export const pxToVw = (px: number): string =>
`${(px * 100) / designWidth.value}vw`;
export const pxToVh = (px: number): string =>
`${(px * 100) / designHeight.value}vh`;
export const pxToFont = (px: number): string =>
`${(px * 100) / designWidth.value}vw`;
封装echarts图表自适应的指令
目前为止,我们只是把 css和js 里面怎么进行单位转换封装成了方法,但是当我们一进入页面,数据大屏是需要自适应,也就是我们的echarts图表,我们通过自定义指令来实现大屏自适应。
// 新建一个ts文件 echartResize.ts
import * as ECharts from "echarts";
import elementResizeDetectorMaker from "element-resize-detector";
import Vue from "vue";
const HANDLER = "_vue_resize_handler";
function bind(el, binding) {
el[HANDLER] = binding.value
? binding.value
: () => {
let chart = ECharts.getInstanceByDom(el);
if (!chart) {
return;
}
chart.resize();
};
// 监听绑定的div大小变化,更新 echarts 大小
elementResizeDetectorMaker().listenTo(el, el[HANDLER]);
}
function unbind(el) {
// window.removeEventListener("resize", el[HANDLER]);
elementResizeDetectorMaker().removeListener(el, el[HANDLER]);
delete el[HANDLER];
}
// 自定义指令:v-chart-resize 示例:v-chart-resize="fn"
Vue.directive("chart-resize", { bind, unbind });
// 一定要记住在main.ts中引入
import '@/utils/echartResize.ts';
在.vue文件中使用
<template>
<div class="linechart">
<div ref="chart" v-chart-resize class="chart"></div>
</div>
</template>
注意:
图表中如果需要 tab 切换动态更新图表数据,在更新数据时一定不要用 echarts 的 dispose 方法先将图表移除,再重新绘制,因为 resize 指令中挂载到的图表实例还是旧的,就监听不到新的 chart 元素的 resize 了,更新数据只需要用 chart 的 setOption 方法重新设置配置项即可。
scale适配和vw vh适配的优缺点
方案 | 优点 | 缺点 |
---|---|---|
scale | 1. 代码量少 2.只需要控制内容展示区域的盒子进行缩放即可 | 当屏幕的大小和设计稿的大小不一致时,两侧会出现留白 |
vw vh | 当屏幕的大小和设计稿的大小不一致时,两侧不会出现留白 | 代码量大,需要自己去调整每个图表的大小,包括图表中字体 间距等 |
推荐阅读
sass内置函数讲解:https://sass-lang.com/documentation/modules/color/