【vue3、echarts踩坑】tooltip不显示、dataZoom无法滚动,第三方库的方法不生效、出现bug等解决方案

前言

在使用 Vue 3ECharts 开发时,遇到了非常棘手的问题:

  1. 明明配置了 tooltip 却无法正常显示。
    在这里插入图片描述
    在这里插入图片描述
  2. 配置了 dataZoom ,进行滚动或缩放时无效且会报错:
    在这里插入图片描述

解决方案:

创建 echarts实例 时使用 shallowRef 而非 ref

// 必要的导入
import { ref, shallowRef } from 'vue';

// 创建echarts实例
const chartInstance = ref();// 错误

const chartInstance = shallowRef();// 正常

好了,来这里解决问题的赶紧回去忙吧

接下来让我们深究一下为什么

这是一段常见的Vue 3组件代码:

<template>
  <div ref="chartDom" style="width: 600px; height: 400px;"></div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import * as echarts from 'echarts';

// 使用 ref 创建图表实例
const chartInstance = ref(null);
const chartDom = ref(null);

// 准备一个简单的图表配置项
const option = ref({
  tooltip: { // tooltip配置
    trigger: 'axis',
  },
  dataZoom: [{ // dataZoom配置
    type: 'inside',
    start: 0,
    end: 100
  }],
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [{
    data: [150, 230, 224, 218, 135, 147, 260],
    type: 'bar'
  }]
});

// 初始化图表
onMounted(() => {
  chartInstance.value = echarts.init(chartDom.value);
  chartInstance.value.setOption(option.value);
});

// 销毁图表
onUnmounted(() => {
  chartInstance.value?.dispose();
});
</script>

尽管这段代码逻辑清晰又足够简单,但运行后你会发现:

  • 鼠标移动到柱状图上,tooltip 不会出现
  • 尝试使用鼠标滚轮或拖动进行缩放滚动(dataZoom),图表毫无反应

问题根因分析

问题的核心在于 ref()shallowRef() 的区别

  1. ref() 的工作原理Vue 3ref 会对其接收的值进行深度响应式转换。这意味着它会递归地将一个对象的所有属性都转换为响应式对象,通过 Proxy 实现。

  2. Echarts实例的特性:Echarts实例本身是一个复杂的、包含大量方法和属性的对象。这些方法(如 setOption, dispatchAction)是维持图表交互(如 tooltip, dataZoom)的关键。

  3. 冲突发生:当我们使用 const chartInstance = ref(null) 并随后将Echarts实例赋值给它时(chartInstance.value = echarts.init(...)),Vue会尝试对这个Echarts实例进行深度响应式代理

    这个过程破坏和包裹了Echarts实例原有的方法和内部属性,导致其内部的事件监听机制函数执行上下文出现问题。因此,图表虽然能正常渲染,但所有依赖于原生实例方法的交互功能(如 tooltip 的显示隐藏、dataZoom 的滚动事件处理)都会全部失效

shallowRef的工作原理

  • shallowRef 只会对 .value 属性本身进行响应式跟踪,而不会对其值(即我们赋给它的Echarts实例)进行深度响应式转换。它只关心整个实例对象的引用是否被替换(例如 chartInstance.value = newInstance),而不关心对象内部的变化。

巧了不是,我们只需要知道图表实例的引用是否存在(以便在组件卸载时调用 dispose 方法),或者是否需要替换整个实例(如在图表类型切换时),而完全不需要Vue去深度监听实例内部的变化。

以后在遇到类似的bug,比如第三方库出现了未知的bug或者没有达到预期的效果那就都可以使用这种方案试一下。

总结

声明方式响应式深度对Echarts实例的影响结果
ref()深度响应式包裹并代理实例方法,破坏其内部机制tooltip, dataZoom 等交互失效
shallowRef()浅层响应式仅跟踪实例引用变化,不触碰实例内部功能正常,交互流畅

在Vue 3中管理Echarts、D3.js、Three.js等第三方库的实例时,一个非常重要的原则是:

除非明确需要,否则避免对复杂的第三方类实例进行深度响应式代理。

对于这类主要用于存储引用、调用方法,而其内部状态由自身管理的对象,shallowRef 是首选。它既保持了响应式的便利性(如判断实例是否存在),又完美避免了深度响应式带来的副作用。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值