el-tab里使用echart实现大小自适应变化

 问题背景

在vue项目中,在el-tab里使用echart,echart不能正常显示,切换tab页面,echart宽度会变成100px。

在网上找了很多资料,大多都是el-tab直接使用echart,而没有echart作为子组件导入到el-tab中的例子,所以决定写一篇博文,帮助遇到同样问题的朋友。

问题所在

之所以出现这个问题,是因为el-tab页面未显示的tab下的div此时的display为none,在点击tab切换时候,div还未渲染完成,图表在执行js初始化的时候找不到这个元素,所以自动将"100%"转成了"100",最后计算出来的图表就成了100px。

其实该问题的核心在于需要在容器生成完成后或echart初始化完成后调用resize()方法

解决方法

在网上找了很多种解决方法,其中v-if每次都需要重新渲染不符合项目需求;:lazy=true本项目无效,以下两个方法有效。

1.nextTick 推荐

关于nextTick的介绍及用法参考这篇博文:3分钟带你了解Vue3的nextTick()_vue3 nexttick()-CSDN博客

大致意思为:它可以在数据更新后,在dom中渲染后,自动执行函数。

本项目在Chart.vue里使用了echart,然后在Tab.vue中导入Chart.vue。

实现过程涉及到父组件调用子组件方法,可参考这篇博文:

【笔记】vue3.2 父组件如何调用子组件中的方法_vue3父组件调用子组件两个函数-CSDN博客

子组件Chart.vue
Chart.vue

<template>
  <el-col :span="14">
    <div :id="id" :class="className" :style="{ height, width }"></div>
  </el-col>
</template>
Chart.vue

<script lang="ts" setup>

const chart = ref<any>("");

function resizeChart() {
  chart.value.resize();
}

//暴露子组件方法供父组件调用 重要!!!
defineExpose({
  resizeChart,
});

onMounted(() => {
// 图表初始化
  chart.value = markRaw(
    echarts.init(document.getElementById(props.id) as HTMLDivElement)
  );
  chart.value.setOption(option);

  // 大小自适应
  window.addEventListener("resize", () => {
    chart.value.resize();
  });
}
</script>
父组件Tab.vue
Tab.vue

<template>
    <el-tabs
      type="border-card"
      class="demo-tabs"
      v-model="activeTab"
      @tab-click="handleClick"
    >
      <el-tab-pane label="图1" name="1" style="width: 100%">
        <Chart ref="chartRef" />
      </el-tab-pane>
      <el-tab-pane label="图2" name="2" style="width: 100%">
        <Chart2 ref="chart2Ref" />
      </el-tab-pane>
    </el-tabs>
</template>
Tab.vue

<script setup lang="ts">
import Chart from "./Chart.vue";

//TAB
const activeTab = ref("1");

const ChartRef = ref();

const Chart2Ref = ref();

const handleClick = (tab) => {
  debugger;
  if (tab.props.name === "2") {
    //关键!!!!
    nextTick(() => {
      ChartRef.value.resizeChart();
    });
  } else {
    // 调用 Chart2组件的方法
    nextTick(() => {
      Chart2Ref.value.resizeChart();
    });
  }
};
</script>

亲测有效无延迟!!!

2.setTimeout延迟加载(能实现,但有延迟,不太推荐)

使用到了vuex和watch方法,可参考这篇博文:

通过vuex传递参数并触发组件中的事件_vuex触发通知-CSDN博客

想法:在用户切换el-tab页面时,调用方法resize();

父组件Tab.vue
Tab.vue

<script setup lang="ts">
import { useStore } from "vuex";

const store = useStore();

const handleClick = (tab) => {
  debugger;
  // 在这里提交数据到 Vuex store
  store.commit("setActiveTab", tab.props.name);
  }
};
</script>
子组件Chart.vue
Chart.vue

<script setup lang="ts">
watch(
  () => store.state.isActiveTab,
  (newVal) => {
    debugger;
    console.log("监听成功");
    setTimeout(() => {
        chart.value.resize();
      }, 0); // 延迟0毫秒初始化图表
  }
);
</script>
vuex

考虑到父子组件通信,用vuex也很方便,因为决定采用vuex作为中介,但watch只有在值变化时才调用事件,所以增加布尔值用于改变状态,参考博文:通过vuex传递参数并触发组件中的事件_vuex触发通知-CSDN博客

store.ts

setActiveTab(state: RootState, tab: string): void {
      state.activeTab = tab;
      state.isActiveTab = !state.isActiveTab; // 每次调用时更新状态
    },

这个方法延时设为0,在切换tab的时候也会先是很小再变大,比较影响用户体验,所以不太推荐。

总结

问题的关键就是在容器生成完成后或图形初始化完之后,再对echart进行resize()。

  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值