vue中换肤功能有着好几种实现方式,如下:

  1. 利用class 命名空间,同时命名多套主题如:black-theme、light-theme等,按需加载主题类名(简单 - 常用)
  2. 准备多套CSS样式,利用link标签的ref切换(简单 - 按需加载主题,但是管理配置没1方便)
  3. 使用CSS预处理器(如:scss)生成多套主题样式(复杂 - webpack打包处理)
  4. CSS3的变量功能生成多套主题样式(复杂 - 兼容性问题(详见css3))
  5. 动态换肤(复杂-适用性广)

不同的实现方式有着不同的优缺点,我们可以根据需要来进行选择,个人优先推荐1、3、5方案。

实现方式一:利用class 命名空间,引一个文件,多套主题类切换

实现如下:(我使用的是sass预编译器)
第一步:在 assets 文件夹中定义主题的文件theme.scss,其内容如下:
在这里插入图片描述

注意每一套主题中的类命名必须和实际的层级结构一样,且提取出所有需要修改覆盖的类名,并且给其附上相关值
层级结构如:
在这里插入图片描述
这个样式的层级结构会根据vue的组件嵌套层级来决定,相信使用过vue的都应该知道vue中样式的层级情况。
第二步:在main.js中全局引入主题
在这里插入图片描述
第三步:切换主题操作,给app添加主题类
在这里插入图片描述

注意:在提取相关样式类的颜色的时候有可能会忘记将原先的样式类去掉相关的颜色,此时需要给theme.scss主题中的css都加上!important才能够将内容替换掉

优点
1.实现简单,只需要提取出需要改变样式的类名,按照其层级结构进行修改即可。
2所有的主题都是统一在一个文件中管理,方便维护
缺点
1.主题多了就会造成体积变大问题。
2.可能会出现主题样式不能覆盖问题:如:组件内的某些样式使用了!important 等,或者组件内某个插件重写了样式如:引入elmentUI重写table样式等,因此需要注意权限层级问题。
这种方式适用于轻改

实现方式二:准备多套CSS样式,利用link标签的ref切换

实现方式:
第一步:在public/static文件夹中准备好需要引用的主题文件如:
在这里插入图片描述

注意:link引用的文件必须要在public/static中,且结尾只能是.css的文件,scss文件不会被编译

第二步:在app.vue中的mounted生命周期中创建link

 var link = document.createElement('link');
 link.type = 'text/css';
 link.id = "theme";  
 link.rel = 'stylesheet';
 link.href = './static/css/theme-default.css';
 document.getElementsByTagName("head")[0].appendChild(link);

第三步:在需要切换内容的组件中进行逻辑操作如:
在这里插入图片描述

注意:方法要在mouted周期里面

优点
实现简单,只需要写一套css样式代码,然后后续的所有主题都可以根据这套代码进行复制修改即可。与方式一的区别在于一个全部引入进来(方式一),这里则是按照需要引用,因此相对而言css的体积会小好多。
缺点
需要手写多份CSS配色样式; 而且切换样式需要下载CSS的时间,如果样式内容比较多,单个文件体积比较大的时候,可能在切换的时候会出现细微的卡顿。

实现方式三: 使用CSS预处理器(scss)或者CSS3的变量功能生成多套主题样式

参考:https://juejin.im/entry/5adc907e6fb9a07ac6529e4e

实现方式四: 使用CSS3的变量功能生成多套主题样式

第一步:认识css3自定义属性
在需要的作用域中定义变量(在任意的全局css文件或者style中定义即可),如:

//:root作用于全局
:root{
    --theme-color:red; // 这里定义了一个--theme-color变量, 值为black
}
//#app作用于id为app的节点内
#app{
    --theme-back-color: black; // 这里定义了一个--theme-back-color变量,值为black
}

使用方式:1.在css中使用,如:在.title中使用:

.title{
	color: var(--theme-color)
}

使用方式:2.在js中使用,如:

// document.documentElement 代表相关的容器如:#box
//js中获取--theme-color的值
var value = getComputedStyle(document.documentElement).getPropertyValue("--theme-color");
//js中更改--theme-color的值
document.documentElement.style.setProperty("--theme-color","black");
优点:只需一套CSS文件; 换肤不需要延迟等候;对浏览器性能要求低;可自动适配多种主题色;
缺点: 兼容性问题、不支持IE, 2016年前的chrome,safari;

实现方式五: 动态换肤

这是elementUi的一种换肤方式
demo代码:

<html lang="en">
<head>
  <title>js 动态换肤</title>
   <!-- 利用axios 实现异步加载样式-->
  <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>
</head>
<body>
 <h3 class="title">js 动态换肤</h3>
 <script>
   // 1. 主题颜色配置
   var colors = {
     red: {
       themeColor: '#FF0000' 
     },
     blue: {
       themeColor: '#0000FF'
     }
   }

   // 2. 异步获取样式
   var styles = ''
   axios.get('theme.css').then((resp=> {
     const colorMap = {
       '#FF0000': 'themeColor'
     }
     styles = resp.data
     Object.keys(colorMap).forEach(key => {
       const value = colorMap[key]
       styles = styles.replace(new RegExp(key, 'ig'), value)
       console.log(styles)
     })
     writeNewStyle (styles, colors.red)
   }))

   // 3.换色
   // console.log 中输入 writeNewStyle (styles, colors.blue)可以换蓝色主题
   // console.log 中输入 writeNewStyle (styles, colors.blue)可以换红色主题
   function writeNewStyle (originalStyle, colors) {
     let oldEl = document.getElementById('temp-style')
     let cssText = originalStyle

     Object.keys(colors).forEach(key => {
       cssText = cssText.replace(new RegExp(key, 'ig'), colors[key])
     })
     const style = document.createElement('style')
     style.innerText = cssText
     style.id = 'temp-style'

     oldEl ? document.head.replaceChild(style, oldEl) : document.head.appendChild(style)
   }
 </script>
</body>
</html>

参考
Vue 换肤实践:https://juejin.im/entry/5a634dc36fb9a01ca071edba
elementUI及vuetifyjs动态换色实践:https://juejin.im/post/5c1f86b9e51d4570f1452ae2
webpack插件实现自动抽取css中的主题色样式,并一键动态切换主题色(element-ui):https://segmentfault.com/a/1190000016061608
vue-element-admin换肤:https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/theme.html#动态换肤

Logo

前往低代码交流专区

更多推荐