有些web产品运行时,提供切换主题的功能。
方案一:动态切换class
给所有规则添加主题选择器,利用less变量覆盖,通过动态切换class实现动态主题切换。
创建主题变量,不同主题变量名相同,比如有light和dark两种主题。lightVars.less:
@bg-color: white;
@font-color: black;
@primary-color: yellow;
darkVars.less:
@bg-color: black;
@font-color: white;
@primary-color: green;
规则文件中有关颜色的规则要使用上文定义的变量,lightStyle.less:
@import "./lightVars";
.l-base-container {
background: @bg-color;
text-align: center;
}
.h2 {
color: @font-color;
margin: 0;
padding: 0;
}
.btn {
background: @primary-color;
line-height: 32px;
width: 50px;
color: @font-color;
}
定义暗黑主题规则,需要导入规则文件,并给所有规则的选择器添加父类选择器,用黑色主题的变量覆盖浅色主题的变量。darkStyle.less:
.dark {
@import "./lightStyle.less";
@import "./darkVars.less";
}
动态切换class:
class App extends React.Component {
state = {
themeClass: "",
};
render() {
return (
<div className={`${this.state.themeClass} l-theme-container`}>
<div className="l-base-container">
<div className={`h2`}>
<h2
onClick={() =>
this.setState((preState) => {
if (preState.themeClass === "") {
return { themeClass: "dark" };
} else {
return { themeClass: "" };
}
})
}
>
this is title
</h2>
</div>
<button className="btn">确定</button>
</div>
</div>
);
}
}
此种方案,有n种主题,最终css包大小就会增加n倍,对首屏渲染有要求的不适合采用这种方案。
方案二:动态加载css主题样式
生成多种主题的css文件,当切换主题时通过js生成link标签,动态加载相应主题的css。
生成css文件可采用方案一的方式,不同主题采用相应的主题变量文件。
动态加载主题样式:
function handleChangeTheme() {
var ele = document.createElement("link");
ele.rel = "stylesheet";
ele.href = "./b.css";
var headEl = document.getElementsByTagName("head")[0];
var linkEl = headEl.getElementsByTagName("link")[0];
headEl.removeChild(linkEl);
headEl.appendChild(ele);
}
该方案需要多次构建才能生成相应主题的css文件,css文件名还要考虑缓存,部署上麻烦些。
方案三:lessjs解析颜色规则
通过antd-theme-webpack-plugin
抽取样式中有关颜色的规则放到一个color.less文件中,网站引入less.js文件来解析color.less,通过less.modifyVars修改颜色文件中的变量。
安装插件 npm install -D antd-theme-webpack-plugin
webpack配置:
const AntDesignThemePlugin = require('antd-theme-webpack-plugin');
const options = {
antDir: path.join(__dirname, './node_modules/antd'),
stylesDir: path.join(__dirname, './src'),
varFile: path.join(__dirname, './src/styles/variables.less'),
themeVariables: ['@primary-color'],
indexFileName: 'index.html',
generateOnce: false,
lessUrl: "https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js",
publicPath: "",
customColorRegexArray: [], // An array of regex codes to match your custom color variable values so that code can identify that it's a valid color. Make sure your regex does not adds false positives.
}
const themePlugin = new AntDesignThemePlugin(options);
// in config object
plugins: [
themePlugin
]
切换主题代码:
const handleClick = () => {
const vars = {
"@bg-color": "red",
};
window.less.modifyVars(vars);
};
代码:https://github.com/compus135/web-examples/tree/master/src/react/bestPractice/runtimeTheme
参考
- dynamic theme, runtime theme, switch themes live
- 使用 css/less 动态更换主题色(换肤功能)
- https://www.cnblogs.com/leiting/p/11203383.html
- https://github.com/mzohaibqc/antd-theme-webpack-plugin