XingYun blog
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具

XingYun

冲!
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具
  • 3个提升Vue性能的写法
  • 重读Vue文档
  • moment.js给定时间获取自然月、周的时间轴
  • Vue虚拟dom与Diff算法
  • 深入响应式原理
  • Echart样例
  • 我的Vue指令库
  • 滚动到底部加载更多
  • 实现一键换肤
    • 1. 方案一:每种主题写一套独立样式文件
      • theme.scss 主文件
      • 每个 theme 主题的组成
      • theme store 管理主题状态
      • 总结
    • 2. 方案二:利用 CSS 变量
      • 2.1 实现方式
      • 2.2 为什么要用样式变量而不用scss变量呢?
  • 手写Vue数据劫持
  • vue-router核心原理与手写实现
  • computed和watch
  • vue数组为什么不是响应式
  • v-for为什么不能用index做key
  • webpack loader和plugin
  • keep-alive组件原理
  • vue插槽进化
  • Vue多层嵌套组件
  • vue生命周期hook
  • vue监听dom元素的resize事件
  • 前端打包需要gzip压缩吗
  • 实现水波浪进度球
  • Vue
XingYun
2022-04-12
目录

实现一键换肤

# 1. 方案一:每种主题写一套独立样式文件

重点: 给 body 赋值不同的类名切换主题

# theme.scss 主文件

# 每个 theme 主题的组成

  1. 变量文件

  1. 引入文件

这里先引入了变量文件然后引入 theme.scss 主文件

编译以后就会生成

.theme-dark-technology {
  .app-container {
    /* 各种样式代码 */
  }
}
1
2
3
4
5

同理其它的主题也会形成类似的主题文件

这样我们就得到了

/* 深色主题 */
.theme-dark-technology {
  .app-container {
    /* 各种样式代码 */
  }
}

/* 浅色主题 */
.theme-light-simple {
  .app-container {
    /* 各种样式代码 */
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

样式代码准备好了,接下来就解决主题的切换

# theme store 管理主题状态

export default {
  namespaced: true,

  state: {
    activeTheme: getStorageTheme()
  },

  getters: {},

  mutations: {
    mergeState(state: any, payload: any = {}) {
      mergeOptions(state, payload)
    },
    addClassName(state, key) {
      state.activeTheme = key
      setStorageTheme(key) // 持久化到localStorage
      document.body.className = `theme-${state.activeTheme}`
    }
  },

  actions: {
    applyTheme(context: any, key: any) {
      context.commit('addClassName', key)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

这样在合适的组件里执行 applyTheme(key) 就可以切换主题了

用一个简单菜单来演示下切换效果

# 总结

这个方案比较简单易于实现,但是由于每个主题都有一套样式代码,很容易产生大量代码,所以一般推荐提取公共代码到 theme-base.scss。

# 2. 方案二:利用 CSS 变量

这也是 element-plus 实现换肤的方案

# 2.1 实现方式

element-plus 官方提供了两套主题,一套是 dark,一套是 light。

实现方式和方案一一样是通过 html 的 class 来区分主题,

但是不同点是在 element-plus 主题文件中添加变量,然后在样式中应用 var(--theme-color)

下面是一套 element-plus 主题样式 example

// 黑色主题 element变量配置
html.dark {
  color-scheme: dark;
  --el-color-primary: #409eff;
  --el-color-primary-light-3: #3375b9;
  --el-color-primary-light-5: #2a598a;
  --el-color-primary-light-7: #213d5b;
  --el-color-primary-light-8: #1d3043;
  --el-color-primary-light-9: #18222c;
  --el-color-primary-dark-2: #66b1ff;
  --el-color-success: #67c23a;
  --el-color-success-light-3: #4e8e2f;
  --el-color-success-light-5: #3e6b27;
  --el-color-success-light-7: #2d481f;
  --el-color-success-light-8: #25371c;
  --el-color-success-light-9: #1c2518;
  --el-color-success-dark-2: #85ce61;
  --el-color-warning: #e6a23c;
  --el-color-warning-light-3: #a77730;
  --el-color-warning-light-5: #7d5b28;
  --el-color-warning-light-7: #533f20;
  --el-color-warning-light-8: #3e301c;
  --el-color-warning-light-9: #292218;
  --el-color-warning-dark-2: #ebb563;
  --el-color-danger: #f56c6c;
  --el-color-danger-light-3: #b25252;
  --el-color-danger-light-5: #854040;
  --el-color-danger-light-7: #582e2e;
  --el-color-danger-light-8: #412626;
  --el-color-danger-light-9: #2b1d1d;
  --el-color-danger-dark-2: #f78989;
  --el-color-error: #f56c6c;
  --el-color-error-light-3: #b25252;
  --el-color-error-light-5: #854040;
  --el-color-error-light-7: #582e2e;
  --el-color-error-light-8: #412626;
  --el-color-error-light-9: #2b1d1d;
  --el-color-error-dark-2: #f78989;
  --el-color-info: #909399;
  --el-color-info-light-3: #6b6d71;
  --el-color-info-light-5: #525457;
  --el-color-info-light-7: #393a3c;
  --el-color-info-light-8: #2d2d2f;
  --el-color-info-light-9: #202121;
  --el-color-info-dark-2: #a6a9ad;
  --el-box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, 0.36), 0px 8px 20px rgba(0, 0, 0, 0.72);
  --el-box-shadow-light: 0px 0px 12px rgba(0, 0, 0, 0.72);
  --el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, 0.72);
  --el-box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, 0.72), 0px 12px 32px #000000,
    0px 8px 16px -8px #000000;
  --el-bg-color-page: #0a0a0a;
  --el-bg-color: #141414;
  --el-bg-color-overlay: #1d1e1f;
  --el-text-color-primary: #e5eaf3;
  --el-text-color-regular: #cfd3dc;
  --el-text-color-secondary: #a3a6ad;
  --el-text-color-placeholder: #8d9095;
  --el-text-color-disabled: #6c6e72;
  --el-border-color-darker: #636466;
  --el-border-color-dark: #58585b;
  --el-border-color: #4c4d4f;
  --el-border-color-light: #414243;
  --el-border-color-lighter: #363637;
  --el-border-color-extra-light: #2b2b2c;
  --el-fill-color-darker: #424243;
  --el-fill-color-dark: #39393a;
  --el-fill-color: #303030;
  --el-fill-color-light: #262727;
  --el-fill-color-lighter: #1d1d1d;
  --el-fill-color-extra-light: #191919;
  --el-fill-color-blank: transparent;
  --el-mask-color: rgba(0, 0, 0, 0.8);
  --el-mask-color-extra-light: rgba(0, 0, 0, 0.3);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

在项目的样式文件中引入这段代码就可以覆盖黑暗主题下的element-plus主题样式

# 2.2 为什么要用样式变量而不用scss变量呢?

#vue
上次更新: 2023/04/05, 09:41:10
滚动到底部加载更多
手写Vue数据劫持

← 滚动到底部加载更多 手写Vue数据劫持→

最近更新
01
JavaScript-test
07-20
02
二维码的原理
07-20
03
利用ChatGPT优化代码
07-20
更多文章>
Theme by Vdoing | Copyright © 2021-2023 XingYun | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式