当前位置: 首页 > article >正文

在Vue 3中使 echarts 图表宽度自适应变化

需求:

有现在这样一段使用 echarts 的 vue3 代码:

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

<script setup>
import {getCurrentInstance, onMounted, onUnmounted, ref} from 'vue';

const chartRef = ref(null);
let chartInstance = null;

// 通过 getCurrentInstance 访问全局属性
const {proxy} = getCurrentInstance();

onMounted(() => {
  chartInstance = proxy.$echarts.init(chartRef.value);
  chartInstance.setOption({
    title: {text: '柱状图示例'},
    tooltip: {},
    xAxis: {data: ['A', 'B', 'C', 'D', 'E']},
    yAxis: {},
    series: [{type: 'bar', data: [10, 20, 30, 40, 50]}]
  });
});

onUnmounted(() => {
  chartInstance?.dispose(); // 销毁实例
});
</script>

作用是在界面显示一个柱状图:
在这里插入图片描述
问题是在页面缩放时,图表大小始终固定:
在这里插入图片描述
希望图表能够根据页面宽度自动调整,特别是在页面缩放时。

解决:

在代码中,chartRef的div被固定设置为600px宽和400px高,现在需要修改这部分,让图表始终占据页面的宽度,并能够响应窗口大小的变化。

为实现自适应宽度。通常可以通过CSS来设置容器的宽度为100%,这样它会填充父容器的宽度。

但仅仅设置CSS可能不够,因为ECharts实例在初始化后不会自动调整大小,除非显式调用图表实例的 resize 方法。

所以,解决方案的大致步骤应该是:

  1. 修改模板中的div样式,将宽度设置为100%,这样它会根据父容器自适应。

  2. 在Vue组件中添加一个监听窗口大小变化的事件,当窗口resize时,触发ECharts实例的resize方法。

  3. 确保在组件卸载时移除事件监听,避免内存泄漏。

代码:

<template>
  <!-- 外层容器用于控制图表宽度,高度可根据需求调整 -->
  <div class="chart-container">
    <div ref="chartRef" class="chart"></div>
  </div>
</template>

<script setup>
import { getCurrentInstance, onMounted, onUnmounted, ref } from 'vue';

const chartRef = ref(null);
let chartInstance = null;
const { proxy } = getCurrentInstance();

// 处理窗口缩放
const handleResize = () => {
  if (chartInstance) {
    // 添加防抖优化性能(可选)
    chartInstance.resize();
  }
};

onMounted(() => {
  // 初始化图表
  chartInstance = proxy.$echarts.init(chartRef.value);
  chartInstance.setOption({
    title: { text: '响应式柱状图' },
    tooltip: {},
    xAxis: { data: ['A', 'B', 'C', 'D', 'E'] },
    yAxis: {},
    series: [{ type: 'bar', data: [10, 20, 30, 40, 50] }]
  });

  // 监听窗口变化
  window.addEventListener('resize', handleResize);

  // 初始执行一次确保尺寸正确
  setTimeout(handleResize, 0);
});

onUnmounted(() => {
  window.removeEventListener('resize', handleResize);
  chartInstance?.dispose();
});
</script>

<style scoped>
.chart-container {
  width: 100%;
  padding: 20px; /* 可根据需求调整 */
}

.chart {
  width: 100%;
  height: 200px; /* 固定高度,可改为 min-height 或使用 calc 动态计算 */

  /* 可选:添加最大宽度限制 */
  max-width: 1200px;
  margin: 0 auto;
}

/* 移动端适配 */
@media (max-width: 768px) {
  .chart {
    height: 300px;
  }
}
</style>

效果如下:
在这里插入图片描述

主要修改点说明:
1,容器结构优化:

  • 添加外层容器 .chart-container 控制布局
  • 图表元素使用百分比宽度 width: 100%

2,响应式处理:

window.addEventListener('resize', handleResize);

监听窗口缩放事件,触发图表 resize 方法

3,自动调整逻辑:

const handleResize = () => {
  chartInstance?.resize();
};

调用 ECharts 实例的 resize() 方法自适应容器

4,CSS 增强:

  • 添加响应式高度(通过媒体查询)
  • 限制最大宽度避免过宽
  • 添加安全间距(padding/margin)

如果需要高度也自适应,可以:

// 在 handleResize 中动态计算高度
const containerWidth = chartRef.value.offsetWidth;
const aspectRatio = 9 / 16; // 16:9 比例
chartRef.value.style.height = `${containerWidth * aspectRatio}px`;
chartInstance.resize();

响应式断点:

/* 在样式中添加更多断点 */
@media (max-width: 480px) {
  .chart {
    height: 250px;
  }
}

父容器控制:确保外层父元素有正确的布局设置

/* 在父组件中 */
.parent-container {
  width: 100%;
  display: flex;
  justify-content: center;
}

扩展:

1,防抖处理

是否需要考虑防抖处理,避免频繁触发resize导致性能问题。但ECharts的resize方法本身有一定的优化,可能不需要额外处理,但根据具体情况可以添加。

// 防抖版 resize(在 handleResize 顶部添加)
let resizeTimer;
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
  chartInstance.resize();
}, 200);

2,多图表并列缩放问题

以两个图表并排并考虑缩放为例,这涉及到布局和响应式处理两个方面。

布局方面,我需要考虑使用CSS Flexbox或者Grid来实现并排。
响应式方面,需要确保每个图表都能在窗口大小变化时正确调整尺寸,并且可能需要在移动设备上切换为垂直排列。

