在vue下封装echarts公共组件的总结

这几天公司里边有一个项目,叫做日控制台,该项目是在webview下的一个webapp,使用vue构建,项目中要求使用许多自定义的图表。考察了许多图表组件之后,发现echarts是所有表库中,最灵活,特效最好看的一种。

一、构建基础公共组件

1. 实现基础功能

在echart官网上搜索到,如何使用

# 1. 获取一个用于挂在 echarts 的 DOM 元素
let $echartsDOM = document.getElementById('echarts-dom')

# 2. 初始化
let myEcharts = echarts.init($echartsDOM)

# 3. 设置配置项
let option = {...}

# 4. 为 echarts 指定配置
myEcharts.setOption(option)

使用echart的步骤也就这几部,就是先获取到承载echart实例的dom实例,然后调用init()方法初始化图标实例,最后调用setOption()方法传入配置项
这几步都要在vue的mounted方法下实现.

mounted() {
      let $echartsDOM = document.getElementById('echarts-dom')
      let myEcharts = echarts.init($echartsDOM)
      let option = {
        title: {
          text: 'ECharts 入门示例'
        },
        tooltip: {},
        legend: {
          data: ['销量']
        },
        xAxis: {
            data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
        },
        yAxis: {},
        series: [{
            name: '销量',
            type: 'bar',
            data: [5, 20, 36, 10, 10, 20]
        }]
    }
    myEcharts.setOption(option)
  }
}

注:在 Vue 中,首先我们需要使用 import echarts from 'echarts' 以引入 echarts。

二、组件化

思路很简单,就是将业务上用到的图表,比如柱状图、折线图,通通封装成组件,然后再main app文件中调用,通过分析,可以通过传props,来改变setOption()方法中的对象,达到封装不同图表组件的目的。

 

将之前的options转移到main app中的data对象之中。
注:echarts图表要求承载的容器具有固定的宽高才能正常显示

.echarts-container{
  width: 100%;
  height: 20rem;
}

1. 组件优化-props的series校验

如果在传入组件的props中传入了空对象,就会发现,图表会抛出一个错误,即

Error: Option should contains series.

原因就是传入的 option 配置对象不含有 series 键,所以,默认值处理是需要存在的,即当调用方传入的对象为空或不存在 series 配置时,应在页面上显示一些提示( 对用户友好的提示,而不是对编程人员 ),即避免因报错而造成空白的情况。
此外,当我们像之前那样给 option 这一参数进行类型限制后,倘若调用方传入非对象类型,Vue 会直接抛出错误——这一结果也不是我们想要的。我们应该取消类型限制,并在 option 发生变化时进行依次以下判断:

// 1. 是否为对象;
export function isObject(option) {
  return Object.prototype.isPrototypeOf(option)
}

// 2. 是否为空对象;
export function isEmptyObject(option) {
  return Object.keys(option).length === 0
}

// 3. 是否包含 series 键;
export function hasSeriesKey(option) {
  return !!option['series']
}

// 4. series 是否为数组;
export function isSeriesArray(option) {
  return Array.isArray(option['series'])
}

// 5. series 数组是否为空。
export function isSeriesEmpty(option) {
  return option['series'].length === 0
}

export function isValidOption(option) {
  return isObject(option) && !isEmptyObject(option)
    && hasSeriesKey(option)
    && isSeriesArray(option) && !isSeriesEmpty(option)
}

然后在组件中引入最后的isValidOption方法作为判断,我们先使用一个watch监听options的变化

 watch: {
    options(options){
      this.checkAndSetOption()
    }
  },
  methods: {
    checkAndSetOption(){
      let options = this.options
      if(isValidOption(options)){
        this.myEcharts.setOption(options)
        this.isOptionAbnormal = false
      }else{
        this.isOptionAbnormal = true
      }
    }
  }

这里的checkAndSetOption方法是判断传入的option是否合法,如果合法,就执行setOption,isOptionAbnormal变量是监控页面是否显示options非法的flag。
同样的dom样式上的改变,也要使用v-show来判断isOptionAbnormal是否要渲染图表和渲染错误信息。


    数据为空
    
      
    

.oc_echarts_container, .echarts {
  width: 100%;
  height: 100%;
}

.shadow {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 1rem;
  color: #8590a6;
}

2. 增强组件功能 - 数据加载提示


        数据加载中...
 

在组件内部需要一个外部的props,isLoading,但是这里需要注意,在 Vue 中,v-show 使用 display 控制组件的显隐。而当 echart init 的时候,如果其挂载 DOM 的 v-show 处于 false 状态,则其 init 的对象宽高都是 0。即使之后 v-show 状态改变,由于 mounted 生命周期不会再次触发,从而使得 echarts 显示不正常。所以需要使用css的visibility来控制显隐。

