.header{...省略颜色:var(--theme-color);border-bottom:1pxsolidvar(--theme-boder-color);background-color:var(--theme-bg);}...Omit前言现在越来越多的网站提供换肤(切换主题)功能,如ElementUI,以满足用户需求或突出自身特色。因此,提供了个性化定制的功能。其实之前就想了解并实现“一键换肤”功能,但是由于种种原因一直拖到现在。CSS样式覆盖的核心是通过切换css选择器来实现主题样式的切换。组件中保持相同的样式,提取需要更改的样式,提供多种样式,为不同的主题定义对应的CSS选择器,根据不同的主题设置不同的样式,实现如下存储和控制全局theme通过vuex代码如下:import{createStore}from'vuex'//创建一个新的store实例conststore=createStore({state(){return{theme:'light'}},mutations:{setTheme(state,payload){state.theme=payloaddocument.querySelector('body').className=payload}}})exportdefaultstore通过vuex中的theme在template模板中设置对应的类名,比如header代码如下如下:{{title}}在下面的theme.css中,使用了两个class选择器.light和.dark来区分llight和dark主题,以及它们对应的样式是预先准备好的,如下:border-bottom:1pxsolid#d6d6d6;颜色:rgb(51,50,50);}.list.light.title{颜色:rgb(51,50,50);}.list.light.describe{颜色:rgb(158,158,158);}.list.light.left{border:1pxsolidrgb(51,50,50);}/*darkdarktheme*/body.dark{background-color:rgb(51,50,50);}.header.dark{背景色:rgb(51,50,50);border-bottom:1pxsolid#fff;颜色:#fff;}.list.dark.title{颜色:#fff;}.list.dark.describe{颜色:rgb(201,201,201);}.list.dark.left{border:1pxsolid#fff;background-color:#fff;}缺点必须引入多种主题样式,导致代码量增加,搜索样式难以管理。开发效率低,可扩展性差。。。实现多套CSS主题样式。多个主题色编译成一个文件,导致单个文件过大css部分直接拆分成ligth.css和dark.css两个文件:设置主题部分的setTheme.js代码如下:exportdefaultfunctionsetTheme(theme='ligth'){letlink=document.querySelector('#theme-link')lethref="/theme/"+theme+".css"if(!link){lethead=document.querySelector('head')link=document.createElement('link')link.id='#theme-link'link.rel="stylesheet"link.href=hrefhead.appendChild(link)}else{link.href=href}}缺点需要重复CV多个样式文件单独修改而不用单独提取变化的样式部分需要提前知道打包后的文件路径,否则可能会导致主题样式引入错误...CSS变量实现的核心是通过body.style.setProperty(key,value),以便页面其他部分的内容可以使用最新的CSS变量进行样式化。实现theme.css负责定义全局CSS变量,代码如下:/*实现方法1*/:root{--theme-bg:initial;//背景颜色--theme-color:initial;//字体颜色--theme-boder-color:initial;//边框颜色}=======================================================/*实现方法2*//*默认值:light*/:root{--theme-bg:#fff;--主题颜色:rgb(51,50,50);--theme-img-bg:#fff;--theme-boder-color:#d6d6d6;}/*深色:深色*/[data-theme='dark']{--theme-bg:rgb(51,50,50);--主题颜色:#fff;--theme-boder-color:#fff;}ThemeUtil.js负责获取当前对应的样式值,并设置body上的值CSS变量值如下:constdarkTheme='rgb(51,50,50)'constlightTheme='#fff'constlightBorderTheme='#d6d6d6'//获取对应的主题色值exportconstgetThemeMap=(isLight)=>{return{'theme-bg':isLight?lightTheme:darkTheme,'theme-color':isLight?darkTheme:lightTheme,'theme-boder-color':isLight?lightBorderTheme:lightTheme,}}//设置主题颜色值exportconstsetTheme=(isLight=true)=>{constthemeMap=getThemeMap(isLight)constbody=document.body/*实现方式一*/Object.keys(themeMap).forEach(key=>{body.style.setProperty(`--${key}`,themeMap[key])})/*实现方式二*///body.style.setProperty('data-theme',isLight?'light':'dark')}通过var()在组件中应用相应的CSS变量,比如在head中使用:.header{...省略颜色:var(--theme-color);border-bottom:1pxsolidvar(--theme-boder-color);background-color:var(--theme-bg);}...Omit缺点缺点是兼容性不好通过css-vars-ponyfill处理兼容的CSS变量,将themeUtil.js中的代码修改为:importcssVarsfrom"css-vars-ponyfill";constdarkTheme='rgb(51,50,50)'constlightTheme='#fff'constlightBorderTheme='#d6d6d6'//这里定义的key/valuepair是给cssVars传递参数exportconstgetThemeMap=(isLight)=>{返回{'--theme-bg':isLight?lightTheme:darkTheme,'--theme-img-bg':lightTheme,'--theme-color':isLight?darkTheme:lightTheme,'--theme-boder-color':isLight?lightBorderTheme:lightTheme,}}exportconstsetTheme=(isLight=true)=>{constthemeMap=getThemeMap(isLight)constbody=document.body/*实现1*/Object.keys(themeMap).forEach(key=>{body.style.setProperty(key,themeMap[key])})/*实现方法2*///body.style.setProperty('data-theme',isLight?'light':'dark')//实现兼容schemecssVars({watch:true,//添加、删除、修改或