网站换肤方案总结

371 阅读6分钟

日常记录,Xmind不够记录的了

 之前的项目采用的是硬编码,维护两套css文件,切换主题时,引不同的css文件进行换肤。之后需要支持新的主题色,由此引出了动态换肤这个需求。记录下自己尝试的方案

方案一:采用css变量与less变量结合的方式开发

大概思路:

1. 项目中的元素色值使用less全局变量  

2.less全局变量值使用css变量控制  

3.在切换主题的时候,修改css变量,导致主题换肤的效果

基于以上的思路,现在说下具体的代码实现

  • 全局less变量

第一步:配置less全局变量,在项目各个元素进行使用,配置方式有一下两种

1. 使用vuecli插件 ,vue-cli-plugin-style-resource-loader

    vue add style-resource-loader

vue.config.js:

const path=require("path")
module.exports={ 
...
pluginOptions:{ 
    'style-resource-loader':{ 
       'preProcessor':'less',
       patterns:[path.resolve(__dirname,".src/common/common.less"/*公共less变量文件*/)]
    }
  }
}

2. 使用sass-resources-loader

   yarn add style-resources-loader

vue.config.js:

module.exports={
...
chainWebpack:config=>{ 
    config.moudule.rule("less").oneOfs.store.forEach(item=>{ 
        item
          .use("sass-resources-loader")
          .loader("sass-resources-loader")
          .options({ 
            resources:'./src/common/common.less'
          })
      })
  }
}

第二步:说下全局less文件与css变量

  • css变量配置文件

cssModel.js : 

//这里主要是维护不同主题的色值
export const cssTheme={ 
  themeOne:{ 
    btn_P1:'#a62b15' ,
    btn_P2:'#63b3f8',
    ....
  },
  themeTwo:{ 
     btn_P1:'#ff846c' ,
     btn_P2:'#63b3f880',
     ....
  },

  //之后可以根据需求配置自己的主题色,只要注意不同主题下,key值统一就行了
}
  • 全局less变量文件

common.less

@btn_P1:var(--btn_P1 , #a62b15)
@btn_P2:var(--btn_P2 , #63b3f8)...
//var(自己定义的css变量,css变量默认值)预设一个css变量默认值,使刚进入页面的时候不要因为还没有初始化css变量完成导致页面“闪一下”

 第三步:切换主题时,改变全局css变量,达到换肤目的:

这里只说下最重要的换肤逻辑,具体项目中会结合状态管理,实现存储用户切换的主题

changeSkin.js

import {cssTheme} from 'cssModel.js'
export const initTheme=(theme="themeOne")=>{ 
    let themeTemp=theme;
    ...
    //省略的逻辑:通过状态管理或storage之类的状态改变这个themeTemp
   changeTheme(themeTemp)
}
export const changeTheme=(theme="themeOne")=>{ 
    //这里获取到对应的主题json
    const cssTheme=cssTheme[theme]
    ...
    //省略的逻辑:更新主题状态并存储
    changeCssVar(cssTheme)
}
const changeCssVar=cssTheme=>{ 
  for(let key of cssTheme){ 
     document.getElementsByTagName("body")[0].style.setProperty(`--${key}`,cssTheme[key])}}

最后在组件中使用less变量就可以了

<componentA />内部less:
<style lang="less" scope>
 .btnPrimary{ 
   background:@btn_P1 
  }
</style>

以上,第一种方案的逻辑走完了。项目初始化的时候,initTheme初始化css变量,换肤的时候,changeTheme传入在cssModel.js中定义的主题名称,改变css全局变量。

需要注意的是:与UI同学敲定色值的时候,一定要说清楚,

  • 一个编码(cssModel.js中主题下的key值)对应N个色值,开发到一半时,想要修改某个主题下某个按钮的色值,只能新增编码,否则会影响其他使用这个编码的元素
  • 同一个元素,只能使用一个编码,不可能说换肤的时候,改变该元素的色值编码。如果发现当前使用的编码在某个主题下色值不太好,如果影响范围小,直接修改色值,影响大,新增编码

对于方案一个的补充:兼容性

因为IE浏览器是完全不兼容css变量的,如果有IE需求,可以使用cssVars兼容处理,不过也有弊端,先说怎么兼容:

import cssVars from "css-vars-ponyfill"

//在changeSkin.js中,changeTheme方法改写,不去调用changeCssVar,直接使用cssVars处理

export const changeTheme= (theme='themeOne') => {
    cssVars({
	preserveStatic:false,
	watch: true, 
	variables: cssTheme[theme], 	
        onlyLegacy: false
 };			    		 
  • 参数说明

watch:当添加,删除或修改其或元素的禁用或href属性时,ponyfill将自行调 用

variables :自定义的 [变量名,色值] 键值对

onlyLegacy :false--默认将css变量编译为浏览器识别的css样式   true--当浏览器不支持css变量的时候将css变量编译为识别的css

preserveStatic:只会将样式中的颜色部分插入到文档中,增强了性能

  • cssVars原理

1. 将页面中的样式进行分类,如果link或者style中的样式没有包含css自定义变量,就将标签的data-cssvars属性赋值为 "skip";如果包含了,该属性赋值为 "src"

2. 根据传入的键值对,将data-cssvars值为 “src” 的内部css自定义变量替换为对应的色值

3. 替换完成,data-cssvars属性值改为 “out” ,并将其整体以style标签的形式插入到文档中

  • cssVars弊端

如果css变量特别多,或者css文件特别大,那么替换的时长比较长,性能不好,用户体验也不会好,因为会有一个颜色切换的过程,过程还很明显。preserveStatic设置为false也是这个原因,将替换的样式,只涉及到颜色的部分插入到文档中,再之后替换色值的时候会稍微提高下性能。但是我试过这个配置,效果不是很理想

方案二:利用less的映射+混入 / scss的map-get+混入实现换肤

文章地址:juejin.cn/post/714576…

方案三:利用less在线编译实现

引入less.js。通过less.ModifyVars改变变量

这种方式不是很友好,大概的逻辑是:页面的less变量写在variable.less中,页面需要换肤的样式可以写在A.less B.less ...,在index.less中分别引入variable.less,A.less,B.less,然后在modifyVars中,修改某个less变量。

注意:less文件要放在public中,否则modifyVars方法会报错

具体的实现步骤,可以参考这两位同学的文章

www.cnblogs.com/zhizhi0810/…

blog.csdn.net/qq\_3483114…

补充说明:

上面两篇文章都是在vue.config.js中定义了初始化的变量。而我说的方式是初始化less文件,然后在index中引用,感觉这种方式也是能行得通的(我确实是没试过这样做)

所以综上,要换肤的话,实现起来还是比较麻烦的,而且把样式文件抽离出来放在public中,不说前期开发写的别扭,还容易有样式覆盖的可能,因为没有了scoped作为保护。再而且如果是一个已经成型的项目,用这种方式做换肤,各种样式抽离+样式覆盖简直是灾难~所以这种方式不建议使用

方案四:用less编译工具编译下新的样式文件

其实这种方式还是属于硬编码,维护另一个样式总的文件,只不过可以用less书写。编译后把样式.css文件参与换肤中,每次切换主题,link引用不同的样式文件.

这种方式前期开发,后期修改色值,都很麻烦,

以上就是关于网站换肤的集中方案的记录。当然还有支持用户自定义色值的换肤,elementUI的动态换肤,还没有看这种解决方案~

有时间的话,我也要看下微信小程序的换肤再继续记录下~

方案五:css变量+css--兼容IE

juejin.cn/post/715425…