前言
个人比较喜欢方案三,可以写一个from对各个组件的样式做定制化操作,对于vue等框架也比较兼容。
方案一:通过切换css文件实现样式切换
整体代码
<body>
<link type="text/css" rel="stylesheet" href="./css/theme01.css" data-theme="0" title="主题一">
<link type="text/css" rel="alternate stylesheet" href="./css/theme02.css" data-theme="1" title="主题二">
<link type="text/css" rel="alternate stylesheet" href="./css/theme03.css" data-theme="2" title="主题三">
<div id="thenm-btns-box"></div>
</body>
<script>
let thenmBtnsBox = document.getElementById('thenm-btns-box');
let themeCss = document.querySelectorAll('link[data-theme]');
themeCss.forEach((item, index) => {
let btn = document.createElement('div');
btn.style.cssText = `
width: 50px;
height: 50px;
border-radius: 50%;
background-color: azure;
`;
btn.addEventListener('click', function () {
themeCss.forEach((cssItem) => {
cssItem.disabled = Number(cssItem.getAttribute('data-theme')) !== index;
});
});
thenmBtnsBox.appendChild(btn);
});
</script>
实现思路
css文件
把主题相关的css样式放到不通的css文件夹中,通过rel="alternate"进行预加载(浏览器会加载当前文件但不会在文档流中生效,目的是当切换css文件时可以流畅不卡顿),并且title必须有值才能生效。添加data-theme作为标识,当需要切换时方便查找。
<link type="text/css" rel="stylesheet" href="./css/theme01.css" data-theme="0" title="主题一">
<link type="text/css" rel="alternate stylesheet" href="./css/theme02.css" data-theme="1" title="主题二">
<link type="text/css" rel="alternate stylesheet" href="./css/theme03.css" data-theme="2" title="主题三">
切换按钮
随便写有个点击事件就行,我为了自适应主题文件数量就遍历了一下。
获取所有主题文件
遍历生成div按钮并添加点击事件
append到需要放置的盒子中
<div id="thenm-btns-box"></div>
<script>
let thenmBtnsBox = document.getElementById('thenm-btns-box');
let themeCss = document.querySelectorAll('link[data-theme]');
themeCss.forEach((item, index) => {
let btn = document.createElement('div');
btn.style.cssText = `
width: 50px;
height: 50px;
border-radius: 50%;
background-color: azure;
`;
btn.addEventListener('click', function () {
});
thenmBtnsBox.appendChild(btn);
});
</script>
点击事件
点击按钮时索引与css标签中的data-相同时让他的disabled属性为false,当前css文件就作用到文档流中了。index是上面遍历themeCss的索引也就是第几个按钮。
btn.addEventListener('click', function () {
themeCss.forEach((cssItem) => {
cssItem.disabled = Number(cssItem.getAttribute('data-theme')) !== index;
});
});
方案二:插件 - webpack-theme-color-replacer
网上有详细解释我就不多赘述了,放一下文章和demo。
webpack-theme-color-replacer文章
webpack-theme-color-replacer domo
方案三 var()实现变量样式切换
整体代码
<style>
/* 默认样式 */
.title {
font-size: 20px;
margin: 20px 0;
}
.box {
width: 100px;
height: 100px;
background-color: black;
}
/* end */
/* 变量赋值样式 */
:root {
--table-fontColor: #d3a5c2;
--title-color: #d3a5c2;
--box-width: 50px;
--box-height: 50px;
--box-bgColor: #d3a5c2;
}
table th, table td {
color: var(--table-fontColor);
}
.title {
color: var(--title-color);
}
.box{
width: var(--box-width);
height: var(--box-height);
background-color: var(--box-bgColor);
}
/* end */
</style>
<body>
<table border="1">
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
<tr>
<td>January</td>
<td>$100</td>
</tr>
</table>
<div class="title">
标题
</div>
<div class="box"></div>
</body>
<script>
// 需要替换的样式对象(数据可以由后端提供或者用通过定制组件产出)
let theme = {
'--table-fontColor': '#271579',
'--title-color': '#5a17c0',
'--box-width': '500px',
'--box-height': '500px',
'--box-bgColor': '#bc42a5',
};
let bodyStyle = document.getElementsByTagName('body')[0].style;
for (const key in theme) {
bodyStyle.setProperty(key, theme[key]);
};
</script>
实现思路
样式的变量赋值
通过:root(伪类作为全局样式)实现全局变量,再通过var()函数赋值到后期需要动态切换的属性中。
/* 变量赋值样式 */
:root {
--table-fontColor: #d3a5c2;
--title-color: #d3a5c2;
--box-width: 50px;
--box-height: 50px;
--box-bgColor: #d3a5c2;
}
table th, table td {
color: var(--table-fontColor);
}
.title {
color: var(--title-color);
}
.box{
width: var(--box-width);
height: var(--box-height);
background-color: var(--box-bgColor);
}
/* end */
切换变量的值
bodyStyle获取body的样式同时也包含root伪类,通过serProperty修改值。
// 需要替换的样式对象(数据可以由后端提供或者用通过定制组件产出)
let theme = {
'--table-fontColor': '#271579',
'--title-color': '#5a17c0',
'--box-width': '500px',
'--box-height': '500px',
'--box-bgColor': '#bc42a5',
};
let bodyStyle = document.getElementsByTagName('body')[0].style;
for (const key in theme) {
bodyStyle.setProperty(key, theme[key]);
};