zl程序教程

您现在的位置是:首页 >  前端

当前栏目

echarts根据上级元素的大小自动更新echarts(element-resize-detector)配合防抖解决大屏页面卡顿的问题

echarts 解决 页面 元素 大小 根据 Element 配合
2023-09-27 14:22:47 时间

echarts根据上级元素的大小自动更新echarts(element-resize-detector)

问题产生的原因:

在项目中有时需要因为其他样式的改变而被动改变echarts图例的大小,比如在我们管理系统中左侧的菜单栏的收缩,会导致右侧内容区的宽度变大,所以我们对应的echarts也要发生位置的变化:
我这里将所有echarts元素都始于一个chart组件,组价的价值主要在于生成一个dom,接受父级传入的echarts的options,并创建echarts图例:
代码:

<!--
 * @Descripttion: 
 * @version: 
 * @Author: ZhangJunQing
 * @Date: 2022-06-08 16:01:36
 * @LastEditors: ZhangJunQing
 * @LastEditTime: 2022-08-10 17:38:41
-->
<template>
  <div class="chart" ref="chartDom"></div>
</template>

<script>
export default {
  props: {
    option: {
      type: Object,
      required: true,
      default: {},
    },
  },
  data() {
    return {
      echartsInstance: null,
    };
  },
  methods: {
    init() {
      if (!this.echartsInstance) {
        let charts = this.$refs.chartDom;
        this.echartsInstance = this.$echarts.init(charts);
      }
      // this.echartsInstance.showLoading({
      //       text: '暂无数据',
      //       showSpinner: false,
      //       textColor: '#646464',
      //       maskColor: 'rgba(255, 255, 255, 1)',
      //       fontSize: '16px',
      //       fontWeight: 'bold',
      //     })
      this.echartsInstance.setOption(this.option);
      // this.echartsInstance.hideLoading()
    },
  },
  watch: {
    option: {
      handler(newOption) {
        this.echartsInstance.clear();
        this.echartsInstance.resize();
        this.echartsInstance.setOption(newOption);
      },
      deep: true
    },
  },
  mounted() {
    this.init();
  },
};
</script>

<style lang="less" scoped>
.chart {
  // width: 300px;
  // height: 300px;
  width: 100%;
  height: 100%;
}
</style>

但是有个问题,即便我们设置window自带的resize方法,但是我们改变左侧菜单的收缩,并不会出发resize方法,因为并没有改变当前页面的视图大小,于是使用了一个第三方插件,简直简直简直好用。

element-resize-detector

npm i element-resize-detector

引入:

import elementResizeDetectorMaker from "element-resize-detector"

使用:

        let myChart = elementResizeDetectorMaker();
        myChart.listenTo(this.$refs.chartDom, () => {
          this.$nextTick(() => {
            this.echartsInstance.resize();
          });
        });

我们在创建echarts实例的时候,使用即可,全部代码如下:

<!--
 * @Descripttion: 
 * @version: 
 * @Author: ZhangJunQing
 * @Date: 2022-06-08 16:01:36
 * @LastEditors: ZhangJunQing
 * @LastEditTime: 2022-08-10 17:38:41
-->
<template>
  <div class="chart" ref="chartDom"></div>
</template>

<script>
import elementResizeDetectorMaker from "element-resize-detector"
export default {
  props: {
    option: {
      type: Object,
      required: true,
      default: {},
    },
  },
  data() {
    return {
      echartsInstance: null,
    };
  },
  methods: {
    init() {
      if (!this.echartsInstance) {
        let charts = this.$refs.chartDom;
        this.echartsInstance = this.$echarts.init(charts);
        let myChart = elementResizeDetectorMaker();
        myChart.listenTo(this.$refs.chartDom, () => {
          this.$nextTick(() => {
            this.echartsInstance.resize();
          });
        });
      }
      // this.echartsInstance.showLoading({
      //       text: '暂无数据',
      //       showSpinner: false,
      //       textColor: '#646464',
      //       maskColor: 'rgba(255, 255, 255, 1)',
      //       fontSize: '16px',
      //       fontWeight: 'bold',
      //     })
      this.echartsInstance.setOption(this.option);
      // this.echartsInstance.hideLoading()
    },
  },
  watch: {
    option: {
      handler(newOption) {
        this.echartsInstance.clear();
        this.echartsInstance.resize();
        this.echartsInstance.setOption(newOption);
      },
      deep: true
    },
  },
  mounted() {
    this.init();
  },
};
</script>

<style lang="less" scoped>
.chart {
  // width: 300px;
  // height: 300px;
  width: 100%;
  height: 100%;
}
</style>

将elementResizeDetectorMaker的实例函数,变成防抖即可:

 myChart.listenTo(this.$refs.chartDom,
          () => {
            this.debounceFun(() => {
              this.echartsInstance && this.$nextTick(() => {
                this.echartsInstance.resize();
              })
            }, 18)
          }
        );
      }

debounceFun

