一次搞懂数据大屏适配方案 (vw vh、rem、scale) | 您所在的位置:网站首页 › 1080*1920px是长宽 › 一次搞懂数据大屏适配方案 (vw vh、rem、scale) |
当接到可视化大屏需求时,你是否会有以下疑问👇如何做一款定制化的数据大屏? 开发可视化数据大屏如何做自适应? vm vh、rem、scale 到底哪种比较好? 时间不够,有没有偷懒的方法?
而解决了适配问题后,后面就只是一个慢工出细活,耗时间的事情了。 适配方案分析看了网上的各种方案,目前大家采用的大概有 3 种👇 方案实现方式优点缺点vm vh1.按照设计稿的尺寸,将px按比例计算转为vw和vh1.可以动态计算图表的宽高,字体等,灵活性较高 2.当屏幕比例跟 ui 稿不一致时,不会出现两边留白情况1.每个图表都需要单独做字体、间距、位移的适配,比较麻烦scale1.通过 scale 属性,根据屏幕大小,对图表进行整体的等比缩放1.代码量少,适配简单 2.一次处理后不需要在各个图表中再去单独适配1.因为是根据 ui 稿等比缩放,当大屏跟 ui 稿的比例不一样时,会出现周边留白情况 2.当缩放比例过大时候,字体会有一点点模糊,就一点点 3.当缩放比例过大时候,事件热区会偏移。rem + vm vh1.获得 rem 的基准值 2.动态的计算html根元素的font-size 3.图表中通过 vm vh 动态计算字体、间距、位移等1.布局的自适应代码量少,适配简单1.因为是根据 ui 稿等比缩放,当大屏跟 ui 稿的比例不一样时,会出现周边留白情况 2.图表需要单个做字体、间距、位移的适配以上 3 种方案在实际应用中该怎么选择视具体情况而定,也有看到大家说自适应在地图的适配中会有一些兼容问题,我这边还没有实践过。 如果想简单,客户能同意留白,选用 scale 即可如果需要兼容不同比例的大屏,并且想在不同比例中都有比较好的效果,图表占满屏幕,类似于移动端的响应式,可以采用 vm vh 的方案至于 rem,个人觉得就是 scale 和 vm vh 的综合,最终的效果跟 scale 差不多接下来介绍下三种方案的具体实现,方案中的代码都以 vue2.0 和 vue-cli3 搭建的 vue 项目为例,因为是 demo,图表的一些细节就没有过多细致的调整了 方案一:vw vh上效果![]() 当屏幕的尺寸比例刚好是 16:9 时 ![]() 当屏幕的尺寸比例大于 16:9 时 ![]() 当屏幕的尺寸比例小于 16:9 时 ![]() 按照设计稿的尺寸,将px按比例计算转为vw和vh,转换公式如下 假设设计稿尺寸为 1920*1080(做之前一定问清楚 ui 设计稿的尺寸)即:网页宽度=1920px网页高度=1080px 我们都知道网页宽度=100vw网页宽度=100vh 所以,在 1920px*1080px 的屏幕分辨率下 1920px = 100vw 1080px = 100vh 这样一来,以一个宽 300px 和 200px 的 div 来说,其所占的宽高,以 vw 和 vh 为单位,计算方式如下: vwDiv = (300px / 1920px ) * 100vwvhDiv = (200px / 1080px ) * 100vh 所以,就在 1920*1080 的屏幕分辨率下,计算出了单个 div 的宽高 当屏幕放大或者缩小时,div 还是以 vw 和 vh 作为宽高的,就会自动适应不同分辨率的屏幕复制代码 话不多说,上代码css 方案 - sassutil.scss // 使用 scss 的 math 函数,https://sass-lang.com/documentation/breaking-changes/slash-div@use "sass:math";// 默认设计稿的宽度$designWidth: 1920;// 默认设计稿的高度$designHeight: 1080; // px 转为 vw 的函数@function vw($px) { @return math.div($px, $designWidth) * 100vw;} // px 转为 vh 的函数@function vh($px) { @return math.div($px, $designHeight) * 100vh;}复制代码 路径配置只需在vue.config.js里配置一下utils.scss的路径,就可以全局使用了 vue.config.js const path = require("path");function resolve(dir) { return path.join(__dirname, dir);} module.exports = { publicPath: "", configureWebpack: { name: "app name", resolve: { alias: { "@": resolve("src"), }, }, }, css: { // 全局配置 utils.scs,详细配置参考 vue-cli 官网 loaderOptions: { sass: { prependData: `@import "@/styles/utils.scss";`, }, }, },};复制代码 在 .vue 中使用 export default{ name: "Box",} /* 直接使用 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;}复制代码 css 方案 - lessutils.less @charset "utf-8";// 默认设计稿的宽度@designWidth: 1920; // 默认设计稿的高度@designHeight: 1080; .px2vw(@name, @px) { @{name}: (@px / @designWidth) * 100vw;} .px2vh(@name, @px) { @{name}: (@px / @designHeight) * 100vh;} .px2font(@px) { font-size: (@px / @designWidth) * 100vw;}复制代码 路径配置在vue.config.js里配置一下utils.less const path = require("path");function resolve(dir) { return path.join(__dirname, dir);} module.exports = { publicPath: "", configureWebpack: { name: "app name", resolve: { alias: { "@": resolve("src"), }, }, }, css: { // 全局配置utils.scss loaderOptions: { less: { additionalData: `@import "@/styles/utils.less";`, }, }, },};复制代码 在 .vue 文件中使用 export default{ name: "Box",} /* 直接使用 vw 和 vh 函数,将像素值传进去,得到的就是具体的 vw vh单位 */.box{ .px2vw(width, 300); .px2vh(height, 100); .px2font(16); .px2vw(margin-left, 300); .px2vh(margin-top, 100); background-color: black;}复制代码 定义 js 样式处理函数// 定义设计稿的宽高const designWidth = 1920;const designHeight = 1080;// px转vwexport const px2vw = (_px) => { return (_px * 100.0) / designWidth + 'vw';}; export const px2vh = (_px) => { return (_px * 100.0) / designHeight + 'vh';}; export const px2font = (_px) => { return (_px * 100.0) / designWidth + 'vw';};复制代码 屏幕变化后,图表自动调整这种使用方式有个弊端,就是屏幕尺寸发生变化后,需要手动刷新一下才能完成自适应调整 为了解决这个问题,你需要在各个图表中监听页面尺寸变化,重新调整图表,在 vue 项目中,也可以借助element-resize-detector,最好封装个 resize 的指令,在各图表中就只要使用该指令就可以了,毕竟作为程序员,能偷懒就偷懒 安装 element-resize-detectornpm install element-resize-detector --save 引入工具包在组件中使用或者在单独的 js 中使用import resizeDetector from 'element-resize-detector' 封装 directive// directive.jsimport * 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.js 中引入import '@/directive/directive';复制代码html 代码 复制代码这里要注意的是,图表中如果需要 tab 切换动态更新图表数据,在更新数据时一定不要用 echarts 的 dispose 方法先将图表移除,再重新绘制,因为 resize 指令中挂载到的图表实例还是旧的,就监听不到新的 chart 元素的 resize 了,更新数据只需要用 chart 的 setOption 方法重新设置配置项即可。 图表字体、间距、位移等尺寸自适应echarts 的字体大小只支持具体数值(像素),不能用百分比或者 vw 等尺寸,一般字体不会去做自适应,当宽高比跟 ui 稿比例出入太大时,会出现文字跟图表重叠的情况
export default { name: "dashboardChart", data() { return { option: null, }; }, mounted() { this.getEchart(); }, methods: { getEchart() { let myChart = this.$echarts.init(this.$refs.chart); const option = { backgroundColor: "transparent", tooltip: { trigger: "item", formatter: "{a} {b} : {c}%", }, grid: { left: this.fitChartSize(10), right: this.fitChartSize(20), top: this.fitChartSize(20), bottom: this.fitChartSize(10), containLabel: true, }, calculable: true, series: [ { color: ["#0db1cdcc"], name: "计划投入", type: "funnel", width: "45%", height: "70%", x: "5%", minSize: " 10%", funnelAlign: "right",center: [" 50%", "50%"], // for piedata: [ { value: 30, name: " 下单30%", }, { value: 55, name: "咨询55%", }, { value: 65, name: "点击65%", }, { value: 60, name: "访问62%", }, { value: 80, name: "展现80%", }, ].sort(function (a, b) { return a.value - b.value; }), roseType: true, label: { normal: { formatter: function () {}, position: "inside", }, }, itemStyle: { normal: { borderWidth: 0, shadowBlur: this.fitChartSize(20), shadowOffsetX: 0, shadowOffsetY: this.fitChartSize(5), shadowColor: "rgba(0, 0, 0, 0.3)", }, }, },{ color: [" #0C66FF"], name: "实际投入", type: "funnel", width: "45%", height: "70%", x: "50%",minSize: " 10%", funnelAlign: "left",center: [" 50%", "50%"], // for piedata: [ { value: 35, name: " 下单35%", }, { value: 40, name: "咨询40%", }, { value: 70, name: "访问70%", }, { value: 90, name: "点击90%", }, { value: 95, name: "展现95%", }, ].sort(function (a, b) { return a.value - b.value; }), roseType: true, label: { normal: { position: "inside", }, }, itemStyle: { normal: { borderWidth: 0, shadowBlur: this.fitChartSize(20), shadowOffsetX: 0, shadowOffsetY: this.fitChartSize(5), shadowColor: "rgba(0, 0, 0, 0.3)", }, }, }, ], }; myChart.setOption(option, true); }, }, beforeDestroy() {},};.chartsdom { width: 100%; height: 100%;}复制代码方案二:scale 通过 css 的 scale 属性,根据屏幕大小,对图表进行整体的等比缩放,从而达到自适应效果 上效果![]() 当屏幕的尺寸比例刚好是 16:9 时,页面能刚好全屏展示,内容占满显示器 ![]() 当屏幕的尺寸比例小于 16:9 时,页面上下留白,左右占满并上下居中,显示比例保持 16:9 ![]() 当屏幕尺寸比例大于 16:9 时,页面左右留白,上下占满并居中,显示比例保持 16:9 ![]() html 部分 复制代码 js 部分 export default {mounted() { // 初始化自适应 ----在刚显示的时候就开始适配一次 handleScreenAuto(); // 绑定自适应函数 ---防止浏览器栏变化后不再适配 window.onresize = () => handleScreenAuto();},deleted() { window.onresize = null;},methods: { // 数据大屏自适应函数 handleScreenAuto() { const designDraftWidth = 1920; //设计稿的宽度 const designDraftHeight = 960; //设计稿的高度 // 根据屏幕的变化适配的比例 const scale = document.documentElement.clientWidth / document.documentElement.clientHeight 设计稿宽高比,我们需要缩放的比例是屏幕高度 / 设计稿高度const scale = document.documentElement.clientWidth / document.documentElement.clientHeight screenRatioByDesign ? (screenRatioByDesign / screenRatio) : 1 ) * docEle.clientWidth / 10; docEle.style.fontSize = fontSize.toFixed(3) + "px"; console.log(docEle.style.fontSize); } setHtmlFontSize() window.addEventListener('resize', setHtmlFontSize)})()复制代码在入口文件 main.js 中引入 rem.js 文件import './utils/rem.js';复制代码至此,页面就已经可以实现 16:9 自适应了。 第三点:屏幕变化,图表自适应屏幕变化后,图表自动调整字体、间距、位移等,此处参考上面 vm vh 的实现方式即可,在此就不重复赘述了 参考资料推荐一个echarts 的案列网站,需要什么直接图表直接在上面去找,可以省去很多查 echarts 配置的时间全网echarts案例资源大总结和echarts的高效使用技巧(细节版)scale 方案参考: 数据大屏最简单自适应方案,无需适配rem单位vm vh 方案参考: Vue+Echarts企业级大屏项目适配方案rem 方案参考:数据大屏rem适配方案作者:懒惰的智慧 链接:https://juejin.cn/post/7163932925955112996 Node 社群我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。 “分享、点赞、在看” 支持一波👍 |
CopyRight 2018-2019 实验室设备网 版权所有 |