js实现跟随系统主题切换

我们知道亮色暗色主题功能, 主要是给html元素加了一个自定义属性, 不同的自定义属性对应不同的css变量, 根据我们的选择不同, 去渲染不同的样式。我们在暗色亮色切换的基础上, 加一个跟随系统切换

首先, 在做这种主题切换功能的时候, 方案其实是有很多的, 比如css变量的方案, SASS方案, 传统方案等等, 今天, 我们基于css变量的方案, 实现一下主题切换

需要我们另起一个theme.css文件, 定义两个css变量

/* 定义暗色主题 */
html[data-theme="dark"] {
  --text-primary: #fff;
  --background-primary: #1b1b1b;
}

/* 默认亮色主题 */
:root {
  --text-primary: #1b1b1b;
  --background-primary: #fff;
}

在main.js中, 将上方定义的css变量进行导入

import './style/theme.css'

现在, 我们准备一个组件, 用于我们的主题切换, 将我们的css变量用于我们的样式中

background: var(--background-primary);
color: var(--text-primary);

接下来, 我们来写一个下拉框, 用于主题的选择

<div>
  <select v-model="theme">
    <!-- <option value="os">跟随系统</option> -->
    <option value="light">亮色</option>
    <option value="dark">暗色</option>
  </select>
</div>

定义一个响应式数据, 优先去本地取数据, 本地没有就显示亮色

const theme = ref(localStorage.getItem("theme") || "light");

如果, 我们选择了其他选项, 应该触发监听, 去更改存储和自定义属性

watchEffect(() => {
  // 存储本地
  localStorage.setItem("theme", theme.value);
  document.documentElement.dataset.theme = theme.value;
});

这样, 我们亮色和暗色的切换就完成了

接下来, 需要我们熟悉一个API, 用于我们跟随主题进行切换

Window.matchMedia() - Web API 接口参考 | MDN

该方法, 会返回一个新的 MediaQueryList 对象,表示指定的媒体查询 (en-US)字符串解析后的结果。返回的 MediaQueryList 可被用于判定 Document 是否匹配媒体查询,或者监控一个 document 来判定它匹配了或者停止匹配了此媒体查询。

我们来写一下, 匹配当前主题颜色是不是暗色, 通过该方法返回的结果, 我们可以拿到布尔类型true或者false

const match = matchMedia('(prefers-color-scheme: dark)');
console.log(match);

如果matches, 返回false, 说明当前主题是亮色

我们如果选择了深色, 就会返回true

这样, 就可以帮助我们跟随系统进行切换了

if(theme.value === 'os') {
    document.documentElement.dataset.theme = match.matches? 'dark':'light'
}

但是, 这样写依然存在一个问题, 就是我们去更改主题颜色的时候, 页面更改不了, 所以, 我们需要给上面方法返回值注册一个change事件

const match = matchMedia('(prefers-color-scheme: dark)');
console.log(match);
match.addEventListener('change', () => {
  document.documentElement.dataset.theme = match.matches? 'dark': 'light'
})

这样, 再次更改电脑主题颜色, 页面也会发生变化

最后, 我们再优化一下代码, 将相同的代码, 提取出来封装成一个函数

<script setup>
import { ref, watchEffect } from "vue";
const theme = ref(localStorage.getItem("theme") || "light");
const match = matchMedia('(prefers-color-scheme: dark)');
const changeFun = () => {
  document.documentElement.dataset.theme = match.matches? 'dark': 'light'
}
// 用于更改主题颜色
watchEffect(() => {
  if(theme.value == 'os') {
    changeFun();
    match.addEventListener('change', changeFun);
  }
  // 存储本地
  localStorage.setItem("theme", theme.value);
  document.documentElement.dataset.theme = theme.value;
});
</script>

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值