在 vue 项目使用 echarts 的场景中,如下三点不容忽视:1. 可视化的数据每每是异步加载的;2. 若一个页面存在大量的图表( 尤为当存在关系图和地图时 ),每每会致使该页面的渲染速度很慢并可能在几秒内卡死,产生极差的用户体验。3. 引入 echarts 组件致使编译后的文件过大从而使得首次访问的加载极慢。关于第三点,你们能够参考以前的撰文 优化 Vue 项目编译文件大小。如下针对上述前两点,给出数据异步、延迟渲染的 echarts vue 组件的设计和实现方式,并对实现之中可能存在的问题进行介绍。
首先,咱们须要把 echarts 使用中公共的部分抽离出来,造成基础组件。html
让咱们在 官网 - 5 分钟上手 ECharts 教程中找到使用 echarts 的步骤:vue
# 1. 获取一个用于挂在 echarts 的 DOM 元素 let $echartsDOM = document.getElementById('echarts-dom') # 2. 初始化 let myEcharts = echarts.init($echartsDOM) # 3. 设置配置项 let option = {...} # 4. 为 echarts 指定配置 myEcharts.setOption(option)
由上可知,在 echarts 使用中,除第三步设置配置项之外,其余的步骤都是重复的,便可以抽离出来放入组件中统一实现。编程
首先咱们书写一个简单 ehcart.vue
,其中,配置项直接复制于官网的教程示例。segmentfault
<style scoped> .echarts { width: 100%; height: 100%; } </style> <template> <div> <div class="echarts" id="echarts-dom"></div> </div> </template> <script> import echarts from 'echarts' export default { name: 'echarts', data() { return {} }, 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) } } </script>
而后在App.vue
中引入这一组件,并设置 echarts 的宽高:api
<style> .echarts-container{ width: 100%; height: 20rem; } </style> <template> <div id="app"> <i-echart class="echarts-container"></i-echart> </div> </template> <script> import iEchart from './components/echart' export default { name: 'app', components: { iEchart } } </script>
刷新页面后,便可看到柱状图。数组
因为咱们须要抽离 option 部分,最好的方式是将其做为组件的属性,即 props 交由调用方配置:app
# echart.vue import echarts from 'echarts' export default { name: 'echarts', props: { option: { type: Object, default(){ return {} } } }, data() { return {} }, mounted() { let $echartsDOM = document.getElementById('echarts-dom') let myEcharts = echarts.init($echartsDOM) let option = this.option myEcharts.setOption(option) } }
而后咱们能够将 option 配置抽离到组件调用方,并经过「传参」的方式进行调用:echarts
<i-echart :option="option" class="echarts-container"></i-echart>
以前咱们注意到,在 option 参数中,咱们给出了默认值 {},即空对象。这样作实际上是有问题的,即在 echarts 中,若是传入的 option 配置对象不含有 series 键,就会抛出错误:dom
Error: Option should contains series.
默认值处理是须要存在的,即当调用方传入的对象为空或不存在 series 配置时,应在页面上显示一些提示( 对用户友好的提示,而不是对编程人员 ),即避免因报错而形成空白的状况。异步
此外,当咱们像以前那样给 option 这一参数进行类型限制后,假若调用方传入非对象类型,Vue 会直接抛出错误——这一结果也不是咱们想要的。咱们应该取消类型限制,并在 option 发生变化时进行依次如下判断:
1. 是否为对象; 2. 是否为空对象; 3. 是否包含 series 键; 4. series 是否为数组; 5. series 数组是否为空。
代码实现以下:
function isValidOption(option){ return isObject(option) && !isEmptyObject(option) && hasSeriesKey(option) && isSeriesArray(option) && !isSeriesEmpty(option) } function isObject(option) { return Object.prototype.isPrototypeOf(option) } function isEmptyObject(option){ return Object.keys(option).length === 0 } function hasSeriesKey(option){ return !!option['series'] } function isSeriesArray(option) { return Array.isArray(option['series']) } function isSeriesEmpty(option){ return option['series'].length === 0 }
而后,当判断 option 符合上述三种状况时,在页面上显示如「数据为空」之类的提示:
import echarts from 'echarts' export default { name: 'echarts', props: { option: { default(){ return {} } } }, data() { return { } }, mounted() { //# 1. 获取一个用于挂在 echarts 的 DOM 元素 let $echartsDOM = document.getElementById('echarts-dom') //# 2. 初始化 let myEcharts = echarts.init($echartsDOM) //# 3. 设置配置项 let option = {...} //# 4. 为 echarts 指定配置 myEcharts.setOption(option) this.myEcharts = myEcharts this.checkAndSetOption() }, watch: { option(option){ this.checkAndSetOption() } }, methods: { checkAndSetOption(){ let option = this.option //配置等于父组件传过来的数据 if(isValidOption(option)){ this.myEcharts.setOption(option); //渲染出来 this.myEcharts.hideLoading(); //隐藏加载动画 }else{ this.myEcharts.showLoading(); //加载动画 } } } }
这里在书写代码时,有如下几点须要注意:
document.getElementById()
的返回结果为空,不能直接使用 echarts.init()
,不然会抛出错误:Error: Initialize failed: invalid dom
;immediate: true
使得 watch
钩子可以在属性初始化赋值时被触发,但这样作是不合适的。由于这样设置以后,在 option 初始化从而触发 watch 时,用于挂载 echarts 的 DOM 元素还未存在于页面中,从而致使出现 TypeError: Cannot read property 'setOption' of null
的错误。咱们要重点注意 echarts 做用的生命周期,这一点后续还会涉及。在实际场景中,用于渲染的数据经常是异步获取的,在异步加载数据之中,咱们可能须要在页面中显示如「正在加载...」的字样来表示加载过程正在进行以提升用户体验。而加载过程就组件而言是没法直接获取的,因此,咱们须要使用某一参数用于进行加载信息的显示
ECharts 默认有提供了一个简单的加载动画。只须要调用 showLoading 方法显示。数据加载完成后再调用 hideLoading 方法隐藏加载动画。
//在App.vue中模拟3秒后获取数据 data() { return { option: {} } }, created(){ setTimeout(()=>{ this.option={ title: { text: 'ECharts 入门示例' }, tooltip: {}, legend: { data: ['销量'] }, xAxis: { data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"] }, yAxis: {}, series: [{ name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] }] } console.log(this.option); },3000) }
而后就能够在echarts组件里调用了
methods: { checkAndSetOption(){ let option = this.option //配置等于父组件传过来的数据 if(isValidOption(option)){ this.myEcharts.setOption(option); //渲染出来 this.myEcharts.hideLoading(); //隐藏加载动画 }else{ this.myEcharts.showLoading(); //加载动画 } } }
当传入的 option 值不符合规定时。基于这一标识,咱们能够对 echarts 组件进行优化,当 option 不合法或数据为空时给出提示信息而不是显示空白甚至报错。