实现echarts全屏的放大/缩小最优解

发布于:2025-06-13 ⋅ 阅读:(20) ⋅ 点赞:(0)

需求 :

丝滑实现echarts全屏的放大/缩小

最终效果如下 : 


未处理前 : 

放大-->缩小后出现echarts样式

旧方案 : 


监听全屏变化事件,全局触发 window.resize , 会出现顿挫感

最终方案 : 


监听全屏切换事件,并在容器尺寸真正变化后才 resize 图表


步骤一 : 在echarts组件中


每个图表组件暴露 resize() 方法

// 文件位置 @/home/components/pieChart.vue

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import * as echarts from 'echarts'

const chartRef = ref<HTMLDivElement | null>(null)
let chartInstance: echarts.ECharts | null = null

const initChart = () => {
  ...
}

const resizeChart = () => {
  chartInstance?.resize()
}

onMounted(initChart)
onBeforeUnmount(() => {
  chartInstance?.dispose()
  window.removeEventListener('resize', resizeChart)
})


// 为每个组件暴露resize方法
const resize = () => {
  chartInstance?.resize()
}

defineExpose({
  resize
})
</script>


步骤二 : 在hooks中


使用 ResizeObserver 来感知图表容器尺寸变化 (还可封装为hooks方法)

// 文件位置 @/hooks/useEChartsResize

import { onMounted, onBeforeUnmount, Ref } from 'vue'

export function useChartResize (
  containerRef: Ref<HTMLElement | null>,
  chartRefs: Ref[] = []
) {
  let observer: ResizeObserver | null = null

  onMounted(() => {
    if (containerRef.value) {
      observer = new ResizeObserver(() => {
        chartRefs.forEach(chartRef => {
          chartRef.value?.resize?.()
        })
      })
      observer.observe(containerRef.value)
    }
  })

  onBeforeUnmount(() => {
    if (observer && containerRef.value) {
      observer.unobserve(containerRef.value)
      observer.disconnect()
    }
  })
}


步骤三 : 在父组件中


父组件(即index.vue)中引入ResizeObserver方法 , 模板中绑定ref

// 文件位置 @/home/index.vue

<template>
  <div class="big-screen" ref="screenRef">
    <!-- 左侧 -->
    <div class="left">
      <div class="chart-box">
        <BarChart ref="barChartRef1" />
      </div>
      <div class="chart-box">
        <LineChart ref="lineChartRef1" />
      </div>
      <div class="chart-box">
        <PieChart ref="pieChartRef1" />
      </div>
    </div>

    <!-- 中间 -->
    <div class="center">
      ...
    </div>

    <!-- 右侧 -->
    <div class="right">
      ...
    </div>

    <!-- 全屏 -->
    <i
      :class="['iconfont', isFullscreen ? 'icon-suoxiao' : 'icon-fangda']"
      class="echarts-icon"
      @click="toggleFullScreen"
    ></i>
  </div>
</template>



<script setup lang="ts">

import { useChartResize } from '@/hooks/useEChartsResize' // 引入hooks

const screenRef = ref<HTMLElement | null>(null)

const barChartRef1 = ref()
const lineChartRef1 = ref()
const pieChartRef1 = ref()
const lineChartRef2 = ref()
const barChartRef3 = ref()
const lineChartRef3 = ref()
const pieChartRef3 = ref()

useChartResize(screenRef, [
  barChartRef1,
  lineChartRef1,
  pieChartRef1,
  lineChartRef2,
  barChartRef3,
  lineChartRef3,
  pieChartRef3
])

// 点击全屏切换
const toggleFullScreen = () => {
  if (screenfull.isEnabled && screenRef.value) {
    screenfull.toggle(screenRef.value).then(() => {
      // 等待动画结束,再 resize 所有图表
      setTimeout(() => {
        ;[
          barChartRef1,
          lineChartRef1,
          pieChartRef1,
          lineChartRef2,
          barChartRef3,
          lineChartRef3,
          pieChartRef3
        ].forEach(refItem => {
          refItem.value?.resize?.()
        })
      }, 300)
    })
  }
}

</script>

项目结构如下