接下来,我需要回忆ECharts的resize方法是否正确应用,是否需要为每个图表实例单独调用resize。需要确保每个图表容器都有正确的宽度设置,比如各占50%或者使用Flexbox的自动调整。

<template>
  <!-- 使用 Flex 布局容器 -->
  <div class="charts-container">
    <!-- 单个图表容器 -->
    <div class="chart-wrapper">
      <div ref="chartRef1" class="chart"></div>
    </div>
    
    <!-- 第二个图表容器 -->
    <div class="chart-wrapper">
      <div ref="chartRef2" class="chart"></div>
    </div>
  </div>
</template>

<script setup>
import { getCurrentInstance, onMounted, onUnmounted, ref } from 'vue';

const chartRef1 = ref(null);
const chartRef2 = ref(null);
let chartInstance1 = null;
let chartInstance2 = null;
const { proxy } = getCurrentInstance();

// 公共配置项
const baseOption = {
  tooltip: {},
  xAxis: { data: ['A', 'B', 'C', 'D', 'E'] },
  yAxis: {},
};

// 初始化图表
const initChart = (ref, option) => {
  const chart = proxy.$echarts.init(ref.value);
  chart.setOption(option);
  return chart;
};

// 带防抖的 resize 处理
let resizeTimer;
const handleResize = () => {
  clearTimeout(resizeTimer);
  resizeTimer = setTimeout(() => {
    chartInstance1?.resize();
    chartInstance2?.resize();
  }, 200);
};

onMounted(() => {
  // 初始化两个图表
  chartInstance1 = initChart(chartRef1, {
    ...baseOption,
    title: { text: '图表1' },
    series: [{ type: 'bar', data: [10, 20, 30, 40, 50] }]
  });

  chartInstance2 = initChart(chartRef2, {
    ...baseOption,
    title: { text: '图表2' },
    series: [{ type: 'bar', data: [50, 40, 30, 20, 10] }]
  });

  // 监听窗口变化
  window.addEventListener('resize', handleResize);
  // 初始调整
  handleResize();
});

onUnmounted(() => {
  window.removeEventListener('resize', handleResize);
  chartInstance1?.dispose();
  chartInstance2?.dispose();
});
</script>

<style scoped>
/* 主容器:Flex 布局 */
.charts-container {
  display: flex;
  gap: 20px; /* 图表间距 */
  width: 100%;
  padding: 20px;
  box-sizing: border-box;
}

/* 单个图表容器 */
.chart-wrapper {
  flex: 1; /* 平分剩余空间 */
  min-width: 0; /* 解决 flex 容器溢出问题 */
}

.chart {
  width: 100%;
  height: 400px; /* 统一高度 */
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0,0,0,0.1);
}

/* 移动端响应式 */
@media (max-width: 768px) {
  .charts-container {
    flex-direction: column; /* 垂直排列 */
  }
  
  .chart {
    height: 300px;
  }
}
</style>

效果如下:
在这里插入图片描述

1,布局方案:

  • 使用 display: flex 创建弹性容器
  • gap: 20px 设置图表间距
  • flex: 1 使两个图表容器平分可用空间
  • min-width: 0 修复 flex 容器溢出问题

2,响应式控制:

  • 媒体查询 @media (max-width: 768px) 实现移动端垂直布局
  • 统一高度设置保证视觉一致性
  • 容器宽度始终为 100% 适配父元素

3,图表控制:

  • 封装 initChart 方法复用初始化逻辑
  • 使用防抖函数优化频繁 resize 性能
  • 同时处理两个图表的 resize 事件

4,样式增强:

  • 添加阴影和圆角提升视觉效果
  • 设置 box-sizing: border-box 避免布局错位
  • 背景色设置保证图表可见性

http://www.kler.cn/a/532037.html

相关文章:

  • 如何创建折叠式Title
  • PHP XML操作指南
  • C++哈希表深度解析:从原理到实现,全面掌握高效键值对存储
  • nodejs:js-mdict 的下载、安装、测试、build
  • Unity Shader Graph 2D - 跳动的火焰
  • 【memgpt】letta 课程1/2:从头实现一个自我编辑、记忆和多步骤推理的代理
  • 什么叫DeepSeek-V3,以及与GPT-4o的区别
  • 实战:如何利用网站外部链接提升收录?
  • UE求职Demo开发日志#21 背包-仓库-装备栏移动物品
  • 【ComfyUI专栏】在ComfyUI中编辑节点框的样式与背景
  • 【大模型】AI 辅助编程操作实战使用详解
  • [250204] Mistral Small 3:小巧、快速、强大 | asdf 0.16.0 发布:Golang 重写带来性能飞跃
  • 机器学习,深度学习,神经网络,深度神经网络
  • DeepSeek:全栈开发者视角下的AI革命者
  • FinRobot:一个使用大型语言模型的金融应用开源AI代理平台
  • LabVIEW的智能电源远程监控系统开发
  • 为什么会有函数调用参数带标签的写法?Swift函数调用的参数传递需要加前缀是否是冗余?函数调用?函数参数?
  • 接口测试用例设计-笔记
  • 本地Ollama部署DeepSeek R1模型接入Word
  • kaggle视频行为分析1st and Future - Player Contact Detection
  • 《海丰县蔡氏简介》前言
  • Kafka的安装及相关操作命令
  • 动态分库分表
  • 鸿蒙Harmony–状态管理器–@State详解
  • Vue 3 30天精进之旅:Day 14 - 项目实践
  • 【图片识别分类】批量按图片水印文字识别后根据内容分类并移至不同文件夹,基于Python和腾讯API的解决方案