/**
 * @param {函数} fn
 * @param {防抖时间间隔} wait
 */
//防抖函数
export const debounce = () => {
    let timer = null;
    const newDebounce = function (fn, wait, ...args) {
        return new Promise((resolve, reject) => {
            if (timer !== null) {
                clearTimeout(timer);
            }
            timer = setTimeout(_ => {
                try {
                    resolve(fn(...args));
                } catch (e) {
                    reject(e);
                }
            }, wait);
        });
    };
    return newDebounce;
};

防抖函数使用:

  data() {
    return {
      debounceFun: debounce(),
      echartsInstance: null,
    };
  },

改造之后的全部代码:
main.js

import elementResizeDetectorMaker from "element-resize-detector"
Vue.prototype.$erd = elementResizeDetectorMaker();

char:

<!--
 * @Descripttion: 
 * @version: 
 * @Author: ZhangJunQing
 * @Date: 2022-06-08 16:01:36
 * @LastEditors: ZhangJunQing
 * @LastEditTime: 2022-08-10 17:38:41
-->
<template>
  <div class="chart" ref="chartDom"></div>
</template>

<script>
// debounce
/**
 * @param {函数} fn
 * @param {防抖时间间隔} wait
 */
//防抖函数
/**
export const debounce = () => {
    let timer = null;
    const newDebounce = function (fn, wait, ...args) {
        return new Promise((resolve, reject) => {
            if (timer !== null) {
                clearTimeout(timer);
            }
            timer = setTimeout(_ => {
                try {
                    resolve(fn(...args));
                } catch (e) {
                    reject(e);
                }
            }, wait);
        });
    };
    return newDebounce;
};
 */

// this.$erd
/**
 * import elementResizeDetectorMaker from "element-resize-detector"
 * Vue.prototype.$erd = elementResizeDetectorMaker();
 */
import { debounce } from '@/utils/ToolFunctions'
export default {
  props: {
    option: {
      type: Object,
      required: true,
      default: {},
    },
  },
  data() {
    return {
      debounceFun: debounce(),
      echartsInstance: null,
    };
  },
  methods: {
    init() {
      if (!this.echartsInstance && !this.$echarts.getInstanceByDom(this.$refs.chartDom)) {
        let charts = this.$refs.chartDom;
        this.echartsInstance = this.$echarts.init(charts);

        // let myChart = ;
        // if (myChart == null) {
        //   myChart = this.$echarts.init(charts);
        //   this.echartsInstance = this.$echarts.init(charts);
        // }


        this.$erd.listenTo(this.$refs.chartDom,
          () => {
            this.debounceFun(() => {
              this.echartsInstance && this.$nextTick(() => {
                this.echartsInstance.resize();
              })
            }, 18)
          }
        );
      }
      this.echartsInstance.hideLoading()
      // this.echartsInstance.showLoading({
      //       text: '暂无数据',
      //       showSpinner: false,
      //       textColor: '#646464',
      //       maskColor: 'rgba(255, 255, 255, 1)',
      //       fontSize: '16px',
      //       fontWeight: 'bold',
      //     })
      this.echartsInstance.setOption(this.option);
      // this.echartsInstance.hideLoading()
    },
  },
  watch: {
    option: {
      handler(newOption) {
        // 显示暂无数据
        if (newOption.error) {
          // 实例生成
          if (this.echartsInstance) {
            this.echartsInstance.clear();
            this.echartsInstance.showLoading({
              text: '暂无数据',
              showSpinner: false,
              textColor: '#646464',
              maskColor: 'rgba(255, 255, 255, 1)',
              fontSize: '16px',
              fontWeight: 'bold',
            })
          } else {
            // 实例不存在
            this.$nextTick(() => {
              // 判断当前dom节点有没有 被 注册
              if (!this.$echarts.getInstanceByDom(this.$refs.chartDom)) {
                let charts = this.$refs.chartDom;
                this.echartsInstance = this.$echarts.init(charts);
              }
              this.echartsInstance.resize();
              this.echartsInstance.showLoading({
                text: '暂无数据',
                showSpinner: false,
                textColor: '#646464',
                maskColor: 'rgba(255, 255, 255, 1)',
                fontSize: '16px',
                fontWeight: 'bold',
              })
            })
          }
        } else {
          // 正常流程
          if (this.echartsInstance) {
            this.$nextTick(() => {
              this.echartsInstance.clear();
              this.echartsInstance.resize();
              this.echartsInstance.hideLoading()
              this.echartsInstance.setOption(newOption);
            })
          }
        }
      },
      deep: true,
      immediate: true
    },
  },
  mounted() {
    this.init();
  },
  destroyed() {
    this.echartsInstance = null
    this.$refs.chartDom && this.$erd.removeAllListeners(this.$refs.chartDom)
    this.$refs.chartDom && this.$refs.chartDom.clear();
  }
};
</script>

<style lang="less" scoped>
.chart {
  width: 100%;
  height: 100%;
}
</style>