vue封装echarts柱状图组件,调用了三次,结果自动轮播也会调用三次,然后就会出现数据错乱,轮播时乱跳动,然后就是封装了一个折线图,根据后端不同的接口调用不同的数据,但是点击多个按键之后数据就错乱了,上一次的数据没有被清除掉,导致轮播一直在几张图里面跳动
echarts跟轮播有什么关系呢?建议贴出完整代码
针对你的两个问题,分别给出如下解决思路:
这个问题的原因是因为在Vue中,每次使用组件都会重新渲染,而自动轮播也是在组件内部实现的,所以组件被重新渲染时,轮播计时器会重新启动。解决办法可以是在组件销毁时清除计时器。具体步骤如下:
export default {
data() {
return {
chartData: [], // 图表数据
timer: null, // 自动轮播计时器
}
},
...
}
export default {
mounted() {
this.timer = setInterval(() => {
this.currentIndex = (this.currentIndex + 1) % this.chartData.length;
this.renderChart();
}, 3000);
},
...
}
export default {
beforeDestroy() {
clearInterval(this.timer);
},
...
}
这样做可以确保在组件被销毁时清除计时器,从而避免轮播数据错乱的问题。这个问题的原因是在组件中没有正确地清除上一次渲染的数据,导致下一次渲染时出现混乱。解决办法可以是在每次重新渲染前,手动清空图表实例和轮播计时器,并在销毁组件时释放资源。具体步骤如下:
export default {
data() {
return {
chartData: [], // 图表数据
currentIndex: 0, // 当前显示的索引
myChart: null, // 图表实例
timer: null, // 自动轮播计时器
}
},
...
}
export default {
methods: {
clearChart() {
if (this.myChart) {
this.myChart.dispose();
this.myChart = null;
}
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
...
}
...
}
在组件的 watch 中监听数据变化,在数据变化时调用 clearChart 方法,清空上一次的图表实例和轮播计时器。export default {
watch: {
data(newValue, oldValue) {
if (newValue !== oldValue) {
this.clearChart();
this.renderChart();
}
},
...
},
...
}
export default {
beforeDestroy() {
this.clearChart();
},
...
}
这样做可以确保在每次重新渲染前清空上一次的图表实例和轮播计时器,从而避免数据混乱的问题。针对第一个问题,可以在组件销毁时清除定时器,避免出现多次轮播的问题。例如可以在组件的beforeDestroy钩子里清除定时器:
beforeDestroy() {
clearInterval(this.timer)
}
针对第二个问题,可以在每次切换数据时,先清空之前的数据,避免数据错乱。例如可以在组件的watch里监听数据变化,然后在数据变化时清空之前的数据:
watch: {
data() {
this.clearData()
// 根据新的数据重新渲染图表
this.renderChart()
}
},
methods: {
clearData() {
this.chartData = []
this.chartLabels = []
},
renderChart() {
// 渲染图表
}
}
js部分
drawCan () {
let dateArr = [] // x轴日期
let finishedPercentageArr = [] // 完成率
let finishCount = [] // 完成户数
let unFinishCount = [] // 未完成户数
let uncooperativeCount = [] // 不配合
data.forEach(item => {
dateArr.push(item.date)
finishedPercentageArr.push(item.finished_percentage.replace('%', ''))
finishCount.push(item.finished.count)
unFinishCount.push(item.unfinished.count)
uncooperativeCount.push(item.uncooperative.count)
})
// y轴刻度自适应
let yLeft = finishCount.concat(unFinishCount).concat(uncooperativeCount)
let yLinBarMaxLeft = Number(Math.max.apply(null, yLeft) * 1.5).toFixed(0)
let yLinBarMaxRight = Number(Math.max.apply(null, finishedPercentageArr) * 1.5).toFixed(0)
options = {
color: ['#0f0', '#ff0', '#f00', '#00f'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: '',
crossStyle: {
color: '#999'
}
},
formatter: (params) => {
let html = ''
params.map((item) => {
let seriesName = item.seriesName
let value = item.value
// let unit = item.seriesName.indexOf('率') === -1 ? '' : '%' // 单位
html += item.name + '</br>' + item.marker + seriesName + ':' + value + '%' + '<br/>'
})
return html
}
},
legend: {
data: ['完成户数', '未完成户数', '不配合', '完成率'],
right: 100
// formatter: params => {
// console.log('legend', params)
// }
},
xAxis: [
{
type: 'category',
data: dateArr,
axisPointer: {
type: 'shadow'
}
}
],
yAxis: [
{
type: 'value',
name: '街道完成户数',
min: 0,
max: yLinBarMaxLeft,
axisLabel: {
formatter: '{value}户'
}
},
{
show: false,
type: 'value',
name: '街道完成率',
min: 0,
max: yLinBarMaxRight,
axisLabel: {
formatter: '{value} %'
}
}
],
series: [
{
name: '完成户数',
type: 'bar',
data: finishCount,
emphasis: {
focus: 'series'
},
tooltip: {
trigger: 'item',
formatter: params => {
let tipHtml = ''
let obj = data[params.dataIndex]
tipHtml = '<div>完成户数:' + obj.finished.count + '</div><div>常住户:' + obj.finished.long_term + '<div>租户:' + obj.finished.tenant + '</div>'
return tipHtml
}
}
},
{
name: '未完成户数',
type: 'bar',
data: unFinishCount,
emphasis: {
focus: 'series'
},
tooltip: {
trigger: 'item',
formatter: params => {
let tipHtml = ''
let obj = data[params.dataIndex]
tipHtml = '<div>未完成户数:' + obj.unfinished.count + '</div><div>常住户:' + obj.unfinished.long_term + '<div>租户:' + obj.unfinished.tenant + '</div>'
return tipHtml
}
}
},
{
name: '不配合',
type: 'bar',
data: uncooperativeCount,
emphasis: {
focus: 'series'
},
tooltip: {
trigger: 'item',
formatter: params => {
let tipHtml = ''
let obj = data[params.dataIndex]
tipHtml = '<div>未完成户数:' + obj.uncooperative.count + '</div><div>常住户:' + obj.uncooperative.long_term + '<div>租户:' + obj.uncooperative.tenant + '</div>'
return tipHtml
}
}
},
{
name: '完成率',
type: 'line',
yAxisIndex: 1,
data: finishedPercentageArr
// tooltip: {
// trigger: 'item',
// formatter: params => {
// let tipHtml = ''
// let obj = data[params.dataIndex]
// tipHtml = '<div>完成率:' + obj.finished_percentage + '</div>'
// return tipHtml
// }
// }
}
]
}
let echartsDom = echarts.init(画布dom)
echartsDom.clear() // 清空画布
echartsDom.setOption(options)
}
针对问题一,可以通过在组件中使用watch
来监听轮播的状态,只有在轮播状态改变时才触发自动轮播。具体步骤如下:
在组件中添加一个变量autoplay
用来表示当前自动轮播的状态,默认为false
。
在watch
中监听autoplay
的变化,在状态发生改变时才触发自动轮播。
在组件中的mounted
方法中调用轮播方法前先检查autoplay
状态是否为false
,如果是则调用轮播方法,并将autoplay
变量设置为true
。
在轮播方法执行结束后将autoplay
变量设置为false
。
下面是示例代码:
<template>
<div class="chart-container">
<div ref="chart1" class="echarts"></div>
<div ref="chart2" class="echarts"></div>
<div ref="chart3" class="echarts"></div>
</div>
</template>
<script>
import echarts from 'echarts';
import debounce from '@/utils/debounce';
export default {
data() {
return {
autoplay: false
};
},
methods: {
play() {
// 轮播方法
// 在此处编写轮播逻辑
this.autoplay = true;
}
},
watch: {
autoplay(newVal) {
if (newVal === true) {
// 在此处触发自动轮播
// 可以调用play方法
this.play();
}
}
},
mounted() {
// 监听窗口大小变化,并在变化后重新渲染图表
window.addEventListener('resize', debounce(() => {
this.$refs.chart1.resize();
this.$refs.chart2.resize();
this.$refs.chart3.resize();
}, 400));
// 在mounted时判断autoplay状态是否为false,
// 如果是则调用轮播方法并将autoplay设置为true
if (!this.autoplay) {
this.play();
this.autoplay = true;
}
},
beforeDestroy() {
// 在组件销毁前取消resize事件监听
window.removeEventListener('resize', debounce);
}
};
</script>
针对问题二,可以通过在点击不同的接口按钮时清空上一次的数据和设置loading
状态来解决数据混乱问题和轮播跳动问题。具体步骤如下:
在组件中添加一个变量loading
表示当前是否正在加载数据,默认为false
。
在点击按钮时,先将loading
状态设置为true
。
在获取数据成功后,先清空之前的数据,然后将新数据赋值给对应的变量。
在数据获取成功后,将loading
状态设置为false
。
下面是示例代码:
<template>
<div>
<button @click="getChartData('url1')">接口1</button>
<button @click="getChartData('url2')">接口2</button>
<button @click="getChartData('url3')">接口3</button>
<div ref="chart" class="echarts"></div>
</div>
</template>
<script>
import echarts from 'echarts';
export default {
data() {
return {
loading: false,
chartData: []
};
},
methods: {
getChartData(url) {
// 在获取数据时先将loading状态设置为true
this.loading = true;
// 在此处调用接口获取数据
this.$http.get(url)
.then(response => {
// 成功获取到数据后清空之前的数据
this.chartData = [];
// 在此处将新数据赋值给对应的变量
this.chartData = response.data;
// 将loading状态设置为false
this.loading = false;
})
.catch(error => {
console.log(error);
// 在此处处理错误
this.loading = false;
});
},
renderChart() {
// 在此处使用echarts渲染图表
let option = {
// 在此处编写图表的相关配置
// 使用this.chartData来设置图表数据
};
let chart = echarts.init(this.$refs.chart);
chart.setOption(option);
}
},
watch: {
chartData() {
// 在数据发生改变时重新渲染图表
this.renderChart();
}
}
};
</script>