【echarts】问题集锦-使用篇

557 阅读5分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

前言

本集锦在前后端分离的架构下,webpack打包、vue.js框架的技术下遇到的使用问题集锦。

(绘图问题集锦详见另一篇:juejin.cn/post/708329…

在 webpack 中使用 ECharts 详见官方文档: echarts.baidu.com/tutorial.ht…

一、vue的keep-alive导致echarts获取不到dom

keep-alive的用法

官方文档:

https://cn.vuejs.org/v2/guide/components-dynamic-async.html#%E5%9C%A8%E5%8A%A8%E6%80%81%E7%BB%84%E4%BB%B6%E4%B8%8A%E4%BD%BF%E7%94%A8-keep-alive https://cn.vuejs.org/v2/api/#keep-alive https://cn.vuejs.org/v2/guide/migration.html#keep-alive-%E5%B1%9E%E6%80%A7-%E6%9B%BF%E6%8D%A2

注意点

1、和<transition>连用

<transition>一起使用时,确保把内容包裹在内:

<transition>
  <keep-alive>
    <component v-bind:is="view"></component>
  </keep-alive>
</transition>

可以理解为,因为keep-alive和router-view是连一起用的,拆开就没有保持缓存的作用了!!!

就连当前页面watch监控'$route'都会出错……

2、和echarts一起用

若当前路由A用到echarts,然后想使用keep-alive保持缓存。

在清空浏览器缓存后,初次登录当前页面A没有问题。

跳转离开,再次进入A,发现echarts图形无法正常绘制,报错获取不到dom的高度和宽度。

通过Element查看当前dom的高宽是存在的。

费解……

于是在生命周期钩子函数activated中获取dom节点查看高宽确实为0,即便使用setTimeout延迟获取dom节点查看高宽仍然为0。直到去掉keep-alive,一切恢复正常。

所以……

keep-alive还是不要用在有echarts的地方了。

二、echarts的div高度一定要定义

高度不定义可能会导致加载了但没显示出来!

eecharts的div高度一定要定义!!

当然了宽度最好也定义!!

三、elementUI的tab页中画echarts图形问题

elementUI的tab页通过v-show控制tab页存在但不展示(v-if不存在v-show存在),但是非当前tab的高宽没有!

导致不能够一次性把所有tab页的图画上,会提示dom高宽未定义!!!

所以可通过切换tab页时将当前数值传递给echarts进行绘制。

四、主题json引入问题

1、json引入和import导入

obj = JSON.parse('/static/***.json')

parse不能这么引入json,于是我import一下吧

import from '/static/***.json'

并没有用啊,谁告诉你import这么用的!!!

2、那试试jquery读json文件咯

jQuery.getJSON("/static/***.json", "", function(response) {
    obj = JSON.parse(response)
})

还是报错,因为response已经是对象了!不需要再JSON.parse!

3、于是直接注册主题吧

jQuery.getJSON("/static/***.json", "", function(response) {
    echarts.registerTheme('themeName', response)
})
let myChart = echarts.init(document.getElementById('test'), 'themeName')

还是没用啊,不对是页面闪现了一下,因为jquery异步,又回到默认了。

4、所以将init放到jQuery处理后

如下总算能引入自定义的主题色了

jQuery.getJSON("/static/***.json", "", function(response) {
    echarts.registerTheme('themeName', response)
    echarts.init(document.getElementById('test'), 'themeName')
})

5、最后其实import很好用啊,这里有了import还要什么jquery。

import chartOpt from './***.json'
let self = this
echarts.registerTheme('themeName', chartOpt)
self.initChart()

呵呵呵,其实这样就好了。

五、echarts3D图引入需要额外下载安装echarts-gl

package.json中的dependencies,添加"echarts-gl": "^1.1.1",会有提示尚未安装

去项目所在根目录执行命令npm install echarts-gl --save

webpack会去下载包save指令会将下载的详情保存至package-lock.json文件中

在使用echarts的时候import 'echarts-gl'即可。

六、echarts缓存问题

当series[]中包含多个对象多组data[]时:

以折线图为例,能实现一条折线到两条的增加,但是当series[]中data[]减少为一条折线数据时,仍然会显示之前的两条折线。

思考过程:

找到this.myChart.setOption(this.currentData)处,打印this.currentData

其中series[]明明只有一个,但是会画出两条甚至多条折线图!!!

猜想是不是有缓存,百度echarts缓存清理得知,需要在setOption之前调用clear方法,即:

this.myChart.clear()
this.myChart.setOption(this.currentData)

果然问题解决。

七、echarts宽度变化后重绘的问题

window.onresize监听宽度变化毛线用没有

定时器定时查询echarts外层div的宽度不建议使用

addEventListener加载监听事件到echarts外层div总是失效

所以,可以在最外层加addEventListener宽度,变化了存起来,然后computed属性读取vuex里面存的宽度,然后watch全局宽度变量变化了就重新绘制echarts。

但是我还是喜欢定时器哈哈哈哈哈

定时器:

  • 用完一定要记得关闭,用之前最好先clearTimeout!!!
  • 用完一定要记得关闭,用之前最好先clearTimeout!!!
  • 用完一定要记得关闭,用之前最好先clearTimeout!!!

记住这样:

somefuntion () {
    // 需要定时执行的方法
    clearTimeout(this.timer)
    this.timer = setTimeout(somefuntion, 30000)
}
destroyed () {
    clearTimeout(this.timer)
}

解释: 写在setTimeout()之前的清除,只是为了保证当前定时器只开启了一个。

先清除缓存中的定时器,然后开启一个30s后执行一次的定时器,30s后先清除还有没有定时器(一般没有),新建一个定时器,以此循环。

比起setInterval建议使用setTimeout只是延迟执行一次

八、myChart对象定义位置的区别

自己定义的echarts组件,通常把myChart = echarts.init(document.getElementById(this.id), 'theme-mychart')挂在

data () {
    return {
        myChart: null
    }
}

同事说这样导致vue对象太大??不太理解

但是经同事建议将myChart定义在外部,如下:

let myChart = []
export default {
    methods: {
        echartsShow () {
          echarts.registerTheme('theme-mychart', chartTheme)
          myChart = echarts.init(document.getElementById(this.id), 'theme-mychart')
        },
        echartsResize () {
          // 重绘图像
          myChart.resize()
        }
    }
}

这有个问题,同一路由下多个echarts组件引入,后面的myChart会覆盖前面的,导致重绘图像只能操作最后一个myChart!

最后借鉴隔壁项目组将同一路由下的myChart放到数组中定义在外部,myChart是临时变量,重绘时遍历数组如下即可:

let myChartArr = []
methods: {
    echartsShow () {
      echarts.registerTheme('theme-mychart', chartTheme)
      let myChart = echarts.init(document.getElementById(this.id), 'theme-mychart')
      // 清理echarts缓存
      myChart.clear()
      // 绘制图像
      myChart.setOption(this.currentData)
      // 判断是否需要往数组里添加myChart对象
      let replace = null
      for (let i = 0; i < myChartArr.length; i++) {
        if (myChartArr[i]._dom.id === this.id) {
          replace = i
          break
        }
      }
      if (replace !== null) {
        myChartArr.splice(replace, 1, myChart)
      } else {
        myChartArr.push(myChart)
      }
    },
    echartsResize () {
      // 重绘图表
      for (let i = 0; i < myChartArr.length; i++) {
        if (this.id === myChartArr[i]._dom.id) {
          myChartArr[i].resize()
          break
        }
      }
    }
}

九、动态追加数据效果

修改series中的data再重新绘制echarts会导致动画从头到尾重新绘制。

比如说随着时间推移数据追加,如果重新绘制echarts会导致动画从第一个数值开始刷新到最后一个,体验很不好。

参考官方案例:

echarts.apache.org/examples/zh…

关键点在:

不要重新创建echarts对象,只需对原来的echarts对象.setOption(newOption)即可。