vue2 大屏开发步骤

274 阅读1分钟

第一步

根据UI图,确定大屏布局,完成百分比布局,如果有需要可以对其进行拆分,以下是我对通用大屏进行的拆分方式,便于模块化小单元管理。

image.png


第二步

封装通用echarts组件

// chart.vue

<template>
  <div :id="id" :class="className" :style="{height:height,width:width}" />
</template>

<script>
import * as echarts from 'echarts'
import resize from './mixins/resize'
import tdTheme from './mixins/theme.json' // 引入默认主题

export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: 'chart'
    },
    id: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '200px'
    },
    height: {
      type: String,
      default: '200px'
    },
    eventClick: {
      type: Function,
      default: () => {}
    }
  },
  data() {
    return {
      chart: null
    }
  },
  mounted() {
    echarts.registerTheme('tdTheme', tdTheme) // 覆盖默认主题(自定义预设主题)
    this.initChart()
  },
  beforeDestroy() {
    if (!this.chart) {
      return
    }
    this.chart.dispose()
    this.chart = null
  },
  methods: {
    initChart(chartOption) {
      this.chart = echarts.init(this.$el, 'tdTheme')
      this.chart = echarts.init(document.getElementById(this.id))
      if (chartOption) {
        this.chart.setOption(chartOption)
        if (this.eventClick) {
          this.chart.on('click', this.eventClick)
        }
      }
    }
  }
}
</script>

// 页面大小发生改变时,重绘图表
// resize.js
import { debounce } from '@/utils'

export default {
  data() {
    return {
      $_sidebarElm: null
    }
  },
  mounted() {
    this.__resizeHandler = debounce(() => {
      if (this.chart) {
        this.chart.resize()
      }
    }, 100)
    window.addEventListener('resize', this.__resizeHandler)

    this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
    this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.__resizeHandler)

    this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
  },
  methods: {
    // use $_ for mixins properties
    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
    $_sidebarResizeHandler(e) {
      if (e.propertyName === 'width') {
        this.__resizeHandler()
      }
    }
  }
}



第三步

页面开发完成后,引入插件,使页面放大缩小的同时可以自适应,这里用到lib-flexible和postcss- pxtorem

  • postcss-pxtorem:自动把px转成rem
  • lib-flexible:页面自适应插件

npm install lib-flexible --save-dev
npm install postcss-pxtorem@5.1.1 --save-dev

特别注意!

修改 node_modules/lib-flexible/flexible.js 中的大屏自适应函数,直接替换函数即可

function refreshRem(){
    var width = docEl.getBoundingClientRect().width;
    if (width / dpr < 540) {
        width = 540 * dpr;
    }else if(width / dpr > 1920){
        width = 1920 * dpr
    }
    var rem = width / 10;
    docEl.style.fontSize = rem + 'px';
    flexible.rem = win.rem = rem;
}
屏幕最大最小宽:540/1920(按设计稿)

vue.config.js 配置

module.exports = {
css: {
    sourceMap: false,
    loaderOptions: {
      css: {
        // options here will be passed to css-loader
      },
      postcss: {
        // options here will be passed to postcss-loader
      },
    },
  },
 }

vue.config.js 同级新建 postcss.config.js

module.exports = {
  plugins: {
    autoprefixer: {},
    'postcss-pxtorem': {
      rootValue: 192, // 结果为:设计稿元素尺寸/10
      propList: ['*'], // 是一个存储哪些将被转换的属性列表,这里设置为['*']全部,假设需要仅对边框进行设置,可以写['*', '!border*']
      unitPrecision: 5, // 保留rem小数点多少位
      // selectorBlackList: ['.radius'],  //则是一个对css选择器进行过滤的数组,比如你设置为['fs'],那例如fs-xl类名,里面有关px的样式将不被转换,这里也支持正则写法。
      replace: true, // replace (Boolean) Replaces rules containing rems instead of adding fallbacks.
      mediaQuery: false, // 媒体查询( @media screen 之类的)中不生效
      minPixelValue: 12, // px小于12的不会被转换
      exclude: e => { // 指定文件跳过px转rem
        if (/src(\\|\/)views(\\|\/)siteScreen/.test(e)) {
          return false
        }
        return true
      }
    }
  }
}


优化

长时间在页面停留,需要定时刷新某些图表数据,或每天哪个时间刷新,每月一刷新...因此需要一个以下函数⬇️

// 轮询函数,每天定时发请求
/*
*  @params {String}fn  时间结束时要调用的函数名
*/
polling(fn) {
  const nowTemp = this.$dayjs().valueOf() // 获取当前时间戳
  
  const nextTemp = new Date(this.$dayjs().add(1, 'hour').format('YYYY-MM-DD HH:mm:ss').substr(0, 14) + '00:00').getTime()// 获取下个小时时间戳
  const tomorrowTemp = new Date(this.$dayjs().add(1, 'days').format().substr(0, 10) + ' 00:00:00').getTime() // 获取今天24:00的时间戳

  const residueTemp = nextTemp - nowTemp // 距离下个时间点还有多久
  this.pollingST = setTimeout(() => {
    clearTimeout(this.pollingST)
    this[fn]() // 重新请求函数
  }, residueTemp)
}

// 记得清除定时器
beforeDestroy() {
  clearTimeout(this.pollingST)
}
  
// 定义变量
data() {
  return {
    pollingST: null,
  }
}
  
// 鼠标移入移出刷新
@mouseover="mouseOver" @mouseleave="mouseLeave"
mouseOver() {
  clearTimeout(this.pollingST)
  this.pollingST = null
},
mouseLeave() {
  this.setMonthChange()
},

专门服务大屏的组件库:datav