一、背景
在最近的一个需求中,一个商业产品要在不同APP中需要使用不同的CSS主题,这就涉及到了动态切换CSS主题的方案
二、方案简介
sass+mixin+js设置html的data-theme属性
原理是使用sass配合mixin编程成固定的css,通过js设定不同的主题,使对应的css生效
1. 定义变量
使用sass的map,可以把所涉及到的变量通过配置的方式整理起来,其中第一层是主题名,第二层是css的value,例如bg、info-price
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @use "sass:map";
$themes: ( appA: ( bg: url('https://wos.58cdn.com.cn/cDazYxWcDHJ/picasso/2m9p9qlv__w1500_h520.png') no-repeat 0 0px / 100%, info-price: #FF552E, ), appB: ( bg: url('https://wos.58cdn.com.cn/cDazYxWcDHJ/picasso/muc3req9__w1500_h520.png') no-repeat 0 0px / 100%, info-price: #09D57E, ), appC: ( bg: url('https://wos.58cdn.com.cn/cDazYxWcDHJ/picasso/7re7pg8r__w1500_h520.png') no-repeat 0 0px / 100%, info-price: #FF704F, ), );
|
2. mixin方法的实现
通过mixin实现把css根据不同主题注入页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @use "sass:map";
// 遍历主题数据,把@content中的css注入页面中 @mixin injectCss { @each $theme-name, $theme-map in $themes { //!global 把局部变量强升为全局变量,让下方的setCss方法也可以使用$theme-map $theme-map: $theme-map !global; //判断html的data-theme的属性值 #{}是sass的插值表达式 //& sass嵌套里的父容器标识 @content是混合器插槽,像vue的slot [data-theme="#{$theme-name}"] & { @content; } } }
// 注入css @mixin setCss($css, $variable) { @include injectCss { #{$css}: map-get($theme-map, $variable); } }
|
3. 通过js设置主题
1 2 3 4 5 6 7
| const app = utils.getApp(); const themeMap = { appA: 'appA', appB: 'appB', appC: 'appC', }; window.document.documentElement.setAttribute('data-theme', themeMap[app] || 'appA');
|
4. 在页面中使用mixin
1 2 3 4 5
| @import '@css/m/mini-theme.scss';
.buy-container { @include setCss("background", "bg"); }
|