1。前言上一个项目需要添加主题变色功能。接下这个需求后,我们开始分析项目的代码内容。我主要分为两类,一类是elementUI下的组件,一类是自定义模板或者组件。两种类型都需要切换样式才能达到变色效果。为了尽可能优雅,最好只改变一个地方,并且可以改变颜色而不重复相同的款式。我的菜鸡真的花了很多时间在上面。二、方案设计方案1、动态引入链接标签或使用不同的类名来切换不同的主题?设计多套不同主题风格的文件。需要时,创建链接标签以动态加载到head标签中,或动态更改链接标签的href属性。或者当主题需要切换时,根标签切换对应的类名来切换不同的风格。但这样一来,如果需要更改某个样式,则需要更改所有主题,既麻烦又容易出错。这可以说是最笨的方法了。方案二、使用css变量+类名切换这是对方案一的改进,大体思路和方案一类似,依然是提前加载样式文件,切换时替换指定的根元素类名。不过这里比较灵活的是CSS变量默认定义在根范围内,你只需要在不同的主题下改变CSS变量对应的值即可。这样操作的好处是,通过CSS变量,可以达到一次更改全部更改的效果。方案三、使用CSS变量+动态setPropertyScheme3会比前两种更灵活,但要看情况。该方案适合用户根据颜色面板设置各种颜色主题。这种主题颜色是不确定的情况,而前两种方案更适合定义几个预设主题。3.方案实践经过综合考虑,我决定使用第三种方案,因为第三种方案足够灵活,可以通过js设置几个默认主题,也可以留给用户自己挑一个颜色来设置新的主题。这样更有利于以后需求变化的时候修改。以下内容将以方案三展开:在工程中新建一个theme文件夹,放置以下文件内容:同上,index.html中的字体文件。设置颜色替换文件中对应的颜色,然后全局放置在html的style标签中,完成elementUI的主题色替换。自定义模板或组件的颜色样式由另一个文件完成。首先看下如何替换elementUI的主题://安装css-color-function,后面会用到转换颜色是rgb还是十六进制npmcss-color-function//yarnaddcss-color-function通过formula.json获取颜色变化规则,然后使用generateColors函数转换颜色//formula.json{"primary":"color(primary)","shade-1":"color(primaryshade(10%)","shade-2":"color(primaryshade(20%))","shade-3":"color(primaryshade(30%))","shade-4":"color(原色(40%))","shade-5":"color(primaryshade(50%))","shade-6":"color(primaryshade(60%))","shade-7":"color(primaryshade(70%)))","shade-8":"color(primaryshade(80%))","shade-9":"color(primaryshade(90%))",“alpha-1”:“颜色(主要alpha(.1))”,“alpha-2”:“颜色(主要alpha(.2))”,“alpha-3”:“颜色(主要alpha(.3)))",“alpha-4”:“颜色(主要alpha(.4))”,“alpha-5”:“颜色(主要alpha(.5))”,“alpha-6”:“颜色(主要alpha(.6)))","alpha-7":"color(primaryalpha(.7))","alpha-8":"color(primaryalpha(.8))","alpha-9":"color(primary)alpha(.9))","light-1":"color(primarytint(10%))","light-2":"color(primarytint(20%))","light-3":"color(primarytint(30%))","light-4":"color(primarytint(40%))","light-5":"color(primarytint(50%))","light-6":"color(primarytint(60%))","light-7":"color(primarytint(70%))","light-8":"color(primarytint(80%))","light-9":"color(primarytint(90%))"}//color.js从'css-color-function'导入表单导入颜色ulafrom'./formula.json'exportfunctiongenerateColors(primary){letcolors={}Object.keys(formula).forEach((key)=>{constvalue=formula[key].replace(/primary/g,primary)constc=color.convert(value)colors[key]=c.indexOf('rgba')>-1?c:colorRgbToHex(c)})returncolors}/*将rgb颜色转换为十六进制*/export函数colorRgbToHex(rgb){let[r,g,b]=rgb.replace(/(?:\(|\)|rgb|RGB)*/g,'').split(',')return'#'+((1<<24)+(Number(r)<<16)+(Number(g)<<8)+Number(b)).toString(16).slice(1)}预设默认颜色每个主题都是为了打电话。如果有多个主题,直接写就可以了。如果以后题目比较多,可以使用mix-in功能。//model.jsletthemes={default:{color_block:"#07b6b5",color_line:"#009aa6"}}export{themes}elementUI主题颜色替换函数代码://index.jsimport{generateColors}from'./color'letstyle=require('!!css-loader?sourceMap=false!postcss-loader?{"postcssOptions":{"plugins":{"cssnano":{}}}}!./index.css')。toString();从'./formula.json'导入公式letoriginalStyle=''exportfunctionwriteNewStyle(themeColor){letcolors=generateColors(themeColor)letcssText=originalStyleletcolorsCssText=''Object.keys(colors).forEach((key)=>{cssText=cssText.replace(newRegExp('(:|\\s+)'+key,'g'),'$1'+colors[key])colorsCssText+=`.color-${key}{color:${colors[key]}!important;}.bg-${key}{background-color:${colors[key]}!important;}.border-${key}{border-颜色:${colors[key]}!important;}`})console.log("cssText",cssText)letstyleTag=document.getElementById('ide-theme-style')if(!styleTag){styleTag=document.createElement('style')styleTag.setAttribute('id','ide-theme-style')document.head.appendChild(styleTag)}styleTag.innerText=cssText+colorsCssText}导出函数getIndexStyle(themeColor){if(!originalStyle){originalStyle=getStyleTemplate(style,themeColor)}writeNewStyle(themeColor)}导出函数getStyleTemplate(data,themeColor){让colors=generateColors(themeColor)constcolorMap=newMap()Object.keys(formula).forEach((key)=>{colorMap.set(colors[key],key)})for(let[key,value]的colorMap){data=data.replace(newRegExp(key,'ig'),value)}returndata}自定义模板或组件替换主题颜色函数代码://theme.jsimport{themes}from"./model";import{getIndexStyle}from"./index.js"constchangeStyle=(obj)=>{for(letkeyinobj){document.getElementsByTagName(";body")[0].style.setProperty(`--${key}`,obj[key]);}};//设置主题的颜色constsetThemeColor=(theme)=>{localStorage.setItem("theme",JSON.stringify(theme));//将主题保存到本地,下次输入时使用changeStyle(theme);//改变样式}constsetFontFamily=(FontFamilyName)=>{localStorage.setItem("FontFamily",FontFamilyName);constthemeConfig={themeFontFamily:FontFamilyName};changeStyle(themeConfig);}exportconstsetTheme=(type='themeColor')=>{if(type==='themeColor'){让当前主题=localStorage.getItem("theme")&&JSON.parse(localStorage.getItem("theme"));if(!currentTheme){currentTheme=themes.default}setThemeColor(currentTheme);getIndexStyle(currentTheme.color_block)}elseif(type==='FontFamily'){letFontFamily=localStorage.getItem("FontFamily");setFontFamily(Font家庭);}};以上就是主题文件夹文件的介绍。调用的入口函数是theme.js文件中的setTheme函数。需要在project工程的main.js文件中引入setTheme函数。如:import{setTheme}from"@/theme/theme";//然后调用创建的生命周期中的函数//初始化主题颜色setTheme&&setTheme();注意:需要注意的是,index.css文件的调用有两种方式,一种是从后台获取,一种是从本地调用。后台获取比较容易理解,但是前端获取css文件的纯文本内容就比较麻烦了。也花了一些时间来解决它。现在给出一个自己的解决方案供参考:使用require获取文本并转换为字符串://cssimportletstyle=require('!!css-loader?sourceMap=false!postcss-loader?{"postcssOptions":{"plugins":{"cssnano":{}}}}!./index.css').toString();//scssimportletstyle=require('!!css-loader?sourceMap=false!postcss-loader?{"postcssOptions":{"plugins":{"cssnano":{}}}}!sass-loader!./style.scss').default.toString();//less引入letstyle=require('!!css-loader?sourceMap=false!postcss-loader?{"postcssOptions":{"plugins":{"cssnano":{}}}}!less-loader!./style.less').default。toString();
