场景题-前端怎么设置主题换肤方案

164 阅读2分钟

背景

  • 大约有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>

优点:

  1. 样式和布局等都可配置
  2. 允许用户自定义

缺点:

  1. 每增加一套主题 就要写多个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'

优点:

  1. 实现简单快速
  2. 设计变量代码集中

缺点:

  1. 难以修改js控制的样式
  2. 不兼容IE

方案三

写个插件,轻松实现基于lesssass的 web 应用在线动态主题切换

vite 参考 vite-plugin-theme-preprocessorvite-plugin-theme

webpack 参考 webpack-stylesheet-variable-replacer-pluginwebpack-theme-color-replacer

比较推荐这个方案 比较好维护 多个项目都能使用