【前端大屏可视化项目适配方案】

引自 https://juejin.cn/post/7009081081760579591#heading-27 感谢!!!

前端大屏可视化项目适配方案

      • 1. 全局适配
        • 1.1 css scale 适配方案
        • 1.2 vw+vh适配方案(有些细节处采用媒体查询处理)
          • 1.2.1 按照设计稿的尺寸,将`px`按比例计算转为`vw`和`vh`
          • 1.2.2 借助scss函数实现计算
          • 1.2.3 动态DOM元素适配
      • 2. echats及第三方组件适配(配置型)

1. 全局适配

1.1 css scale 适配方案

  • 注1:如果组件内部已经存在有scale缩放属性的元素时,内部功能会受到此方案的影响(例:地图)
  • 注2:以下方案在适配时会因分辨率大小出现两侧留白现象

// * 默认缩放值
const scale = {
  width: '1',
  height: '1',
}

// * 设计稿尺寸(px)-- 需跟ui确认
const baseWidth = 1920
const baseHeight = 1080
// const baseWidth = document.body.clientWidth
// const baseHeight = document.body.clientHeight 
// * 需保持的比例(默认1.77778)
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))

export default {
  data() {
    return {
      // * 定时函数
      drawTiming: null
    }
  },
  mounted () {
    this.calcRate()
    window.addEventListener('resize', this.resize)
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.resize)
  },
  methods: {
    calcRate () {
      const appRef = this.$refs["appRef"]
      // const geoMap = document.getElementById('geomap-container')
      if (!appRef) return 
      // 当前宽高比
      const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
      if (appRef) {
        if (currentRate > baseProportion) {
          // 表示更宽
          scale.width = ((window.innerHeight * baseProportion) / baseWidth).toFixed(5)
          scale.height = (window.innerHeight / baseHeight).toFixed(5)
          appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
          // geoMap.style.transform = `scale(${-scale.width}, ${-scale.height}) translate(-50%, -50%)`
        } else {
          // 表示更高
          scale.height = ((window.innerWidth / baseProportion) / baseHeight).toFixed(5)
          scale.width = (window.innerWidth / baseWidth).toFixed(5)
          appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
          // geoMap.style.transform = `scale(${-scale.width}, ${-scale.height}) translate(-50%, -50%)`
        }
      }
    },
    resize () {
      clearTimeout(this.drawTiming)
      this.drawTiming = setTimeout(() => {
        this.calcRate()
      }, 200)
    }
  },
}

1.2 vw+vh适配方案(有些细节处采用媒体查询处理)

1.2.1 按照设计稿的尺寸,将px按比例计算转为vwvh

	即:
	网页宽度=1920px
	网页高度=1080px

	我们都知道
	网页宽度=100vw
	网页宽度=100vh
	
	所以,在1920x*1080px的屏幕分辨率下
	
	1920px = 100vw
	
	1080px = 100vh
	
	这样一来,以一个宽300px和200px的div来说,其作所占的宽高,以vw和vh为单位,计算方式如下:
	
	vwDiv = (300px / 1920px ) * 100vw
	vhDiv = (200px / 1080px ) * 100vh
	
	所以,就在1920*1080的屏幕分辨率下,计算出了单个div的宽高
	
	当屏幕放大或者缩小时,div还是以vw和vh作为宽高的,就会自动适应不同分辨率的屏幕
1.2.2 借助scss函数实现计算
在项目静态资源文件夹下新建一个`utils.scss`文件,定义好设计稿的宽度和高度两个变量;
使用scss内置的`math.div`函数,定义两个`vw`和`vh`的计算函数;
传入具体的像素值,其帮我们自动计算出vw和vh的值;

utils.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; // math.div无效时可尝试用下面这句
  // @return calc( $px/$designWidth) * 100vw;
}

//px转为vh的函数
@function vh($px) {  
  @return math.div($px , $designHeight) * 100vh; // math.div无效时可尝试用下面这句
  // @return calc($px/$designHeight )* 100vw;
}
  • 配置utils.scss路径 – 用于全局使用
    本人项目基于Vue2开发,需在vue.config.js中配置相关
const path = require('path')
const resolve = dir => {
  return path.join(__dirname, dir)
}
module.exports = {
  publicPath: './',
  chainWebpack: config => {
    config.resolve.alias
      .set('_c', resolve('src/components')) // key,value自行定义,比如.set('@@', resolve('src/components'))
  },
  configureWebpack: {
    externals: {
    'AMap': 'AMap' // 高德地图配置
    }
  },
  css:{
    //全局配置utils.scss,详细配置参考vue-cli官网
    loaderOptions:{
      sass:{
        prependData:`@import "@/assets/scss/utils.scss";` // 路径根据个人实际情况做修改
      }
    }
  }
}
  • 在.vue组件中使用