computed: {
    isChartVisible() {
       return !this.isLoading && !this.isOptionAbnormal
    }
  },
 
      
    

3. 组件复用-随机ID

echarts 进行 init 挂载时使用的是 DOM 元素的 ID。而在组件中,我们设置的 ID 是固定的( 注意与 scoped css 进行区分 )。如果多个组件的 ID 是相同的,只有一个组件会被 echarts 挂载。
所以我们要设定一个随机的randomId,赋值到承载echarts图表的dom元素的id中


      
    

三、延迟加载

延迟加载是组件的一个优化,在业务的开发中可以看到,一个页面往往有着许多的图表,图标伴随着许多异步请求和canvas渲染,如果一次性渲染所有的图表会导致许多的性能问题。这里想到的一个解决方案就是延迟加载。
用通俗的话讲就是,页面滚动到哪张图表就去渲染哪一张图表。
完成这一功能需要以下步骤:

  1. 监听页面滚动事件;
  2. 滚动事件中获取 echarts 的位置;
  3. 在页面当前位置达到 echarts 位置的时候进行 echarts 的初始化。

1. 监听页面滚动

如果要监听页面滚动,需要用到dom的监听器,addEventListener('scroll', [funciton])。这样就能为每一个组件附上监听事件。

2. 获取当前滚动下边界和组件的上边界

这一个步骤需要封装成一个函数,checkPosition()

checkPosition() {
      let windowHeight = document.documentElement.clientHeight||window.innerHeight
      let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
      let windowBottom = scrollTop + windowHeight
      const selfTop = _.get(this.$refs, 'selfEcharts.offsetTop', 0);
      if(windowBottom >= selfTop) {
        this.isPositionReady = true
        this.checkAndSetOption()
        window.removeEventListener('scroll',  this.scrollEvent)
      }
    },

3. 初始化

data() {
    return {
      myEcharts: null,
      isOptionAbnormal: false,
      randomId: 'echarts-dom' + Date.now() + Math.random(),
      scrollEvent:  _.throttle(this.checkPosition, 500), // 滑动事件
      isPositionReady: false, //控制数据异步与页面滚动先后顺序的flag
    }
  },
mounted() {
    let $echartsDOM = document.getElementById(this.randomId)
    if(!$echartsDOM) return
    this.myEcharts = echarts.init($echartsDOM)
        // 第一次未滑动的时候
    this.checkPosition()
        //滑动之后的监听
    window.addEventListener('scroll', this.scrollEvent)
  },

checkPosition方法不仅要在scroll监听事件中调用,在组件第一次渲染的时候也要调用一次进行初始化,不然,组件无法正常渲染图表。

4.节流

组件代码经过测试之后发现,如果滚动过于快速,会不停的调用checkPosition(),关键是这个方法会不停的去setOption(),所以以上代码均采用了lodash的throttle节流方法,在500毫秒内只允许调用一次。

5. 解绑监听事件

解绑事件,组件中有设定监听器,如果该图表已经被加载了,那么这个监听器就没有作用了。

window.removeEventListener('scroll',  this.scrollEvent)

这段代码就是解绑监听器,多多少少会优化一下速度吧。因为增加监听和解绑监听的时间函数要求一致,所以在data中新增了scrollEvent,顺便把节流函数一起加了上去。

6. 请求异步控制setOption

由于用于渲染 echarts 的数据常常是异步获取的,也就是说,option 可能会在异步调用结束之后更新,从而触发 option 的 watch,进而导致 this.checkOption()执行,最终使得 setOption 在页面没有滚动到合适位置时就触发了。
为了解决这个问题,我们应该让 setOption 的过程受制于一个标识位,而该标识位会在页面滚动到合适位置时置为 true,从而杜绝由于 option 更新、触发 watch 而导致的漏洞。
首先,我们要添加一个新的 data,取名为为 isPositionReady,然后,在 checkAndSetOption() 中加入对该标识位的判断:最后,在位置检测方法 checkPosition() 中,当达到合适位置时,将该标识位置为 true

    checkPosition() {
     // ....
      if(windowBottom >= selfTop) {
        this.isPositionReady = true
        // ....
      }
    },
    checkAndSetOption() {
    // ....
      if(!this.isPositionReady) return 
      //....
    }

四、echarts重绘

这里的重绘指的是 ehcarts 中的 resize() 方法。用于在某些时刻进行 echarts 的调整,包括:

1.页面宽度改变

继续增加监听器就能完成

window.addEventListener('resize', _.throttle(() => {
    this.myEcharts.resize()
    console.log('---')
}, 500))
展开阅读全文

页面更新:2024-04-22

标签:组件   监听器   初始化   图表   宽度   加载   对象   位置   页面   方法

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top