1:前提准备

1.需要安相关的依赖

npm install style-resources-loader -D
npm install vue-cli-plugin-style-resources-loader -D

2.在这里我使用的less,所以没有安装less相对应的依赖的话需要安装less

npm install less-loader@5.0.0 --save
npm install less --save

2:具体实现

 1.创建全局的 less 变量文件:variables.less

//导航栏
@navbackground  :var(--navbackground,'#001529'); // var('变量名','默认值')
//tab
@tabbackground :var(--tabbackground,'black');
@tabfontcolor : var(--tabfontcolor,'black');
//主题颜色
@contentbackground :var(--contentbackground,'#1890ff');
@contenthouverbackground :var(--contenthouverbackground,'#e6f7ff');
@buttonhouverbackground : var(--buttonhouverbackground,'#fff');
//抛出自己定义的变量
:export{
  name: 'less';
  navbackground:@navbackground;
  tabbackground:@tabbackground;
  contentbackground:@contentbackground;
  contenthouverbackground:@contenthouverbackground;
  tabfontcolor : @tabfontcolor;
  buttonhouverbackground : @buttonhouverbackground;
}

2.定义主题默认对应的颜色 :model.js

export const themes = {
  //默认nav导航栏
  default: {
    navbackground:'#001529'
  },
  dark: {
    navbackground:'#ffffff'
  },
  //默认头部
  headerdefault:{
    tabbackground:'#ffffff',
    tabfontcolor:'#000'
  },
  headerdedark:{
    tabbackground:'#000000',
    tabfontcolor:'#fff'
  },

  headerthreme:{
    tabbackground : "#1890ff",
    tabfontcolor:'#fff'
  },
  //默认主题颜色
  themebackground : {
    contentbackground: '#1890ff',
    contenthouverbackground : "#e6f7ff",
    tabfontcolor:'#fff'
  },
};

2.配置解析less变量设置:在vue.config.json文件中找到 mudule.exprots

module.exports = defineConfig({
    publicPath: process.env.NODE_ENV === "production" ? "./" : "./",
    // 输出文件目录
    outputDir: 'dist',
    pluginOptions: {
      "style-resources-loader": {
        preProcessor: "less",
        patterns: [
          // 这个是加上自己的路径,不能使用(如下:alias)中配置的别名路径 需要解析的less文件
          path.resolve(__dirname, "./src/assets/css/variables.less"),
        ],
      },
    },
   
})

3.点击不同的主题颜色,调用方法改变原来的less变量值,直接吧主题模块代码

<template>
  <div class="theme-content">
      <div class="broadside" >
        <div v-for="(item ,index) in broadsideList" >
          <el-tooltip class="item" effect="dark" :content="item.text" placement="top">
            <div @click="handelBroadside(index,item)" :class="item.class+'-'+item.type"  style="margin-left:10px" >
              <div class="left"></div>
              <div class="rigth">
                <div class="rigth-top"></div>
                <div class="rigth-bottom">
                  <i class="el-icon-check" v-if="item.isshow"></i>
                </div>
              </div>
            </div>
            </el-tooltip>
          </div>
      </div>
      <div class="topbar">
        <!-- 第二行 -->
        <div  v-for="(item ,index) in TopBarList">
          <el-tooltip class="item" effect="dark" :content="item.text" placement="top">
            <div @click="handelTopBar(index,item)" :class="item.class+'-'+item.type" style="margin-left:10px">
              <div class="left"></div>
              <div class="rigth">
                <div class="rigth-top"></div>
                <div class="rigth-bottom">
                  <i class="el-icon-check" v-if="item.isshow"></i>
                </div>
              </div>
            </div>
          </el-tooltip>
        </div>

      </div>
      <!-- 第三行 -->
      <div class="colordisc">
         <div v-for="(item,index) in colordiscList">
          <el-tooltip class="item" effect="dark" :content="item.text" placement="top">
              <div :style="{'background':item.color}" class="disc" @click="handelcolordisc(index,item)">
                <i class="el-icon-check" v-if="item.isshow"></i>
              </div>
          </el-tooltip>
         </div>
      </div>
  </div>
