第26章:ECharts 自定义主题 + 页面一键切换主题(深色 / 浅色两套)

第26章:ECharts 自定义主题 + 页面一键切换主题(深色 / 浅色两套)

业务场景:后台管理平台,支持全局 / 单张图表切换深色、浅色主题,若依自带暗黑模式联动,复用我们封装好的 useEcharts。

原理:ECharts 支持预注册主题,初始化图表时指定 theme 名称;我们做两套主题,增加按钮一键切换。

第一步:准备 echarts 主题

  1. 官网主题编辑器:https://echarts.apache.org/zh/theme-builder.html
  2. 我们直接内置两套极简主题,不需要额外下载 js,代码内定义。

完整页面 Vue 代码

复制代码
<template>
  <div class="chart-container">
    <el-alert title="ECharts自定义主题切换:浅色/深色主题一键切换" type="info" style="margin-bottom:10px"/>
    <el-button type="primary" @click="toggleTheme">切换图表主题</el-button>
    <div
      ref="chartRef"
      style="width:100%;height:400px;border:1px solid #eee;margin-top:10px"
    ></div>
  </div>
</template>

<script setup>
import * as echarts from 'echarts'
import { ref, onMounted } from 'vue'
import { useEcharts } from '@/composables/echartHelper'

const { chartRef, setChartOption } = useEcharts()
// 标记当前主题
const isDark = ref(false)

// 浅色主题配置
const lightOption = {
  title: {
    text: "产品月度销量统计",
    left: "center",
    textStyle: { color: "#303133" }
  },
  tooltip: { trigger: "axis" },
  legend: { data: ["A产品","B产品"], bottom: 10, textStyle: { color: "#303133" } },
  grid: { left: "3%", right: "4%", bottom: "15%", containLabel: true },
  xAxis: {
    type: "category",
    data: ["1月","2月","3月","4月","5月","6月"],
    axisLine: { lineStyle:{color:'#ccc'} },
    axisLabel: { color: "#606266" }
  },
  yAxis: {
    type: "value",
    axisLine: { lineStyle:{color:'#ccc'} },
    axisLabel: { color: "#606266" }
  },
  series: [
    {
      name: "A产品",
      type: "bar",
      data: [120, 200, 150, 280, 190, 240],
      itemStyle: { color: "#409EFF" }
    },
    {
      name: "B产品",
      type: "bar",
      data: [80, 140, 220, 160, 250, 180],
      itemStyle: { color: "#67C23A" }
    }
  ]
}

// 深色主题配置
const darkOption = {
  backgroundColor: "#1f2937",
  title: {
    text: "产品月度销量统计",
    left: "center",
    textStyle: { color: "#ffffff" }
  },
  tooltip: { trigger: "axis", backgroundColor:"#333", textStyle:{color:"#fff"} },
  legend: { data: ["A产品","B产品"], bottom: 10, textStyle: { color: "#e5e7eb" } },
  grid: { left: "3%", right: "4%", bottom: "15%", containLabel: true },
  xAxis: {
    type: "category",
    data: ["1月","2月","3月","4月","5月","6月"],
    axisLine: { lineStyle:{color:'#4b5563'} },
    axisLabel: { color: "#d1d5db" }
  },
  yAxis: {
    type: "value",
    axisLine: { lineStyle:{color:'#4b5563'} },
    axisLabel: { color: "#d1d5db" }
  },
  series: [
    {
      name: "A产品",
      type: "bar",
      data: [120, 200, 150, 280, 190, 240],
      itemStyle: { color: "#3b82f6" }
    },
    {
      name: "B产品",
      type: "bar",
      data: [80, 140, 220, 160, 250, 180],
      itemStyle: { color: "#22c55e" }
    }
  ]
}

// 切换主题函数
async function toggleTheme() {
  isDark.value = !isDark.value
  if(isDark.value){
    await setChartOption(darkOption)
  }else{
    await setChartOption(lightOption)
  }
}

onMounted(async () => {
  await setChartOption(lightOption)
})
</script>

进阶知识点(若依暗黑模式联动)

若依 Vue3 自带全局暗黑主题,我们可以监听若依的暗黑变量,自动切换图表颜色,不需要手动点按钮:

复制代码
// 引入若依全局暗黑状态
import { useAppStore } from '@/stores/app'
const appStore = useAppStore()

// 监听暗黑模式变化
watch(()=>appStore.dark, (newVal)=>{
  if(newVal){
    setChartOption(darkOption)
  }else{
    setChartOption(lightOption)
  }
},{immediate:true})

注意:需要在顶部引入 import { watch } from 'vue'

知识点总结

  1. 两套 option,区分背景、文字、坐标轴颜色;深色图表必须设置backgroundColor
  2. 复用我们封装好的setChartOption,notMerge:true,切换主题时完整覆盖旧配置,不会残留样式
  3. 可以单独页面切换,也可以监听若依全局暗黑状态自动同步图表主题
  4. resize、实例销毁逻辑全部继承自 useEcharts,不用重复写

🧪 测试清单

  1. 保存页面,刷新浏览器
  2. 页面默认浅色柱状图,文字、坐标轴颜色正常
  3. 点击【切换图表主题】按钮,图表立刻切换深色背景,文字变白
  4. 多次点击,深浅来回切换无样式残留
  5. 窗口缩放,图表自适应
  6. 切换菜单,图表实例销毁,无内存泄漏
相关推荐
usdoc文档预览1 天前
USDOC系列之PPT文件在线编辑-VUE前端实现在线浏览器在线编辑PPT文档
前端·vue.js·编辑器·office365·ppt在线编辑·office文件在线编辑·文件在线编辑
Java小卷1 天前
面向 schema 编程,轻松搞定 Element 虚拟化表格复杂应用场景
vue.js·低代码·element
仨孩子的爹1 天前
Lodop、hiprint 与 vue-print-designer:打印控件选型对比
vue.js
ruanno_top1 天前
四个 canvas 组件,在 2 倍屏上一直是糊的
vue.js
ruanno_top1 天前
一个脏数据能让整条折线消失:图表组件的四种数据契约
vue.js
FlyWIHTSKY2 天前
vue2和vue3有什么区别,用法上有哪些区别
前端·javascript·vue.js
ruanno_top2 天前
能点,但 Tab 不到:两个组件把「可操作」做了一半
vue.js
爱吃烧烤的技术渣2 天前
别再手写 CRUD 了:我把 Element Plus 的工作量压缩成一份列 schema
前端·vue.js
徐小夕2 天前
万字长文!DeepSeek Super-agent × 企业知识库架构深度拆解与落地实践
前端·vue.js·github
ruanno_top3 天前
倒计时该用 deadline 还是每秒减一?我把两种写法都跑了一遍
vue.js