实现echarts主题随项目主题切换

news2025/1/15 17:15:23

前言

项目中很多时候都带有dark/light两中主题类型,通过switch标签控制,但是echarts图形是通过canvas标签绘制,其背景颜色和字体样式并不会随着项目主题类型的切换而切换。所以需要额外设置监听主题事件,主要实现思路如下:

  1. 配置echarts主题,并引入注册
  2. 配置选项并绘制图形
  3. 监听系统主题变化,根据其改变echarts主题
  4. 监听屏幕变化,实现大小屏切换resize效果

实现效果

dark主题:

在这里插入图片描述

light主题:

在这里插入图片描述

项目环境

配置echarts主题

其实最新的echarts(5.x.x)已支持dark/light模式两种主题,但是很多时候还是满足不了项目需求,比如主题下的primarywarnningerror等样式,就可以使用**registerThemeAPI**注册主题样式,先配置主题样式(地址:主题编辑器),然后进行注册,这个官网已经给出了教程

vuetifydark样式其实和echartsdark样式相似,故不用使用**registerTheme**注册,主要区别在于backgroundColorcolor的不同,所以使用在init()之前使用条件判断,如下:

let baseOptions = {};
// vm.$vuetify.theme.dark:是否是dark模式
if (vm.$vuetify.theme.dark) {
  baseOptions = {
    backgroundColor: themeConfig.themes.dark.backgroundColor,
    textStyle: {
      color: themeConfig.themes.dark.color,
    },
  };
}

绘制echarts图形

主要是通过onDrawLine()实现,实现思路如下:

  1. 判断vm.$vuetify.theme.dark (项目dark主题)是否为true
  2. 如果为true,配置backgroundColortextStyle.color ,使用echartsdark主题
  3. 如果为false,不配置backgroundColortextStyle.color ,使用echarts中的light(即默认主题)
let lineChart = {};
const splitLine = {
  show: true,
  lineStyle: {
    // 实线
    // type: 'solid',
    // width: 0.5,
    // opacity: 0.8,

    // 虚线
    type: [5, 5],
    dashOffset: 0,
    shadowBlur: 0,
  },
};
const axisLine = { show: false };
const axisTick = { show: false };
const onDrawLine = () => {
  lineChart = vm.$echarts.init(
    document.getElementById("line-chart"),
    vm.$vuetify.theme.dark ? "dark" : "light"
  );
  let baseOptions = {};
  if (vm.$vuetify.theme.dark) {
    baseOptions = {
      backgroundColor: themeConfig.themes.dark.backgroundColor,
      textStyle: {
        color: themeConfig.themes.dark.color,
      },
    };
  }
  const option = {
    ...baseOptions,
    color: [
      $themeColors.error,
      $themeColors.danger,
      $themeColors.warning,
      $themeColors.low,
    ],
    title: {
      // text: 'Stacked Line'
    },
    tooltip: {
      trigger: "axis",
    },
    legend: {
      data: ["严重", "高", "中", "低"],

      // 放在底部
      bottom: 0,
    },
    grid: {
      top: "5%",
      left: "2%",
      right: "3%",
      bottom: "10%",
      containLabel: true,
    },
    xAxis: {
      type: "category",
      boundaryGap: false,
      data: [
        "10/09",
        "10/10",
        "10/11",
        "10/12",
        "10/13",
        "10/14",
        "10/15",
        "10/16",
        "10/17",
        "10/18",
        "10/19",
        "10/20",
        "10/21",
        "10/22",
        "10/23",
      ],
      splitLine,

      axisLine,
      axisTick,
    },
    yAxis: {
      type: "value",
      splitLine,
      interval: 90,
      max: 450,
      axisLine,
    },

    // 数据值
    series: [
      {
        name: "严重",
        type: "line",
        lineStyle: {
          width: 5,
        },

        // 显示点为实圆心
        stack: "Total",
        showSymbol: false,
        symbol: "none",
        data: [
          80, 150, 180, 270, 210, 160, 160, 202, 265, 210, 270, 255, 290, 360,
          375,
        ],
      },
      {
        name: "高",
        type: "line",
        showSymbol: false,
        symbol: "none",
        lineStyle: {
          width: 5,
        },
        data: [
          80, 125, 105, 130, 215, 195, 140, 160, 230, 300, 220, 170, 210, 200,
          280,
        ],
      },
      {
        name: "中",
        type: "line",
        showSymbol: false,
        symbol: "none",
        lineStyle: {
          width: 5,
        },
        data: [
          80, 99, 82, 90, 115, 115, 74, 75, 130, 155, 125, 90, 140, 130, 180,
        ],
      },
      {
        name: "低",
        type: "line",
        showSymbol: false,
        symbol: "none",
        lineStyle: {
          width: 5,
        },
        data: [
          10, 19, 32, 50, 15, 105, 14, 55, 30, 145, 115, 80, 200, 100, 150,
        ],
      },
    ],
  };

  lineChart.setOption(option)
};