1.2.3 动态DOM元素适配

有的时候可能不仅在.vue文件中使用,比如在js中动态创建的DOM元素,它可能是直接渲染到html中的

let oDiv = document.createElement('div')
document.body.appendChild(oDiv)

这样的话,此处用了以下两种处理方式,来给创建的div设置样式

  • 定义全局的class样式
    scr/styles目录下新建一个global.scss文件,在main.js中引入
 // global.scss文件
 .global-div{
    width: vw(300);
    height: vw(200);
    background-color: green;
}

// 在main.js中引入
import './styles/global.scss'  // 路径根据个人需求更改

// 使用时给div配置className
let oDiv = document.createElement('div')
oDiv.className = "global-div"
  • 定义js样式处理函数
    这种处理方式和scss处理函数类似,只不过使用了纯js将px转为vw和vh。
    src/utils目录下新建一个styleUtil.js文件,内容如下:
//定义设计稿的宽高
const designWidth = 1920;
const designHeight = 1080;

let styleUtil = {
    // px转vw
    px2vw: function (_px) {
        return _px * 100.0 / designWidth + 'vw';
    },
		// px转vh
    px2vh: function (_px) {
        return _px * 100.0 / designHeight + 'vh';
    },

};

export default styleUtil;

使用时,单独设置宽高等属性

import styleUtil from "./src/utils/styleUtil.js" // 注意使用个人路径

let oDiv = document.createElement('div')
oDiv.style.width = styleUtil.px2vw(300)
oDiv.style.height = styleUtil.px2vh(200)
oDiv.style.margin = styleUtil.px2vh(20)

不过这种使用方式有种弊端,就是屏幕尺寸发生变化后,需要手动刷新一下才能完成自适应调整

2. echats及第三方组件适配(配置型)

  • 图表宽高自适应
    图表宽高使用百分比,继承父元素的宽高
  • 图表字体、间距等尺寸自适应
    src/utils目录下新建一个resizeEchart.js文件,内容如下:
/* Echarts图表字体、间距自适应 */
export const fitChartSize = (size,defalteWidth = 1920) => { // 默认宽高问设计
  let clientWidth = window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;
  if (!clientWidth) return size;
  let scale = (clientWidth / defalteWidth);
  return Number((size*scale).toFixed(3));
}

// 在main.js中引入
import {fitChartSize} from './utils/resizeEchart.js'
Vue.prototype.fitChartSize = fitChartSize;

// 实际使用
axisLabel: {
    textStyle: {
      color: '#4CC8F8',
      fontSize: _this.fitChartSize(14),
      verticalAlign: "bottom",
      align: "right",
      padding: [0,_this.fitChartSize(30),_this.fitChartSize(9),0]
    }
}

// 此方法也适用于其他通过配置项配置的组件库 eg: dataV
patrolData: [
    {
      id: 1,
      name: '巡查里程',
      number: {
        number: [0],
        textAlign: 'center',
        toFixed: 2,
        content: '{nt} 公里',
        style: {
          fontSize: this.fitChartSize(26),
          fontWeight: 'bold',
          fill: '#e5b048',
          fontFamily: 'D-DIN'
        }
      }
    }
]
  • 监听DOM元素尺寸变化的插件 – element-resize-detector

这是一个用于监听DOM元素尺寸变化的插件。我们已经对窗口缩放做了监听,但是有时候其父级容器的大小也会动态改变的。 我们对父级容器的宽度进行监听,当父级容器的尺寸发生变化时,echart能调用自身的resize方法,保持视图正常。
当然,这个不适用于tab选项卡的情况,在tab选项卡中,父级容器从display:none到有实际的clientWidth,可能会比注册一个resizeDetector先完成,所以等开始监听父级容器resize的时候,可能为时已晚。

安装 element-resize-detector
npm install element-resize-detector

使用

// 在你的chart组件中引入
import ResizeListener from "element-resize-detector";

// 此处我在chart初始化时调用了该方法 -- 调用时机根据个人需求而定
this.addChartResizeListener(myChart)
  window.addEventListener('resize',function() {
    myChart.resize()
  })
},

// 对chart元素尺寸进行监听,当发生变化时同步更新echart视图
addChartResizeListener (myChart) {
  const instance=ResizeListener({
    strategy: "scroll",
    callOnAdd: true,
  });

  instance.listenTo(this.$el,() => {
    if(!myChart) return;
    myChart.resize();
  });
}

你可能感兴趣的:(前端,echarts)