概述
在大数据盛行的今天,数据可视化变得越来越广泛。而在前端工作中,数据可视化用得最多的,可能就是图表了。在众多的图表插件中,echarts以其良好的性能和完善的API,图表的多样性和功能的完整性,被广大开发者认可,成为了前端图表使用最多的工具,所以,今天我就简单的讲一下,如何在vue中更优雅的使用echarts。
第一步,下载echarts我就不多说了:npm install echarts.
然后我们看一下一般人(刚开始用vue或echarts)的使用方法,大概是这个样子:
<template>
<div>
<div ref="chartColumn" style="width:100%; height:400px;"></div>
<button @click="changeOption">点击改变内容</button>
</div></template> <script>
import echarts from 'echarts'
export default {
data() {
return {
chartColumn: null,
option:{
title: {
text: '普通图表'
},
tooltip: {},
xAxis: {
data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
},
data:[5, 20, 36, 10, 10, 20,5, 20, 36, 10, 20, 36, 10, 10, 20,5, 20, 36, 10]
}
},
methods: {
changeOption(){
var r = Math.floor(Math.random()*12);
//splice会改变原来的数组
//var data = this.data.splice(r,6);
var d = this.data.slice(r,r+6);
this.option.series[0].data = d;
this.columnChart.setOption(this.option);
},
initChart() {
this.chartColumn = echarts.init(this.$refs.chartColumn);
this.chartColumn.setOption(this.option);
}
},
mounted: function () {
this.initChart()
}
}</script>复制代码
上面的代码,虽然功能实现了,也没什么错误,但是需要优化的地方很多。
首先,我们考虑到多个地方需要用到echarts,封装一个组件出来,就像下面这样:
组件部分:
// components/chart-block.vue <template>
<div ref="chartEl" style="height:100%"></div></template><script>
import echarts from 'echarts';
export default {
data(){
return {
chart:null
}
},
props:{
option:{
type:Object
}
},
watch:{
option:{
handler(newValue, oldValue) {
this.chart.setOption(newValue);
},
// 因为option是个对象,而我们对于echarts的配置项,要更改的数据往往不在一级属性里面
// 所以这里设置了deep:true,不知道该属性的可以看一下vue的文档
deep: true
}
},
mounted(){
this.chart = echarts.init(this.$refs.chartEl);
this.chart.setOption(this.option);
}
}</script>复制代码
然后使用它:
<template>
<div>
<div id="chartColumn" style="width:100%; height:400px;">
<chart-lock :option="option"></chart-lock>
</div>
<button @click="changeOption">点击改变内容</button>
</div></template> <script>
import chartBlock from '@/components/chart-block.vue'
export default {
components:{
chartBlock
},
data() {
return {
option:{
//... 省略其他属性
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
},
data:[5, 20, 36, 10, 10, 20,5, 20, 36, 10, 20, 36, 10, 10, 20,5, 20, 36, 10]
}
},
methods: {
changeOption(){
var r = Math.floor(Math.random()*12);
//splice会改变原来的数组
//var data = this.data.splice(r,6);
var d = this.data.slice(r,r+6);
this.option.series[0].data = d;
}
}
}</script>复制代码
和之前的比起来,我们看看封装后的组件做了什么:
1、不用给每个图表指定ref属性了
2、不用定义图表变量了
(1和2在我们同一个页面有多个图表时,减少了很多不必要的变量)
3、不用自己初始化图表了
4、数据改变时,我们自动监听,再也不需要手动处理了
(3和4在我们同一个页面有多个图表时,减少了重复逻辑的工作量)
上面针对的,是同一个页面有多个图表时的优化。接下来,我们继续优化,如果一个组件有多个页面都要用到,我们就该考虑把它注册为全局的,减少引用。代码如下:
// components/chart-block.vue <template>
<div ref="chartEl"></div></template><script>
import echarts from 'echarts';
var ChartBlock = {
name:'ChartBlock', // 这里加个name属性,用于注册使用
... //其他的属性
}
/* 注册组件的方法 */
ChartBlock.install = function(Vue) {
Vue.component(ChartBlock.name, ChartBlock);
};
export default ChartBlock;</script>复制代码
main.js全局注册
import ChartBlock from '@/components/chart-block.vue'Vue.use(ChartBlock)复制代码
在需要使用组件的页面,下面的代码就不需要了
//import chartBlock from '@/components/chart-block.vue' export default {
components:{
...
//chartBlock
}
...}复制代码
好了,到这里已经解决了组件的复用性,以后再也不用引入和声明组件了。接下来再做点其他的。很多时候,我们的图表可能都需要跟随窗口进行实时的动态改变,每个组件都单独写,显然不现实,那我们最好的办法,就是把跟随窗口改变的代码直接写在组件里面,需要注意的是,一定要在组件销毁时移除窗口改变的监听。继续完善我们的组件,如下:
var ChartBlock = {
name:'ChartBlock',
data(){
return {
chart:null
}
},
props:{
option:{
type:Object
}
},
methods:{
returnChartToParent(){
this.$emit('chartReady',this.chart);
}
},
watch:{
option:{
handler(newValue, oldValue) {
this.chart.setOption(newValue);
},
deep: true
}
},
mounted(){
this.chart = echarts.init(document.getElementById(this.id));
this.chart.setOption(this.option);
// 添加窗口改变时的监听,跟随实时窗口改变
var chart = this.chart;
this.chart.__resize = function(){
chart.resize();
};
setTimeout(() => {
window.addEventListener('resize',this.chart.__resize);
}, 200);
},
beforeDestroy() {
// 移除窗口改变监听
window.removeEventListener('resize',this.chart.__resize);
}
}复制代码
有了上面的补充,以后再也不用担心图表响应的问题了,只管调用即可。但是,这样就OK了吗?作为一个好(bushitailan)的开发,我们要的可不只是功能,还要考虑性能的问题啊。
第一点:像窗口改变大小这种事件,一旦存在拖动,将发生得太频繁,我们很有必要做一下节流处理(不知道函数节流的,自行了解一下,算是前端必须掌握的基础技能哦)。解决办法,自然就是添加一个节流函数,继续看代码,主要改变的就是mounted函数,其他不变。
var ChartBlock = {
name:'ChartBlock',
...
mounted(){ // 添加函数节流处理
this.chart = echarts.init(document.getElementById(this.id));
this.chart.setOption(this.option);
// 节流函数,来自Lodash,这里可以自己写一个简单点的
// 如果有多个地方用到,也可以使用引入的方式
function throttle(func, wait, options) {
let time, context, args, result;
let previous = 0;
if (!options) options = {};
let later = function() {
previous = options.leading === false ? 0 : new Date().getTime();
time = null;
func.apply(context, args);
if (!time) context = args = null;
};
let throttled = function() {
let now = new Date().getTime();
if (!previous && options.leading === false) previous = now;
let remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (time) {
clearTimeout(time);
time = null;
}
previous = now;
func.apply(context, args);
if (!time) context = args = null;
} else if (!time && options.trailing !== false) {
time = setTimeout(later, remaining);
}
};
return throttled;
};
var chart = this.chart;
this.chart.__resize = throttle(function(){
chart.resize();
},200);
setTimeout(() => {
window.addEventListener('resize',this.chart.__resize);
}, 200);
},
beforeDestroy() {
window.removeEventListener('resize',this.chart.__resize);
}
}复制代码
第二点:也是更重要的一点,从vue 的角度出发,我们把图表的 option 写在 data 里,是很浪费性能的。为什么这么说呢,因为 vue 的数据改变监听实质上就是对 data 对象进行逐层循环,为每一个属性添加监听。而我们图表的数据对象,只是我们图表需要的一些配置项,压根不参与业务逻辑,一个简单的对象还好,但复杂的 echarts 图表,一个option 上100个属性,如果一个页面再有多个图表的话,得额外添加多少没用的监听器,可想而知。所以,我的建议是,把 option 数据写到 data 之外,然后通过调用 echarts 的 setOption 方法设置数据。既然如此,那我们就得在chart-block组件里暴露出我们的setOption方法,以供父组件调用了。继续修改代码:
<template>
<div ref="chartEl" style="height:100%;"></div></template><script>
import echarts from 'echarts';
var ChartBlock = {
name:'ChartBlock',
data(){
return {
chart:null
}
},
// 去除props和watch,添加methods
methods:{
setOption(option){
this.chart && this.chart.setOption(option)
}
},
mounted(){
... //同上
},
beforeDestroy() {
window.removeEventListener('resize',this.chart.__resize);
}
}
/* 注册方法 */
ChartBlock.install = function(Vue) {
Vue.component(ChartBlock.name, ChartBlock);
};
export default ChartBlock;</script>复制代码
使用如下:
<template>
<div>
<div id="chartColumn" style="width:100%; height:400px;">
<!--少了option,多了ref,用于调用setOption方法-->
<chart-lock ref="chart1"></chart-lock>
</div>
<button @click="changeOption">点击改变内容</button>
</div></template> <script>
import chartBlock from '@/components/chart-block.vue'
// echarts图表的配置数据写在外面,而不是data里
let option1 = {
//... 省略其他属性
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
let data = [5, 20, 36, 10, 10, 20,5, 20, 36, 10, 20, 36, 10, 10, 20,5, 20, 36, 10]
export default {
components:{
chartBlock
},
data() {
return {
}
},
methods: {
changeOption(){
var r = Math.floor(Math.random()*12);
var d = data.slice(r,r+6);
option1.series[0].data = d;
this.$refs.chart1.setOption(option1);
}
},
mounted(){
this.$refs.chart1.setOption(option1);
}
}</script>复制代码
这样一来,通过一个组件,我们就把echarts图表的复用性,响应性(还自带节流处理),以及数据分离都解决了,是不是跟一开始的代码比起来,优雅了很多呢。
好了,本文到此结束。文章如有写得不对或不足的地方,欢迎指出。如果有什么不明白的,可以通过留言提问。
最后,站在产品的角度说句话,我们可以给图表添加个 type 的 props 属性,在数据没拿到之前,根据type,展示不同的默认图,这样是不是比空白好了很多呢?
原文地址:liguixing.com/archives/10…
最后
以上就是威武大船为你收集整理的在vue中如何优雅的使用echarts的全部内容,希望文章能够帮你解决在vue中如何优雅的使用echarts所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复