注意:这里的lineChart不用使用ref 声明,因为不需要做响应式

术语速查手册

echarts的配置项真的很多,有时候不知道哪个是哪个意思,找起来比较费时间,官网给出了术语速查手册,有助于理解记忆

在这里插入图片描述

实现动态切换

实现echart图形切换主要思路如下:

  1. 监听项目主题(vm.$vuetify.theme.dark
  2. 注销图形(dispose()
  3. 重绘图形

主要代码如下:

watch(
  () => vm.$vuetify.theme.dark,
  (value) => {
    lineChart.dispose();
    onDrawLine();
  },
  {
    // immediate: true,
    deep: true,
  }
);

**注意:**不能immediate不能为true ,组件初始化时,lineChart还没有init(),所以会报错,故第一次绘制需要在onMounted,主要实现如下:

onMounted(() => {
  onDrawLine();
});

实现大小屏切换

主要通过[window.onresize](https://juejin.cn/post/7168860905625796616)实现,因为项目需求,有时候会进行大小屏切换,主要实现代码如下:

onMounted(() => {
  onDrawLine();
  window.onresize = function () {
    lineChart.resize();
  };
});

onBeforeUnmount(() => {
  window.onresize = null;
});

注意: 在组件实例销毁时,必须注销window.onresize,原因如下:

  1. window.onresize是全局组件,不注销会影响其他组件的功能
  2. 系统性能变差,因为window.onresize只要屏幕有改变就会触发,如果不注销又多个组件使用,屏幕变化一次,window.onresize会被执行多次

vue3版本代码实现

<!--
* @Description:告警时间趋势 折线图
* @version:1.0.0
* @Author: yuanyu
* @Date: 2022-11-03 10:22:55
* @LastEditors: yuanyu
* @LastEditTime: 2022-12-09 16:17:23
-->
<template>
  <!-- <vue-apex-charts
    type="line"
    height="280"
    :options="apexChatData.lineChartSimple.chartOptions"
    :series="apexChatData.lineChartSimple.series"
  /> -->
  <div id="line-chart" style="min-height:295px;width:100%"></div>
</template>

<script>
import VueApexCharts from 'vue-apexcharts'
import {
  onMounted, getCurrentInstance, onBeforeUnmount, watch,
} from 'vue-demi'
import themeConfig from '@themeConfig'
import apexChatData from './apexChartData'

const $themeColors = themeConfig.themes.light
export default {
  components: { VueApexCharts },
  setup() {
    const vm = getCurrentInstance().proxy
    console.log('document', document.getElementById('line-chart'))
    let lineChart = {}
    const splitLine = {
      show: true,
      lineStyle: {
        // 实线
        // type: 'solid',
        // width: 0.5,
        // opacity: 0.8,

        // 虚线
        type: [5, 5],
        dashOffset: 0,
        shadowBlur: 0,
      },
    }
    const axisLine = { show: false }
    const axisTick = { show: false }
    const onDrawLine = () => {
      lineChart = vm.$echarts.init(document.getElementById('line-chart'), vm.$vuetify.theme.dark ? 'dark' : 'light')
      let baseOptions = {}
      if (vm.$vuetify.theme.dark) {
        baseOptions = {
          backgroundColor: themeConfig.themes.dark.backgroundColor,
          textStyle: {
            color: themeConfig.themes.dark.color,
          },
        }
      }
      const option = {
        ...baseOptions,
        color: [$themeColors.error, $themeColors.danger, $themeColors.warning, $themeColors.low],
        title: {
          // text: 'Stacked Line'
        },
        tooltip: {
          trigger: 'axis',
        },
        legend: {
          data: ['严重', '高', '中', '低'],

          // 放在底部
          bottom: 0,
        },
        grid: {
          top: '5%',
          left: '2%',
          right: '3%',
          bottom: '10%',
          containLabel: true,
        },
        xAxis: {
          type: 'category',
          boundaryGap: false,
          data: [
            '10/09',
            '10/10',
            '10/11',
            '10/12',
            '10/13',
            '10/14',
            '10/15',
            '10/16',
            '10/17',
            '10/18',
            '10/19',
            '10/20',
            '10/21',
            '10/22',
            '10/23',
          ],
          splitLine,

          axisLine,
          axisTick,
        },
        yAxis: {
          type: 'value',
          splitLine,
          interval: 90,
          max: 450,
          axisLine,
        },

        // 数据值
        series: [
          {
            name: '严重',
            type: 'line',
            lineStyle: {
              width: 5,
            },

            // 显示点为实圆心
            stack: 'Total',
            showSymbol: false,
            symbol: 'none',
            data: [80, 150, 180, 270, 210, 160, 160, 202, 265, 210, 270, 255, 290, 360, 375],
          },
          {
            name: '高',
            type: 'line',
            showSymbol: false,
            symbol: 'none',
            lineStyle: {
              width: 5,
            },
            data: [80, 125, 105, 130, 215, 195, 140, 160, 230, 300, 220, 170, 210, 200, 280],
          },
          {
            name: '中',
            type: 'line',
            showSymbol: false,
            symbol: 'none',
            lineStyle: {
              width: 5,
            },
            data: [80, 99, 82, 90, 115, 115, 74, 75, 130, 155, 125, 90, 140, 130, 180],
          },
          {
            name: '低',
            type: 'line',
            showSymbol: false,
            symbol: 'none',
            lineStyle: {
              width: 5,
            },
            data: [10, 19, 32, 50, 15, 105, 14, 55, 30, 145, 115, 80, 200, 100, 150],
          },
        ],
      }

      // option = {
      //   ...apexChatData.lineChartSimple.chartOptions,
      //   series: apexChatData.lineChartSimple.series.map(item => Object.assign(item, { type: 'line' })),
      // }
      console.log('apexChatData', apexChatData)
      lineChart.setOption(option)

      window.onresize = function () {
        console.log('改变了', vm.$vuetify.theme.dark)
        lineChart.resize()
      }
    }

    onMounted(() => {
      onDrawLine()
    })
    onBeforeUnmount(() => {
      window.onresize = null
    })
    watch(
      () => vm.$vuetify.theme.dark,
      value => {
        lineChart.dispose()
        onDrawLine()
      },
      {
        // immediate: true,
        deep: true,
      },
    )

    return {
      apexChatData,
    }
  },
}
</script>

vue2版本代码实现

<!--
* @Description:告警时间趋势 折线图
* @version:1.0.0
* @Author: xxxxxx
* @Date: 2022-12-09 14:50:38
* @LastEditors: xxxxxx
* @LastEditTime: 2022-12-09 16:41:23
-->
<template>
  <div id="line-chart" :style="`height:${height};width:${width}`"></div>
</template>

<script>
import themeConfig from '@themeConfig'

const $themeColors = themeConfig.themes.light
let lineChart = {}
const splitLine = {
  show: true,
  lineStyle: {
    // 实线
    // type: 'solid',
    // width: 0.5,
    // opacity: 0.8,

    // 虚线
    type: [5, 5],
    dashOffset: 0,
    shadowBlur: 0,
  },
}
const axisLine = { show: false }
const axisTick = { show: false }
export default {
  props: {
    // 高度
    height: {
      type: [String],
      require: true,
    },

    // 宽度
    width: {
      type: String,
      default: '100%',
    },
    option: {
			type: Object,
			default: {}
		},
  },
  data() {
    return {}
  },
  watch: {
    '$vuetify.theme.dark': {
      handler(value) {
        lineChart.dispose()
        this.onDrawLine()
      },
      deep: true,
    },
  },
  mounted() {
    this.onDrawLine()
  },
  beforeDestroy() {
    window.onresize = null
  },
  methods: {
    onDrawLine() {
      lineChart = this.$echarts.init(document.getElementById('line-chart'), this.$vuetify.theme.dark ? 'dark' : 'light')
      let baseOptions = {}
      if (this.$vuetify.theme.dark) {
        baseOptions = {
          backgroundColor: themeConfig.themes.dark.backgroundColor,
          textStyle: {
            color: themeConfig.themes.dark.color,
          },
        }
      }
      const option = {
        ...baseOptions,
        color: [$themeColors.error, $themeColors.danger, $themeColors.warning, $themeColors.low],
        title: {
          // text: 'Stacked Line'
        },
        tooltip: {
          trigger: 'axis',
        },
        legend: {
          data: ['严重', '高', '中', '低'],

          // 放在底部
          bottom: 0,
        },
        grid: {
          top: '5%',
          left: '2%',
          right: '3%',
          bottom: '10%',
          containLabel: true,
        },
        xAxis: {
          type: 'category',
          boundaryGap: false,
          data: [
            '10/09',
            '10/10',
            '10/11',
            '10/12',
            '10/13',
            '10/14',
            '10/15',
            '10/16',
            '10/17',
            '10/18',
            '10/19',
            '10/20',
            '10/21',
            '10/22',
            '10/23',
          ],
          splitLine,

          axisLine,
          axisTick,
        },
        yAxis: {
          type: 'value',
          splitLine,
          interval: 90,
          max: 450,
          axisLine,
        },

        // 数据值
        series: [
          {
            name: '严重',
            type: 'line',
            lineStyle: {
              width: 5,
            },

            // 显示点为实圆心
            stack: 'Total',
            showSymbol: false,
            symbol: 'none',
            data: [80, 150, 180, 270, 210, 160, 160, 202, 265, 210, 270, 255, 290, 360, 375],
          },
          {
            name: '高',
            type: 'line',
            showSymbol: false,
            symbol: 'none',
            lineStyle: {
              width: 5,
            },
            data: [80, 125, 105, 130, 215, 195, 140, 160, 230, 300, 220, 170, 210, 200, 280],
          },
          {
            name: '中',
            type: 'line',
            showSymbol: false,
            symbol: 'none',
            lineStyle: {
              width: 5,
            },
            data: [80, 99, 82, 90, 115, 115, 74, 75, 130, 155, 125, 90, 140, 130, 180],
          },
          {
            name: '低',
            type: 'line',
            showSymbol: false,
            symbol: 'none',
            lineStyle: {
              width: 5,
            },
            data: [10, 19, 32, 50, 15, 105, 14, 55, 30, 145, 115, 80, 200, 100, 150],
          },
        ],
      }
      lineChart.setOption(option)

      window.onresize = function () {
        console.log('改变了', this.$vuetify.theme.dark)
        lineChart.resize()
      }
    },
  },
}
</script>
<style scoped lang='scss'>
</style>

求解

在项目中,echarts图形会不止一个,如果每次使用watch监听主题变化,代码会变得非常冗余,目前的思路是封装一个echarts公共组件,不知道有没有大佬有更好的思路,求指点

参考链接

https://echarts.apache.org/examples/zh/editor.html?c=line-stack

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/387699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode】982. 按位与为零的三元组

982. 按位与为零的三元组 题目描述 给你一个整数数组 nums &#xff0c;返回其中 按位与三元组 的数目。 按位与三元组 是由下标 (i, j, k) 组成的三元组&#xff0c;并满足下述全部条件&#xff1a; 0 < i < nums.length0 < j < nums.length0 < k < num…

深度学习笔记:数据正规化和抑制过拟合

1 Batch-normalization batch-normalization将输入数据转化为平均值0&#xff0c;标准差为1的分布&#xff0c;该方法可以加速学习并抑制过拟合。batch-normalization作为神经网络特定的一个层出现 batch-normalization计算表达式&#xff1a; 接下来&#xff0c;会对数据进…

tmux 使用看这一篇文章就够了

tmux简介及用途 tmux是一个终端复用工具&#xff0c;允许用户在一个终端会话中同时管理多个终端窗口&#xff0c;提高了终端使用效率&#xff0c;尤其在服务器上进行远程管理时更加实用。在tmux中&#xff0c;可以创建多个终端窗口和窗格&#xff0c;并在这些窗口和窗格之间自…

八、Bean的生命周期

Bean生命周期的管理&#xff0c;可以参考Spring的源码&#xff1a;AbstractAutowireCapableBeanFactory类的doCreateBean()方法。 1 什么是Bean的生命周期 Spring其实就是一个管理Bean对象的工厂。它负责对象的创建&#xff0c;对象的销毁等。 所谓的生命周期就是&#xff1a…

【SpringCloud】SpringCloud教程之Feign实战

目录前言SpringCloud Feign远程服务调用一.需求二.两个服务的yml配置和访问路径三.使用RestTemplate远程调用(order服务内编写)四.构建Feign(order服务内配置)五.自定义Feign配置(order服务内配置)六.Feign配置日志(oder服务内配置)七.Feign调优(order服务内配置)八.抽离Feign前…

论文投稿指南——中文核心期刊推荐(新闻事业)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

Spring Cloud融合Nacos配置加载优先级 | Spring Cloud 8

一、前言 Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置&#xff1a; A&#xff1a;通过内部相关规则(应用名、扩展名、profiles)自动生成相关的 Data Id 配置B&#xff1a;通过 spring.cloud.nacos.config.extension-configs的方式支持…

Redis十大类型——List常见操作

Redis十大类型——List常见操作 底层数据结构是双端链表 Redis列表是字符串值的链接列表。Redis列表经常用于&#xff1a; 实现堆栈和队列。为后台工作系统构建队列管理。 命令操作简列 lpush &#xff1a; 左侧添加元素rpush &#xff1a; 右侧添加元素lrange &#xff1a; …

LPNet for Image Derain

Lightweight Pyramid Networks for Image Deraining前置知识高斯-拉普拉斯金字塔图像中的高频信息和低频信息为什么高斯-拉普拉斯金字塔可以实现去雨&#xff1f;可能性分析网络结构整体结构&#xff1a;子网结构&#xff1a;递归块结构&#xff1a;后续补充代码 前置知识 这…

数组--java--动态数组--有序数组--底层

java数组基础--java中的数组创建数组空间占用初始化数组访问元素插入查找删除元素动态数组扩容插入和添加重写toString删除二维数组二维数组注意点有序数组实现测试写在开头&#xff1a; 这篇文章包括数组的基础、一点底层的内容和一些稍微深入的东西。 作为第一个深入学习的数…

【2021.12.25】ctf逆向中常见加密算法和编码识别

【2021.12.25】ctf逆向中常见加密算法和编码识别&#xff08;含exe及wp&#xff09; 文章目录【2021.12.25】ctf逆向中常见加密算法和编码识别&#xff08;含exe及wp&#xff09;0、前言1、基础加密手法2、base64&#xff08;1&#xff09;原理&#xff1a;&#xff08;2&#…

利用出厂状态下的闲置主机配置HP M1136打印机

利用出厂状态下的闲置主机配置HP M1136打印机 打印机型号&#xff1a;LaserJet M1136 MFP 主机状态&#xff1a;出厂状态&#xff0c;C盘及储存盘被分成了5片 网络环境&#xff1a;与打印机相连的主机全程无Internet连接&#xff0c;主机处于离线状态。打印机驱动及一些相关软…

Splunk 成功获取Salesforce 数据

1: 先说一下Splunk server 上要安装Splunk Add-on for Salesforce : (https://splunkbase.splunk.com/) 去下载: https://splunkbase.splunk.com/app/3549 2: 下载安装后,看到如下界面: 3: 官方的指导文档: Configure your Salesforce account to collect data…

0301_对应的南京比特物联网

0301_对应的南京比特物联网目录概述需求&#xff1a;设计思路实现思路分析1.流程拓展实现性能参数测试&#xff1a;参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better …

C#的Version类型值与SQL Server中二进制binary类型转换

使用C#语言编写的应用程序可以通过.NET Framework框架提供的Version类来控制每次发布的版本号&#xff0c;以便更好控制每次版本更新迭代。 版本号由两到四个组件组成&#xff1a;主要、次要、内部版本和修订。 版本号的格式如下所示&#xff0c; 可选组件显示在方括号 ([ 和…

UML 时序图

时序图&#xff08;Sequence Diagram&#xff09;是显示对象之间交互的图&#xff0c;是按时间顺序排列的。 时序图中显示的是参与交互的对象及其对象之间消息交互的顺序。 时序图包括的建模元素主要有&#xff1a;对象&#xff08;Actor&#xff09;、生命线&#xff08;Lif…

项目实战典型案例19——临时解决方案和最终解决方案

临时解决方案和最终解决方案一&#xff1a;背景介绍二&#xff1a;思路&方案四&#xff1a;总结五&#xff1a;升华一&#xff1a;背景介绍 本篇博客是对项目开发中出现的临时解决方案和最终解决方案进行的总结和改进。目的是将经历转变为自己的经验。通过博客的方式分享给…

(蓝桥真题)最长不下降子序列(权值线段树)

样例输入&#xff1a; 5 1 1 4 2 8 5 样例输出&#xff1a; 4 分析&#xff1a;看到这种对其中连续k个数进行修改的我们就应该想到答案是由三部分组成&#xff0c;因为求的是最长不下降子序列&#xff0c;那么我们可以找到一个最合适的断点i&#xff0c;使得答案是由区间[1…

【信息安全案例】——网络信息面临的安全威胁

&#x1f4d6; 前言&#xff1a;2010年&#xff0c;震网病毒&#xff08;Stuxnet&#xff09;席卷全球工业界。其目标是从物理上摧毁一个军事目标&#xff0c;这使得网络武器不仅仅只存在于那个人类创造的空间。网络武器的潘多拉魔盒已经打开。 目录&#x1f552; 1. 信息、信息…

28个精品Python爬虫实战项目

先来说说Python的优势&#xff01;然后给大家看下这28个实战项目的实用性&#xff01;Python跟其他语言相比&#xff0c;有以下优点&#xff1a;1. 简单Python是所有编程语言里面&#xff0c;代码量最低&#xff0c;非常易于读写&#xff0c;遇到问题时&#xff0c;程序员可以把…