现在越来越多的网站都提供了拥有换肤(切换主题)功能,如 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
进行更好的实现。
参考文章:点击这里