如何优雅的实现复杂的主题换肤功能

2,601 阅读3分钟

前端必备技能 -- 主题换肤功能

开源

个人开源的leno-admin后台管理项目,前端技术栈:reactHooksant-design;后端技术栈:koamysqlredis,整个项目包含web端electron客户端mob移动端template基础模板,能够满足你快速开发一整套后台管理项目;如果你觉得不错,就为作者点个✨star✨吧,你的支持就是对我最大的鼓励;

演示地址

文档地址

源码github地址

在一个平静的加班夜里,正在工位上摸鱼的小刘;
突然公司领导冷不丁的出现在小刘身边,说了一句让小刘头皮发麻的话:“小刘啊!我刚刚想,我们公司那个软件加一个换肤功能会不会好看些啊?
小刘的内心虽然已经开始逐渐抓狂,但是表面上还是得大力赞赏领导的这个奇思妙想;
今夜注定是一个属于小刘的漫漫长夜~

第一章 拯救小刘之从安装scss做起

如果你项目在构建的时候就选择了scss可以直接下一章哦

1、首先检查下看下你原先的项目安装scss没,如果没有还不快帮小刘安装scss;

npm install node-sass sass-loader --save-dev

2、既然安装了scss,那就去webpack.base.config.js当中的rules添加scss规则;

{
    test: /\.scss$/,
    loaders: ['style', 'css', 'sass'v]
}

3、在vue中使用scss小刘应该咩问题吧!但还是把格式写一下吧!

<style lang='scss' scoped>

</style>

第二章 拯救小刘之搭建主题对象

在styles文件夹里创建_theme.scss文件;
这个动态切换主题是利用data-theme属性在HTML元素最顶层的body或者HTML上设置,data-theme = "_theme.scss里提前设置的主题色库" 这个属性的;
最后用 window.document.documentElement.setAttribute( "data-theme", _theme.scss里提前设置的主题色库);来达到主题的切换功能的;

// 在_theme.scss文件内部创建两个测试用的主题方案,data-theme=“小刘设置主题方案”;
// 其中要注意的就是,每套你设置的方案颜色、种类多少都可以自定义,但是要保证每套方案的key都一样才不会造成后期紊乱;
// 主题模板必须放置在$themes当中;

$themes: (
    themeRed: ( 
        //字体
        font_color1: #373737,
        font_color2: #ec4141,

        //背景
        background_color1: #ec4141,

        // 边框
        border_color1: #ec4141,
    ),
    themePick: ( 
        //字体
        font_color1: #373737,
        font_color2: #ff7a9e,

        //背景
        background_color1: #ff7a9e,

        // 边框
        border_color1: #ff7a9e,
    ),
 )

第三章 拯救小刘之配置scss混入器

在styles文件夹里再创建一个_handle.scss文件来防止scss混入器,操作_theme.scss里小刘之前设置的主题模板

@import "./_themes.scss";

//遍历主题map
@mixin themeify {
    @each $theme-name, $theme-map in $themes {
        //!global 把局部变量强升为全局变量
        $theme-map: $theme-map !global;
        //判断html的data-theme的属性值  #{}是sass的插值表达式
        //& sass嵌套里的父容器标识   @content是混合器插槽,像vue的slot
        [data-theme="#{$theme-name}"] & {
            @content;
        }
    }
}

//声明一个根据Key获取颜色的function
@function themed($key) {
    @return map-get($theme-map, $key);
}

//获取背景颜色
@mixin background_color($color) {
    @include themeify {
        background-color: themed($color)!important;
    }
}

//获取字体颜色
@mixin font_color($color) {
    @include themeify {
        color: themed($color)!important;
    }
}

//获取边框颜色
@mixin border_color($color) {
  @include themeify {
      border-color: themed($color)!important;
  }
}

上面我只定义了三个比较常规的背景色,边框色,字体色的主题色更换,你想再增多可以继续往下额外添加即可;

第四章 拯救小刘之组件内使用

组件内使用,也很简单先引入_handle.scss,后用@include来设定背景、边框、字体颜色等

<style lang="scss" scoped>
    @import '@/styles/_handle.scss';

.el-header {
  @include background_color("background_color1"); // 主题背景色
  @include font_color("font_color2");   // 主题色

  border: 1px solid #000;
  @include border_color("border_color1"); // 主题颜色的边框
}
</style>

// 注意,设置边框时,保留原先的border设置,在下面添加@include边框主题色覆盖;

第五章拯救小刘之动态切换主题功能

1、在HTML或Body顶层元素上设置data-theme

<html lang="zh-CN" data-theme="themeRed">

2、template里面设置颜色更改,传递主题色索引号

      <div v-for="(item,index) in colorThemList" :key="index" class="small-box">
        <div :style="{backgroundColor:item}" :data-index="index" @click="changeColorFn">
          <svg v-show="index === isShowIconIndex" slot="reference" class="icon set-icon right-icon" aria-hidden="true">
            <use xlink:href="#icon-danxuan-xuanzhong" />
          </svg>
        </div>
      </div>

3、点击对应主题,传回索引值,更改全局主题色

changeColor(index) {
  if (index === 0) {
        window.document.documentElement.setAttribute('data-theme', 'themeRed')
   } else if (index === 1) {
       window.document.documentElement.setAttribute('data-theme', 'themePick')
   } 
}

4、接下来,你的css样式初选以下属性就表示成功啦~

[data-theme=themeGreen4] .el-header {
    background-color: #3e7972 !important;
}

终章 拯救小刘计划成功

小刘望着眼前随着自己点击而不断变换颜色的主题,心中不免开始愉悦了起来,~ “我这么能干,会不会给老板看中,从此走上升任总经理、迎娶白富美、走上人生巅峰的王大锤之路啊!!!”

想想就让人开心~~💯