背景
- 大约有5年没面试了,最近出去面试发现面试官不问算法了,反而问八股文和场景题,我这几天陆续产出点场景题了
前端怎么设置主题换肤方案
通过切换 css 选择器的方式实现主题样式的切换.
- 在各组件中样式不变,将需要变化的样式(色块、文字、边框等)颜色进行抽离
- 给不同的主题定义不同对应颜色变量
方案一
- 假设目前只有两种主题,light与dark,在需要设置换肤的div上setAttribute为data-theme,在css中写两套主题对应的css
在app.vue中
import { reactive }from "vue";
const configRef = reactive({
theme: "light"
})
const themeInit = () => {
let localTheme = localStorage.getItem("theme")
if (localTheme === null) {
let localHour = new Date().getHours()
localStorage.setItem("theme", localHour >= 6 && localHour < 18? "light" : "dark")
console.log(localHour)
}
else configRef.value.theme = localTheme
document.documentElement.setAttribute("data-theme", configRef.value.theme)
}
themeInit()
在某个页面中
<template>
<div id="theme-toggle-box" :data-theme="confRef.theme">
</div>
</template>
<script lang="ts">
export default {
name: "ThemeSwitch",
}
</script>
<style scoped>
#theme-toggle-box[data-theme="light"] {
border: 2px solid #00000020;
}
#theme-toggle-box[data-theme="dark"] {
border: 2px solid #4B4D4E;
}
</style>
优点:
- 样式和布局等都可配置
- 允许用户自定义
缺点:
- 每增加一套主题 就要写多个css,复用率不高,维护成本更高!!
方案二
- 通过CSS变量值实现换肤
1.首先需要建一个存放公共css变量的js文件,将需要定义的css变量存放到该js文件
//themeColor.js
//浅色
export const lightTheme = {
"--left-bg": "rgb(182, 23, 23)",
"--right-bg": "rgb(63, 9, 9)",
"--top-bg": "rgb(6, 36, 65)",
"--bottom-bg": "rgb(55, 214, 10)",
};
// 深色
export const darkTheme = {
"--left-bg": "#0094ff",
"--right-bg": "blue",
"--top-bg": "red",
"--bottom-bg": "pink",
};
2.页面中使用css变量,例如:
<style lang="less">
.left { background-color: var(--left-bg); }
</style>
3.安装css-vars-ponyfill 插件 在传统浏览器和现代浏览器中为CSS自定义属性(又名“CSS变量”)提供客户端支持的ponyfill。
npm i css-vars-ponyfill
4.封装切换主题的js,在main.js做初始化调用
// theme.js
import { lightTheme, darkTheme } from "../src/types/themeColor";
import cssVars from "css-vars-ponyfill";
export const initTheme = (theme) => {
document.documentElement.setAttribute("data-theme", theme ? "light" : "dark");
cssVars({
watch: true, // 当添加,删除或修改其<link>或<style>元素的禁用或href属性时,ponyfill将自行调用
variables: theme ? lightTheme : darkTheme, // variables 自定义属性名/值对的集合
onlyLegacy: false, // false 默认将css变量编译为浏览器识别的css样式 true 当浏览器不支持css变量的时候将css变量编译为识别的css
});
};
5.main.js做调用
import { initTheme } from './theme'
let theme = localStorage.getItem('theme') === 'light' ? false : true initTheme(theme)
6.主题值存储在localstorge中
localStorage.getItem('theme') === 'light' ? 'light' : 'dark'
优点:
- 实现简单快速
- 设计变量代码集中
缺点:
- 难以修改js控制的样式
- 不兼容IE
方案三
写个插件,轻松实现基于less、sass的 web 应用在线动态主题切换
vite 参考 vite-plugin-theme-preprocessor 、vite-plugin-theme
webpack 参考 webpack-stylesheet-variable-replacer-plugin、webpack-theme-color-replacer
比较推荐这个方案 比较好维护 多个项目都能使用