场景说明:管理员可在管理后台配置自定义颜色为主题色,小程序无需打包进行切换
1. 介绍一下CSS自定义属性(变量):
css变量的基本使用方式:
// css变量定义
:root {
--background-color:#fff;
--text-color:#333;
}
// var方法第一个参数是变量名,第二个为备用参数,在第一个变量失效的时候生效,
// 其他复杂使用方式可以查看文档
h1 {
background-color: var(--background-color,'#fff');
color: var(--text-color,#333);
}
注意,规则集所指定的选择器定义了自定义属性的可见作用域。通常的最佳实践是定义在根伪类 :root 下,这样就可以在 HTML 文档的任何地方访问到它了。
2. 这里以普通HTML为例,实现主题色切换
通过给html标签动态设置style实现主题切换。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
:root {
--background-color: #fff;
--text-color: #333;
}
h1 {
background-color: var(--background-color,'#fff');
color: var(--text-color,#333);
}
</style>
</head>
<body>
<div>
<h1>Hello World</h1>
<ul>
<li data-color="red">主题红色</li>
<li data-color="blue">主题蓝色</li>
</ul>
</div>
<script>
const ul = document.querySelector('ul');
ul.onclick = (event) => {
const target = event.target;
if (target.tagName.toLowerCase() === 'li') {
document.documentElement.style.setProperty('--background-color', target.dataset.color);
document.documentElement.style.setProperty('--text-color', '#fff');
}
}
</script>
</body>
</html>
3. 小程序实现:
思路和普通的html一样,给根节点style设置变量,但小程序存在一个问题无法动态给Page节点设置style。为了解决这个问题,我们只能自定义第一个页面容器。首次加载小程序的时候,从服务器获取配置,通过redux进行theme更新,实现主题色的动态切换。
4. 用taro的redux模版实现demo
用taro init
初始化一个redux模版,在store里添加一个getConfig方法获取主题数据
// 修改路径store/index文件
const getConfig = async(dispatch) => {
const getTheme = async() => {
return new Promise((resolve) => {
// 模拟数据获取,真实场景使用真实api获取数据
setTimeout(() => {
resolve({
'backgroundColor': 'red',
'textColor': '#fff'
});
},1000);
})
}
const theme = await getTheme();
if (theme) {
dispatch({
type: "SET_THEME",
payload: {
...theme,
}
})
}
}
export default function configStore () {
const store = createStore(rootReducer, enhancer)
// 获取配置
getConfig(store.dispatch);
return store
}
注意:这里还需要修改reducers
为自己需要处理的type,这里就不再赘述。具体可以查看源码。
有了主题数据,我们还需要实现一个页面容器Page组件,作为css变量设置的节点,以下组建Page/index.tsx
import { View } from '@tarojs/components';
import { useSelector } from 'react-redux';
import { useMemo } from 'react';
import './index.less';
type Theme = {
backgroundColor: string;
textColor: string;
}
const Page = ({ children }) => {
const theme = useSelector((state: { theme: Theme }) => state.theme);
console.log('主题:', theme)
const styles = useMemo(() => {
if (theme) {
return {
'--background-color': theme.backgroundColor,
'--text-color':theme.textColor
}
}
return null;
}, [theme]);
return (
<View style={styles} className="page">
{children}
</View>
)
}
export default Page;
Page组件的样式:
.page {
width: 100vw;
height: 100vh;
box-sizing: border-box;
overflow: auto;
}
有了Page组建我们在每个页面最外层套上即可。效果如下(视频转换失效,放个图片):