目录
背景
用Taro开发的微信小程序,需求是页面的UI主题想要跟随手机系统的主题适配,实现亮/暗模式。
实现方案
方案一:CSS 变量 + prefers-color-scheme 媒体查询
什么是 prefers-color-scheme?
prefers-color-scheme 是一个 CSS 媒体特性,用于检测用户系统是否设置为亮色(light)或暗色(dark)模式。我们可以在 @media (prefers-color-scheme: dark) 和 @media (prefers-color-scheme: light) 中定义不同的 CSS 变量,并在编写 CSS 样式时使用这些变量,这样在系统主题变化时,页面的样式也会随之变化。
代码示例
在 theme.scss 文件中,可以通过以下方式来定义亮色和暗色主题的样式:
css
// 默认为亮主题
:root,
page {
// 主题配色
--theme: #fff;
--color: #222326;
--button-background-primary: var(--color);
--button-content-primary: var(--theme);
}
// 暗黑主题
@media (prefers-color-scheme: dark) {
:root,
page {
// 主题配色
--theme: #000;
--color: #fff;
--button-background-primary: var(--color);
--button-content-primary: var(--theme);
}
}
然后在使用 CSS 变量时,可以这样引用:
css
.button {
background: var(--button-background-primary);
color: var(--button-content-primary);
}
.icon {
background: var(--download-icon);
background-size: 100%;
width: 14px;
height: 14px;
}
方案二:通过 JavaScript 监听系统主题切换
除了使用 CSS 媒体查询之外,我们还可以通过 JavaScript 监听系统的主题切换,动态更新应用的样式。
- 声明启用 darkmode 支持
首先在 app.json 中声明启用 darkmode:
javascript
{
"darkmode": true
}
- 监听主题变化
接下来可以使用 wx.getSystemInfo 或 wx.getSystemInfoSync 获取当前主题状态,并通过 wx.onThemeChange 监听主题变化。例如:
javascript
getSystemInfo() {
const systemInfo = getSystemInfoSync();
console.log('🚀🚀🚀---systemInfo', systemInfo);
set({ systemInfo });
},
changeThemeListener() {
const listener = (res) => {
if (process.env.TARO_ENV === 'h5') {
res.theme = res.theme === 'light' ? 'dark' : 'light';
}
set(s => {
s.systemInfo.theme = res.theme;
});
};
Taro.onThemeChange(listener);
},
- 使用 useThemeIcon 动态切换图标
获取初始化主题状态并监听主题切换
上面的代码示例展示了如何获取系统信息并设置监听器以响应主题的变化。
封装一个 useThemeIcon 钩子
javascript
import { useAppInfoStore } from '@/store';
import { lightIconMap, darkIconMap } from './themeIcon';
export const useThemeIcon = () => {
const { theme = 'light' } = useAppInfoStore(s => s.systemInfo);
if (theme === 'dark') {
return darkIconMap;
}
return lightIconMap;
};
配置两套主题图标
javascript
import darkDeleteIcon from '@/icons/dark/delete-icon.svg';
import darkDownloadIcon from '@/icons/dark/download-icon.svg';
import lightDeleteIcon from '@/icons/light/delete-icon.svg';
import lightDownloadIcon from '@/icons/light/download-icon.svg';
// 暗黑主题使用图标
export const darkIconMap = {
'delete-icon': darkDeleteIcon,
'download-icon': darkDownloadIcon,
};
// 亮主题使用图标
export const lightIconMap = {
'delete-icon': lightDeleteIcon,
'download-icon': lightDownloadIcon,
};
使用 useThemeIcon
javascript
const themeIcon = useThemeIcon();
<Image className={styles.buttonIcon} src={themeIcon['delete-icon']} />
通过这样的方式,我们可以根据系统主题来动态切换应用中的图标,使用户在不同主题下都有一致且友好的体验。