echarts图图表屏幕变化自适应

<template>
  <div ref="elRef" class="chart-container"></div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, onActivated, onDeactivated, nextTick } from 'vue'
import { debounce } from 'lodash-es'
import { useDesign } from '@/hooks/web/useDesign'
import * as echarts from 'echarts' // 明确导入 echarts

const { variables } = useDesign()

// 1. 类型定义(如果使用 TypeScript)
// type ElRef = HTMLElement | null

const elRef = ref(null)
const contentEl = ref(null)
let chartInstance = null 

// 2. 创建防抖函数
const debouncedResize = debounce(() => {
  if (chartInstance) {
    chartInstance.resize()
  }
}, 100)

// 3. 内容区域变化处理器
const handleContentResize = (e) => {
  if (e.propertyName === 'width' || e.propertyName === 'height') {
    debouncedResize()
  }
}

// 4. 初始化图表
const initChart = async () => {
  await nextTick() // 确保 DOM 已渲染
  if (!elRef.value) return
  
  // 销毁现有实例(如果存在)
  if (chartInstance) {
    chartInstance.dispose()
  }
  
  try {
    chartInstance = echarts.init(elRef.value)
    
    // 5. 定义图表配置
    const option = {
      // ... 你的图表配置
      // 示例配置
      title: { text: '示例图表' },
      tooltip: {},
      xAxis: { data: ['A', 'B', 'C'] },
      yAxis: {},
      series: [{ type: 'bar', data: [5, 20, 36] }]
    }
    
    chartInstance.setOption(option)
    
    // 6. 初始 resize(处理 SSR 或延迟加载)
    debouncedResize()
  } catch (error) {
    console.error('图表初始化失败:', error)
  }
}

// 7. 清理函数
const disposeChart = () => {
  if (chartInstance) {
    chartInstance.dispose()
    chartInstance = null
  }
}

// 8. 事件监听器管理
const addEventListeners = () => {
  window.addEventListener('resize', debouncedResize)
  
  const contentElement = document.querySelector(`.${variables.namespace}-layout-content`)
  if (contentElement) {
    contentEl.value = contentElement
    contentElement.addEventListener('transitionend', handleContentResize)
    // 也监听 animationend,因为某些动画可能使用 animation
    contentElement.addEventListener('animationend', handleContentResize)
  }
}

const removeEventListeners = () => {
  window.removeEventListener('resize', debouncedResize)
  
  if (contentEl.value) {
    contentEl.value.removeEventListener('transitionend', handleContentResize)
    contentEl.value.removeEventListener('animationend', handleContentResize)
  }
}

// 9. 生命周期钩子
onMounted(() => {
  initChart()
  addEventListeners()
})

onBeforeUnmount(() => {
  removeEventListeners()
  disposeChart()
})

// 10. keep-alive 支持
onActivated(() => {
  if (chartInstance) {
    // 延迟执行,确保组件完全激活
    nextTick(() => {
      chartInstance.resize()
    })
  }
})

onDeactivated(() => {
  // 可选:在组件失活时暂停图表(节省资源)
  // if (chartInstance) {
  //   chartInstance.clear()
  // }
})

// 11. 提供外部 API(可选)
defineExpose({
  refresh: () => {
    disposeChart()
    initChart()
  },
  getChart: () => chartInstance,
  resize: () => {
    if (chartInstance) {
      chartInstance.resize()
    }
  }
})
</script>

<style scoped>
.chart-container {
  width: 100%;
  height: 100%; /* 或使用 CSS 变量 */
  min-height: 400px; /* 设置最小高度 */
}
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值