记一次Vue-echarts显示异常问题(将chart声明为响应式数据导致了一些显示问题)

188 阅读1分钟

问题代码

data() { 
    return { 
        chart: null 
    } 
}, 
mounted() { 
this.chart = echarts.init(this.$refs.chart, 'light', this.data.style) 
this.data.options.yAxis = { 
    // 兼容处理 ...this.data.options.yAxis, 
    nameRotate: 90, 
    nameGap: 30, 
    nameLocation: 'middle'
} 
this.data.options.grid.left = '15%' this.renderChart() },

这段代码会使chart的一些样式失效,比如指鼠标移入图表时出现十字准心和悬浮值,而同样的代码,在不写chart: null时样式正常。

问题原因分析

这个问题是典型的 Vue 响应式系统与 ECharts 实例化冲突。在 Vue 中,data() 返回的对象会被转换为响应式对象,这意味着 Vue 会递归地将所有属性转换为 getter/setter。这种机制可能会干扰 ECharts 的正常工作,尤其是在处理复杂对象时。

当在 data() 中声明 chart: null 时,Vue 会将 this.chart 转换为响应式属性。当 ECharts 实例被赋值给这个属性时,Vue 会尝试对 ECharts 对象进行响应式处理,这可能破坏 ECharts 的内部结构和事件处理机制。

为什么移除 chart: null 后样式恢复正常?

当不在 data() 中声明 chart: null 时,this.chart 只是一个普通的对象属性,不会被 Vue 转换为响应式属性。这样,ECharts 实例可以正常工作,所有交互功能(如十字准心和悬浮值)都会保持正常。

解决方案

直接删掉 chart:null 的声明即可,让其在mounted函数中声明。
或是避免将 ECharts 实例存储在 Vue 的响应式数据中,本质上和删除chart:null声明一样。可以将其存储在组件实例的其他位置,例如:

export default {
  mounted() {
    // 将 ECharts 实例存储在组件实例上,而不是响应式数据中
    this._chart = echarts.init(this.$refs.chart, 'light', this.data.style);
    
    // 配置图表
    this.data.options.yAxis = {
      ...this.data.options.yAxis,
      nameRotate: 90,
      nameGap: 30,
      nameLocation: 'middle'
    };
    this.data.options.grid.left = '15%';
    
    this.renderChart();
  },
  
  methods: {
    renderChart() {
      // 使用 this._chart 而不是 this.chart
      this._chart.setOption(this.data.options);
    }
  },
  
  beforeDestroy() {
    // 组件销毁前释放 ECharts 实例
    if (this._chart) {
      this._chart.dispose();
      this._chart = null;
    }
  }
}

其他可能的影响

除了交互样式失效外,将 ECharts 实例存储在响应式数据中还可能导致以下问题:

  1. 性能下降:Vue 会对响应式对象进行深度监听,ECharts 实例是一个复杂对象,这会增加不必要的性能开销。
  2. 内存泄漏:如果 ECharts 实例没有被正确销毁,会导致内存泄漏。
  3. 更新异常:当 ECharts 实例被修改时,可能触发不必要的 Vue 重新渲染。

总结

在 Vue 中使用第三方库(如 ECharts)时,应避免将其实例存储在响应式数据中。建议将它们存储在组件实例的其他属性上(如 this._chart),并在组件销毁前手动释放资源。这样可以确保第三方库的正常工作,同时避免 Vue 响应式系统带来的潜在问题。