这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战
深色模式对于经常大部分人并不陌生,大多数的 APP 和 web 网页都已经支持了深色模式。深色模式通过调整整体颜色和对比度,从而降低白点值和屏幕亮度,保护用户视力,是一个网站用户体验的评判标准。 如何手动的实现网站的深色/浅色模式,而不使用第三方的插件支持,掌握几个核心要点即可。
- 准备深色/浅色 CSS 样式
- 监听系统模式切换
- 本地化存储当前模式
- 手动切换主题的实现
样式准备
这里采用的是两份样式文件,分别为ThemeLight.less和ThemeDark.less,并完全引入。具体为控制 body 标签的样式类名,实现切换至对应的样式文件。
document.querySelector("html").setAttribute("class", `${theme}-mode`);
核心实现
新建theme.js作为模式控制相关的核心,设定两个基础方法,set和get,用于设置和获取当前的主题模式。
set方法主要是切换 body 标签的样式,从而实现整体的视觉切换,同时将切换后的主题存到浏览器缓存,进而在用户刷新或者下一次进入的时候,可以保持上一次切换的主题模式。
get会优先从本地存储获取之前设置的模式,如果不存在则调用set方法设置默认主题。
具体实现如下:
export const useTheme = () => {
const themeMode = {};
/**
* 设置主题模式
* @param {String} theme 主题
* @return {String} 主题
*/
themeMode.set = (theme = "light") => {
document.querySelector("html").setAttribute("class", `${theme}-mode`);
window.localStorage.setItem("theme", theme);
return theme;
}
/**
* 获取当前的主题模式,初始化为 light
* @return {String} 主题
*/
themeMode.get = () => {
const currentTheme = window.localStorage.getItem("theme");
return currentTheme ? currentTheme : themeMode.set("light");
}
return {
themeMode
}
}
手动触发
这一块是放在主题切换按钮组件中的,节选了一部分,引入useTheme后即可调用set方法去手动设置主题。
const { themeMode } = useTheme();
// 手动触发主题切换
const setCurrentThemeMode = () => {
const val = props.themeMode === "light" ? "dark" : "light";
const setThemeMode = themeMode.set(val);
emit("change", setThemeMode);
};
系统监听
这里用到的是 window 的matchMediaAPI,具体实现如下:
const { themeMode } = useTheme();
// 监听系统主题变化
let listeners = {
dark: (mediaQueryList) => {
if (mediaQueryList.matches) {
const setThemeMode = themeMode.set("dark");
emit("change", setThemeMode);
}
},
light: (mediaQueryList) => {
if (mediaQueryList.matches) {
const setThemeMode = themeMode.set("light");
emit("change", setThemeMode);
}
},
};
window
.matchMedia("(prefers-color-scheme: dark)")
.addListener(listeners.dark);
window
.matchMedia("(prefers-color-scheme: light)")
.addListener(listeners.light);