现在越来越多的网站都提供了拥有换肤(切换主题)功能,如 elementui,既是为了迎合用户需求,或是为了凸显自己特点,因此提供了个性化定制的功能.
其实之前就想了解和实现 “一键换肤” 功能,但是由于种种原因一直拖到了现在。
一、CSS 样式覆盖实现
核心
通过切换 css 选择器的方式实现主题样式的切换.
- 在组件中保留不变的样式,将需要变化的样式进行抽离
- 提供多种样式,给不同的主题定义一个对应的 CSS 选择器
- 根据不同主题设置不同的样式
实现
下面通过 vuex 存储和控制全局的主题色,其代码如下:
import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
state () {
return {
theme: 'light'
}
},
mutations: {
setTheme (state, payload) {
state.theme = payload
document.querySelector('body').className = payload
}
}
})
export default store
在 template 模板中通过 vuex 中的主题设置对应类名,如头部代码如下:
<template>
<div :>
<span>{{title}}</span>
<input v-model="checked" type="checkbox" @change="changeTheme" />
</div>
</template>
下面 theme.css 中通过 .light 和 .dark 两个类选择器来区分明亮主题和暗黑主题,并且事先准备了它们对应的样式,如下:
/* light 默认主题*/
body.light {
background-color: #fff;
}
.header.light {
background-color: #fff;
border-bottom: 1px solid #d6d6d6;
color: rgb(51, 50, 50);
}
.list.light .title {
color: rgb(51, 50, 50);
}
.list.light .describe{
color: rgb(158, 158, 158);
}
.list.light .left{
border: 1px solid rgb(51, 50, 50);
}
/* dark 暗黑主题 */
body.dark {
background-color: rgb(51, 50, 50);
}
.header.dark {
background-color: rgb(51, 50, 50);
border-bottom: 1px solid #fff;
color: #fff;
}
.list.dark .title {
color: #fff;
}
.list.dark .describe{
color: rgb(201, 201, 201);
}
.list.dark .left{
border: 1px solid #fff;
background-color: #fff;
}
缺点
- 多种主题样式都要引入,导致代码量增大
- 样式不易管理
- 查找样式复杂
- 开发效率低
- 拓展性差
- …
二、实现多套 CSS 主题样式
核心
实现多套 CSS 主题样式,根据用户切换操作,通过 link 标签动态加载不同的主题样式,主要解决了多个主题色被编译到一个文件中导致单个文件过大。
实现
css 部分直接拆分成 ligth.css 和 dark.css 两个文件。
设置主题部分的 setTheme.js 代码如下:
export default function setTheme(theme = 'ligth') {
let link = document.querySelector('#theme-link')
let href = "/theme/" + theme + ".css"
if (!link) {
let head = document.querySelector('head')
link = document.createElement('link')
link.id = '#theme-link'
link.rel = "stylesheet"
link.href = href
head.appendChild(link)
} else {
link.href = href
}
}
缺点
- 需要重复 CV 多份样式文件进行单独修改
- 没有单独提取出可变的样式部分
- 需要提前知道打包后的文件路径,否则可能导致主题样式引入错误
- …
三、CSS 变量实现
核心
通过 body.style.setProperty(key, value) 动态修改 body 上的 CSS 变量,使得页面上的其他部分可以应用最新的 CSS 变量对应的样式。

结语
以上就是目前了解到一些的换肤方案,以上全部基于 css 去实现的,不过知道了原理就可以结合 less 和 sass 进行更好的实现。
参考文章:点击这里