前言
- 需求 : 两个 tabpane,其中一个用来筛选数据,另一个在数据筛选完成之后才显示,里面有几个echarts饼状图,用来进行统计分析。
- 遇到的困难:
- 一开始在 tabpane直接使用 v-if,然后下面 v-if 无数据时 empty组件,有数据时 渲染饼状图。
但echarts在初始化 dom时(无论是 getElementByid 还是 ref方法),都需要有dom存在,而v-if 的特性是,有条件时 dom渲染,无条件时 dom直接不存在,这样就会使得 echarts报错。 - 那么我就想到能不能用 v-show呢?
首先我们要知道,tabpane在没数据时是不能存在的,那么v-show会使得tabpane一开始就存在,只不过display: none. (详情可以看vue官方文档,v-if和v-show的区别)。而 tabpane设为 v-if,当为false的时候,子组件生命周期也是不存在的,这样也会报错 getAttribute error。 - 既然tabpane要使用 v-if,那么echart的 div dom,能不能等 tabpane的 v-if条件为 true时,再 echarts.init 呢?
这时我想到 this.$nextTick(() =>{}). 但是echarts初始化时依旧 报错。
黔驴技穷了,那怎么办呢?
解决方法
组件化Echarts图表
- tabpane依旧是 v-if的条件渲染方式,而echarts的图表,单独组件化为一个组件,传入生成的数据作为props即可。并且需要注意的是,因为随着筛查数据的不同,图表需要有变化,所以需要一个侦听属性,来检测传入数据的变化,使得图表变化
- 具体代码示例:
<!-- 父组件.vue -->
<a-tab-pane v-if="canshow_chart" key="2" tab="">
<child-chart :chartData="chartData" />
</a-tab-pane>
<!-- echarts子组件.vue -->
<a-card>
<h1 style="margin:20px 0;text-align:center;">图表分析</h1>
<div v-show="hasData">
<a-empty/>
</div>
<div v-show="!hasData">
<div class='chart Cmin' ref='mainPay' id="mainPay" style="width: 45%;height:35rem;"></div>
<div class='chart Cmin' ref='mainDetail' id="mainDetail" style="width: 45%;height:35rem;"></div>
<div class='chart Cmin' ref='main' id="main" style="width: 45%;height:35rem;"></div>
<div class='chart Cmin' ref='mainItem' id="mainItem" style="width: 45%;height:35rem;"></div>
<div class='chart Cmin' ref='mainDepartment' id="mainDepartment" style="width: 45%;height:35rem;"></div>
<div class='chart Cmin' ref='mainDoctor' id="mainDoctor" style="width: 45%;height:35rem;"></div>
</div>
</a-card>
<!-- 渲染方法 -->
props: [ 'chartData', 'hospitalName'],
mounted() {
if(!this.chartData) {
this.hasData = true;
}
this.$nextTick(() => {
this.drawLine();
})
},
watch: {
chartData: function(val) {
this.drawLine();
}
},
data() {
return {
hasData: false,
}
},
后续又遇到的问题
- 需求:又要开发一个页面,只有一个查询框,查询后有数据,展示几个图表。
- 分析:因为又需要判断有无数据,所以还是需要v-if 操作,因此需要将图表组件化为一个子组件。
一开始想的是直接放一个子组件,在子组件里面判断有无数据,但这样发现子组件拿不到 传递的props,本来以为this.$nextTick()会更新,但并没有。 - 解决:
<a-card>
<a-empty v-if="!auditData"/>
<child-chart-2
v-else
:value1="auditData"
:value2="attendData"
:value3="picketData"
:value4="selfPayData"
:value5="obeyRuleData"
/>
</a-card>
<!-- childChart2 -->
props: [ 'value1', 'value2', 'value3', 'value4', 'value5'],
data() {
return {
auditData: this.value1,
attendData: this.value2,
picketData: this.value3,
selfPayData: this.value4,
obeyRuleData: this.value5
}
},
mounted() {
this.$nextTick(() => {
this.drawChart();
})
},