</template>
<script>
import { setTheme } from "@/assets/js/theme";
import Vue from 'vue'
   export default{
    data(){
      return{
        broadsideList:[
          {
            class:'broadside',
            text:'暗色側邊欄',
            type:'left',
            isshow:true,
            status:'default',//进入默认选中的查找数据
          },
          {
            class:'broadside',
            text:'亮色側邊欄',
            type:'rigth',
            isshow:false,
            status:'dark',//进入默认选中的查找数据
          },
        ],
        TopBarList:[
          {
            class:'topbar',
            text:'亮色頂欄',
            type:'white', 
            isshow:true,
            status:'headerdefault',//进入默认选中的查找数据
          },
          {
            class:'topbar',
            text:'暗色頂欄',
            type:'black',
            isshow:false,
            status:'headerdedark',//进入默认选中的查找数据
          },{
            class:'topbar',
            text:'主色頂欄',
            type:'theme',
            isshow:false,
            status:'headerthreme',//进入默认选中的查找数据
          }
        ],
        colordiscList:[
          {
            color:'#1890ff',//进入默认选中的查找数据
            text:'拂曉藍',
            isshow:true,
          },
          {
            color:'#5f80c7',//进入默认选中的查找数据
            text:'薄暮',
            isshow:false,
          },
          {
            color:'#faad14',//进入默认选中的查找数据
            text:'日暮',
            isshow:false,
          },
          {
            color:'#f5686f',//进入默认选中的查找数据
            text:'火山',
            isshow:false,
          },
          {
            color:'#9266f9',//进入默认选中的查找数据
            text:'醬紫',
            isshow:false,
          },
          {
            color:'#2bccce',//进入默认选中的查找数据
            text:'明青',
            isshow:false,
          },
          {
            color:'#33cc99',//进入默认选中的查找数据
            text:'極光綠',
            isshow:false,
          },
          {
            color:'#32a2d4',//进入默认选中的查找数据
            text:'極客藍',
            isshow:false,
          },
        ],
        headerthreme:'',
        clickheader:'',//点击的是哪个类型
      }
    },
    mounted(){
      //默认选中
      if(sessionStorage.getItem('threme-nav')){
        this.broadsideList.filter(function(item){
          if(item.status !== sessionStorage.getItem('threme-nav'))
          {
            item.isshow = false
          }else{
            item.isshow = true
          }
        })
      }
      if(sessionStorage.getItem('threme-header')){
        this.TopBarList.filter(function(item){
          if(item.status !== sessionStorage.getItem('threme-header'))
          {
            item.isshow = false
          }else{
            item.isshow = true
          }
        })
      }
      if(sessionStorage.getItem('threme-color')){
        this.colordiscList.filter(function(item){
          if(item.color !== sessionStorage.getItem('threme-color'))
          {
            item.isshow = false
          }else{
            item.isshow = true
          }
        })
      }
    },
    methods:{
      handelBroadside(index,item){
        this.broadsideList.filter(i=> { if(i.isshow === true){
           i.isshow = false
           item.isshow = true
        }})
        switch (index) {
          case 0:
            setTheme("default")
            sessionStorage.setItem('threme-nav','default')
            break;
          case 1:
            setTheme("dark")
            sessionStorage.setItem('threme-nav','dark')
            break;
        }
      },
      handelTopBar(index,item){
        this.TopBarList.filter(i=> { if(i.isshow === true){
           i.isshow = false
           item.isshow = true
        }}) 
        switch (index) {
          case 0:
              setTheme("headerdefault")
              sessionStorage.setItem('threme-header','headerdefault')
            break;
          case 1:
              setTheme("headerdedark")
              sessionStorage.setItem('threme-header','headerdedark')
            break;
          case 2:
              setTheme("headerthreme")
              sessionStorage.setItem('threme-header','headerthreme')
            break;
        }
      },
      handelcolordisc(index,item){
        this.colordiscList.filter(i=> { if(i.isshow === true){
           i.isshow = false
           item.isshow = true
        }}) 
        sessionStorage.setItem('threme-color',item.color)
        if(sessionStorage.getItem('threme-header') === 'headerthreme'){
          setTheme("headerthreme")
        }
        Vue.prototype.bus.$emit('color',item.color)
      },
    }
   }
</script>
<style lang="less" scoped>
 .theme-content{
     width: 100%;
     height: 400px;
     
     .broadside,.topbar{
       width: 100%;
       margin: auto;
       height: 80px;
       display: flex;
       .broadside-left,.broadside-rigth,.topbar-white,.topbar-black,.topbar-theme{
          width: 70px;
          height: 50px;
          overflow: hidden;
          border-radius: 5px;
          display: flex;
          flex-direction: row;
          box-shadow: 1px 1px  5px #e4e4e4;
          .left{
            width: 30%;
            height: 100%;
            background: #001529;
          }
          .rigth{
            width: 70%;
            height: 100%;
            background: cadetblue;
            .rigth-top{
              width: 100%;
              height: 20%;
            }
            .rigth-top{
              width: 100%;
              height: 20%;
              background: #ffffff;
            }
            .rigth-bottom{
              width: 100%;
              height: 80%;
              background: #f0f2f5;
            }
          }
       }
       //左侧栏深色 end
      .broadside-rigth{
          .left{
            width: 30%;
            height: 100%;
            background: #ffffff;
          }
          .rigth{
            width: 70%;
            height: 100%;
            background: cadetblue;
            .rigth-top{
              width: 100%;
              height: 20%;
            }
            .rigth-top{
              width: 100%;
              height: 20%;
              background: #ffffff;
            }
            .rigth-bottom{
              width: 100%;
              height: 80%;
              background: #f0f2f5;
            }
          }
       }
       //左侧栏白色 end
     }
 }
 .rigth-bottom{
   color: #63b6dc;
   display: flex;
   justify-content: center;
   align-items: center;
   font-size: 20px;
 }
