vue echarts

vue封装echarts柱状图组件,调用了三次,结果自动轮播也会调用三次,然后就会出现数据错乱,轮播时乱跳动,然后就是封装了一个折线图,根据后端不同的接口调用不同的数据,但是点击多个按键之后数据就错乱了,上一次的数据没有被清除掉,导致轮播一直在几张图里面跳动

echarts跟轮播有什么关系呢?建议贴出完整代码

针对你的两个问题,分别给出如下解决思路:

问题一:调用三次导致轮播数据错乱

这个问题的原因是因为在Vue中,每次使用组件都会重新渲染,而自动轮播也是在组件内部实现的,所以组件被重新渲染时,轮播计时器会重新启动。解决办法可以是在组件销毁时清除计时器。具体步骤如下:

  • 在组件的 data 中定义一个计时器变量 timer。
    export default {
    data() {
      return {
        chartData: [], // 图表数据
        timer: null, // 自动轮播计时器
      }
    },
    ...
    }
    
  • 在组件的 mounted 钩子函数中启动自动轮播计时器。
    export default {
    mounted() {
      this.timer = setInterval(() => {
        this.currentIndex = (this.currentIndex + 1) % this.chartData.length;
        this.renderChart();
      }, 3000);
    },
    ...
    }
    
  • 在组件的 beforeDestroy 钩子函数中清除计时器。
    export default {
    beforeDestroy() {
      clearInterval(this.timer);
    },
    ...
    }
    
    这样做可以确保在组件被销毁时清除计时器,从而避免轮播数据错乱的问题。

问题二:多个按键点击后数据错乱

这个问题的原因是在组件中没有正确地清除上一次渲染的数据,导致下一次渲染时出现混乱。解决办法可以是在每次重新渲染前,手动清空图表实例和轮播计时器,并在销毁组件时释放资源。具体步骤如下:

  • 在组件的 data 中定义一个图表实例变量 myChart。
    export default {
    data() {
      return {
        chartData: [], // 图表数据
        currentIndex: 0, // 当前显示的索引
        myChart: null, // 图表实例
        timer: null, // 自动轮播计时器
      }
    },
    ...
    }
    
  • 在组件的 methods 中添加一个方法 clearChart,用于清空图表实例和轮播计时器。
    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();
        }
      },
      ...
    },
    ...
    }
    
  • 在组件的 beforeDestroy 钩子函数中销毁图表实例,释放资源。
    export default {
    beforeDestroy() {
      this.clearChart();
    },
    ...
    }
    
    这样做可以确保在每次重新渲染前清空上一次的图表实例和轮播计时器,从而避免数据混乱的问题。

针对第一个问题,可以在组件销毁时清除定时器,避免出现多次轮播的问题。例如可以在组件的beforeDestroy钩子里清除定时器:

beforeDestroy() {
  clearInterval(this.timer)
}

针对第二个问题,可以在每次切换数据时,先清空之前的数据,避免数据错乱。例如可以在组件的watch里监听数据变化,然后在数据变化时清空之前的数据:

watch: {
  data() {
    this.clearData()
    // 根据新的数据重新渲染图表
    this.renderChart()
  }
},
methods: {
  clearData() {
    this.chartData = []
    this.chartLabels = []
  },
  renderChart() {
    // 渲染图表
  }
}
  • 你可以看下这个问题的回答https://ask.csdn.net/questions/7661530
  • 你也可以参考下这篇文章:Echarts图表宽度变成100px,让图表宽度随着父元素自动适应,Vue实时监听宽度的变化,这可能是史上最好的解决方案!...
  • 除此之外, 这篇博客: vue项目Echarts柱状图动态渲染效果中的 案例二:多组数据,实现点击组内某一根柱子 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 在这里插入图片描述
    在这里插入图片描述

    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)
    }
    
  • 以下回答由chatgpt基于相关博客总结生成:

    针对问题一,可以通过在组件中使用watch来监听轮播的状态,只有在轮播状态改变时才触发自动轮播。具体步骤如下:

    1. 在组件中添加一个变量autoplay用来表示当前自动轮播的状态,默认为false

    2. watch中监听autoplay的变化,在状态发生改变时才触发自动轮播。

    3. 在组件中的mounted方法中调用轮播方法前先检查autoplay状态是否为false,如果是则调用轮播方法,并将autoplay变量设置为true

    4. 在轮播方法执行结束后将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状态来解决数据混乱问题和轮播跳动问题。具体步骤如下:

    1. 在组件中添加一个变量loading表示当前是否正在加载数据,默认为false

    2. 在点击按钮时,先将loading状态设置为true

    3. 在获取数据成功后,先清空之前的数据,然后将新数据赋值给对应的变量。

    4. 在数据获取成功后,将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>