手摸手教你封装echarts自适应大小组件(节流版)

源代码

图表大小自适应-代码地址

需要效果如下(无节流版效果)

我们可以看到没有节流会有一点卡顿

Z475T0S74G.gif

思路

1、把这三个图表抽离出一个公共组件
2、在组件内进行监听窗口 window.addEventListener('resize', fn)
3、最后组件直接响应图表视图chart.resize()

笔者这里用的是vue,所以以vue为标准

1、创建公共组件chartComponent.vue

组件props接收 chartId, echarts绑定的对象domId,
组件props接收 option, echarts的options属性,
图表渲染完成事件参考之前写的一篇

创建图表公用组件chartComponent.vue

  • javascript
<script>
import * as echarts from 'echarts'
export default {
  name: 'chartComponent',
  props: {
    chartId: { type: String, required: true },//图表id
    option: { type: Object, default: () => {} }, //图表属性
    loading: { type: Boolean, default: false }// 可不写loading状态
  },
  data() {
    return {
      myChart: null,
      isFinished: false
    }
  },
  methods: {
    drawChart() {
      this.myChart.setOption(this.option, true)
    },
    chartResize() {
      this.myChart.resize()
      console.log('重置大小')
    }
  },
  mounted() {
    if (!this.myChart) {
      this.myChart = echarts.init(this.$refs[this.chartId])
    }
    //监听窗口大小变化
    window.addEventListener('resize', this.chartResize)
    this.drawChart()

    this.myChart.on('finished', () => {
      if (!this.isFinished) {
        console.log('finished')
        this.isFinished = true
        this.myChart.resize()
      }
    })
  },
  beforeDestroy() {
    //销毁window监听对象
    window.removeEventListener('resize', this.chartResize)
    if (this.myChart) this.myChart.dispose()
    this.myChart = null
  },
  watch: {
    //数据可能是异步的,用watch接听接收
    option: {
      handler(newVal) {
        const options = newVal
        this.drawChart(options)
      },
      deep: true
    }
  }
}
</script>
复制代码
  • html,css
<template>
  <div class="chart-box" :ref="chartId"></div>
</template>

<style lang="scss" scoped>
.chart-box {
  width: 100% !important;
  height: 100% !important;
}
</style>
复制代码

2、使用

  • 直接引入使用就好
  <chartComponent chartId="chart_a" :option="option"></chartComponent>
复制代码

细心的朋友发现没有节流,好了,我们在chartResize上增加节流, 没有节流会有明显的卡顿

3、增加节流

1、引入节流方法(可以自己网上找,也可以用lodash的节流),这里就不写节流的具体内容
2、在chartResize方法上绑定节流

  • chartCompont中引入throttle方法
import { throttle } from '../util/tool'

//为上面的chartResize方法增加节流
methods: {
    ...
    //绑定上节流方法
    chartResize: throttle(function () {
      this.myChart.resize()
      console.log('重置大小')
    }, 2000)
}
复制代码

4、效果 (节流版本)

vYcksxS3F7.gif

???什么东西,为什么只有最后一个图表重置大小了,其它没变化??

5、分析原因

节流确实生效了,问题是什么?
因为在一个页面内使用了多次这个组件,由于节流是异步的, 暂时只能记录最后一个组件对象
所以只会响应resize最后一个

6、解决方法

其实我们更优的方法,应该把监听窗口事件(window.addEventListener('resize', fn))抽离到最外层,而不是在组件内

我的思路-使用vuex

1、在全局中监听window.addEventListener('resize', fn),套上节流。
2、把监听到的窗口大小存在vuex
3、在我们的chartCompnent.vue组件中监听vuex的窗口大小

7、最终效果

加了节流之后,会顺畅很多

walSebLwxu.gif

8、部分优化代码,vuex,onResize提取

vuex-window模块

新建vuex的window模块,用来存放页面的宽高。

const window = {
  state: {
    //页面的宽高
    innerWH: {}
  },

  mutations: {
    SET_INNER_WH(state, val) {
      //state.innerWH = { ...Object.assign(state.innerWH, val) }
      state.innerWH = val
    }
  },

  actions: {
    setInnerWH({ commit }, val) {
      commit('SET_INNER_WH', val)
    }
  }
}

export default window

复制代码

main.js内引入的监听onResize.js文件

全局监听窗口大小,并且存入vuex

onResize.js

import { throttle } from './tool'//节流方法

//vuex对象
import store from '@/store/index'

const windowFn = throttle(
  function () {
    let innerWH = {
      innerWidth: window.innerWidth,
      innerHeight: window.innerHeight
    }
    store.dispatch('setInnerWH', innerWH)
  },
  1000,
  { leading: false }
)

//全局监听窗口大小变化事件
window.addEventListener('resize', windowFn)

复制代码

组件内的监听vuex内数据-chartComponent

chartComponent

//监听vuex内的窗口大小
watch: {
    innerWH: {
      handler() {
        console.log('窗口resize')
        this.myChart.resize()
      },
      deep: true
    }
}

复制代码

9、总结思路

全局监听窗口大小, 把窗口大小存在vuex内 ,节流在这里加上。
echarts组件中监听vuex内的窗口大小,从而响应图表大小

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享