//  第二行第一个
.topbar-white{
  .left{
      background: #ffffff !important;
    }
}
//  第二行第二个
.topbar-black{
  .left{
      background: #ffffff !important;
    }
  .rigth-top{
      width: 100%;
      height: 20%;
      background: black !important;
    }
}
//  第二行第三个
.topbar-theme{
  .left{
      background: #ffffff !important;
    }
  .rigth-top{
      width: 100%;
      height: 20%;
      background: @contentbackground !important;
    }
}

// 色盘
.colordisc{
  width: 100%;
  height: 30px;
  display: flex;
  justify-content: space-around;
  .disc{
    width: 20px;
    height: 20px;
    border-radius: 3px;
    line-height: 20px;
    text-align: center;
    .el-icon-check{
      color: white;
      font-size: 13px;
    }
  }
}

</style>

4.主题组件调用的方法 

//默认的对象数据
import { themes } from "./model";
import Vue from 'vue'

const changeStyle = (obj) => {
  console.log('obj',obj);
  for (let key in obj) {
    //重新赋值自己之前定义的less变量值
    document.getElementsByTagName("body")[0].style.setProperty(`--${key}`, obj[key]);
  }
  console.log();
};

//切换主题颜色方法
const changeTheme = (data) => {
  console.log('主题颜色',data);
  for (let key in data) {
    //重新赋值自己之前定义的less变量值
    document.getElementsByTagName("body")[0].style.setProperty(`--${key}`, data[key]);
  }
  Vue.prototype.bus.$on('color',val=>{
    let data = {}
    console.log('val',val);
    switch (val) {
      case '#1890ff':
        data.contentbackground = '#1890ff'
        data.contenthouverbackground = '#40a9ff'
        data.buttonhouverbackground = '#e6f7ff'//透明的按钮移入背景
        changeTheme(data)
        break;
      case '#5f80c7':
        data.contentbackground = '#5f80c7'
        data.contenthouverbackground = '#87a2d4'
        data.buttonhouverbackground = '#f0f7ff'//透明的按钮移入背景
        changeTheme(data)
        break;
      case '#faad14':
        data.contentbackground = '#faad14'
        data.contenthouverbackground = '#ffc53d'
        data.buttonhouverbackground = '#fffbe6'//透明的按钮移入背景
        changeTheme(data)
        break;
      case '#f5686f':
        data.contentbackground = '#f5686f'
        data.contenthouverbackground = '#ff9496'
        data.buttonhouverbackground = '#fff1f0'//透明的按钮移入背景
        changeTheme(data)
        break;
      case '#9266f9':
        data.contentbackground = '#9266f9'
        data.contenthouverbackground = '#b691ff'
        data.buttonhouverbackground = '#f7f0ff'//透明的按钮移入背景
        changeTheme(data)
        break;
      case '#2bccce':
        data.contentbackground = '#2bccce'
        data.contenthouverbackground = '#51dbd9'
        data.buttonhouverbackground = '#f0fffd'//透明的按钮移入背景
        changeTheme(data)
        break;
      case '#33cc99':
        data.contentbackground = '#33cc99'
        data.contenthouverbackground = '#59d9aa'
        data.buttonhouverbackground = '#f0fff7'//透明的按钮移入背景
        changeTheme(data)
        break;
      case '#32a2d4':
        data.contentbackground = '#32a2d4'
        data.contenthouverbackground = '#5abae0'
        data.buttonhouverbackground = '#f0fdff'//透明的按钮移入背景
        changeTheme(data)
        break;
    }
  })
}

//改变主题的方法
export const setTheme = (themeName) => {
  let themeConfig = themes[themeName];
  //判断点击的是不是 header头部主题类型样式
  if(themeName === 'headerthreme'){
    themeConfig.tabbackground = sessionStorage.getItem('threme-color')
  }
  
  //themeName 传递的是默认值 还是其他值 就是 model.js 中的 default 或者 dark
  sessionStorage.setItem("theme", themeName); // 保存主题到本地,下次进入使用该主题
  // 如果有主题名称,那么则采用我们定义的主题 
  //判断传递过来的 themeName 是否存在,如果没存在 themes[themeName]获取不到你想要的数据 就会走else
  if (themeConfig) {
    sessionStorage.setItem("themeConfig",JSON.stringify(themeConfig)); // 保存主题色到本地
    changeStyle(themeConfig); // 改变样式
  } else {
    changeStyle(themeConfig);
  }
};

调用方法更改less变量的值,然后把less变量给对应需要改变颜色的css中就行啦

附上截图

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