基于css变量轻松实现网站的主题切换功能

news2024/11/16 13:22:14

我们经常看到一些网站都有主题切换,例如vue官方文档。那他是怎么实现的呢?

在这里插入图片描述

检查元素,发现点击切换时,html元素会动态的添加和移除一个class:dark,然后页面主题色就变了。仔细想想,这要是放在以前,可能要写两套样式,就像这样:

body {
  background-color: '#fff';
}
body.dark {
  background-color: '#000';
}

这写起来得多麻烦啊,而且难以维护。

好在我们有CSS变量,早在2017年,微软宣布Edge浏览器将支持CSS变量,现在几乎所有的浏览器都已经支持了这个功能。(IE:啊这?)

css变量也是变量,就像js一样,先声明,再读取。

body {
  --text-color: red;
}
.box {
  color: var(--text-color);
}

已经出来很多年了,今天就不详细介绍了,有兴趣的推荐阅读 阮一峰老师的《CSS 变量教程》

今天就用vue3项目来写一个基于css变量实现的主题切换demo。

创建一个vue3项目:

npm create vue@latest

创建一个theme.css文件。

/**
  *默认主题
  */
:root {
  --bg: #fff;
  --text-color: #000;
}
/**
  *添加属性,用来控制暗黑模式时的样式
  */
html[data-theme="dark"] {
  --bg: #000;
  --text-color: #fff;
}

或者像vue文档中一样使用class,如下所示:

:root {
  --bg: #fff;
  --text-color: #000;
}
html.dark {
  --bg: #000;
  --text-color: #fff;
}

但是如果某个页面内无意中野使用到同名dark这个class,可能会造成影响,我这里还是用属性。

main.js中引入一下theme.css

import './assets/theme.css'

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

App.vue style中调用一下变量,并动态改变data-theme的值:

<template>
  <main>
    <p>主题切换demo</p>
    <button @click="change">切换</button>
  </main>
</template>
<script>
  let theme = 'light'
  const change = () => {
    theme = theme === 'light' ? 'dark' : 'light'
    document.documentElement.setAttribute('data-theme', theme)
  }
</script>

<style scoped>
main {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background-color: var(--bg);
  color: var(--text-color);
}
p {
  margin: 20px 0;
}
</style>

看看效果:

在这里插入图片描述

功能基本上已经实现了,再来把这个切换操作封装成一个组件,并全局实时共享主题数据。

创建一个useTheme.js,用来执行设置属性的操作:

import { ref, watchEffect } from 'vue'

// 默认用亮色
const theme = ref('light')

// 每次改变都设置一下
watchEffect(() => {
  document.documentElement.setAttribute('data-theme', theme.value)
})

export default function useTheme() {
  return {
    theme
  }
}

创建一个switch-theme.vue组件,仅仅用来改变theme的值:

<template>
  <el-switch 
    v-model="theme"
    :active-action-icon="Moon"
    :inactive-action-icon="Sunny"
    active-color="#2f2f2f"
    active-value="dark"
    inactive-value="light"
    @change="changeDark"
  ></el-switch>
</template>

<script setup>
  import { Sunny, Moon } from '@element-plus/icons-vue'
  import useTheme from '../hooks/useTheme'
  const { theme } = useTheme()
  const changeDark = (data) => {
    theme.value === data
  }
</script>

改一下App.vue文件,引入并使用ThemeSwitch组件和useTheme Hook:

<template>
  <main>
    <p>主题切换demo</p>
    <ThemeSwitch></ThemeSwitch>
    <p>当前主题:{{theme}}</p>
  </main>
</template>

<script setup>
  import ThemeSwitch from './components/theme-switch.vue'
  import useTheme from './hooks/useTheme'

  const { theme } = useTheme()
</script>

<style scoped>
main {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background-color: var(--bg);
  color: var(--text-color);
}
p {
  margin: 20px 0;
}
</style>

再看看效果:

在这里插入图片描述

现在由一个专门的组件用来控制切换主题,并且不同组件内也都能共享theme变量了。

最后再优化一下,目前默认是亮色,切换到暗色以后再刷新页面,又会回到亮色,可以把theme变量存到localstorage

修改一下useTheme.js:

import { ref, watchEffect } from 'vue'

// 从取缓存中取值,给个默认值。
const theme = ref(localStorage.getItem('theme') || 'light')

// 每次改变都设置一下属性,并存到缓存中。
watchEffect(() => {
  document.documentElement.setAttribute('data-theme', theme.value)
  localStorage.setItem('theme', theme.value)
})

export default function useTheme() {
  return {
    theme
  }
}

全部代码见Github

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1047760.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenAI宣布ChatGPT支持互联网浏览;GPT-4V(ision)介绍

&#x1f989; AI新闻 &#x1f680; OpenAI宣布ChatGPT支持互联网浏览 摘要&#xff1a;OpenAI宣布ChatGPT现在可以浏览互联网&#xff0c;由微软必应提供支持&#xff0c;并提供直接来源链接。这一功能对于需要最新信息的任务特别有用&#xff0c;如技术研究、购买商品或选…

项目管理:项目经理一定要避开这四大误区

项目经理要保质保量按时达成项目目标&#xff0c;需要关注项目的方方面面&#xff0c;要具有很强的沟通协调能力和目标意识。但是项目经理也不免不了失误&#xff0c;管理中的这四大误区&#xff0c;你经历过几个&#xff1f; 误区一&#xff1a;做不该做的事 你是否遇到这种…

剑指offer32Ⅰ:从上到下打印二叉树

题目描述 从上到下按层打印二叉树&#xff0c;同一层的节点按从左到右的顺序打印&#xff0c;每一层打印到一行。 例如: 给定二叉树: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回其层次遍历结果&#xff1a; [3,9,20,15,7] 提示&#xff1a; 节…

LeetCode每日一题:2251. 花期内花的数目(2023.9.28 C++)

目录 2251. 花期内花的数目 题目描述&#xff1a; 实现代码与解析&#xff1a; 离散化差分 原理思路&#xff1a; 2251. 花期内花的数目 题目描述&#xff1a; 给你一个下标从 0 开始的二维整数数组 flowers &#xff0c;其中 flowers[i] [starti, endi] 表示第 i 朵花的…

pytorch函数reshape()和view()的区别及张量连续性

目录 1.view() 2.reshape() 3.引用和副本&#xff1a; 4.区别 5.总结 在PyTorch中&#xff0c;tensor可以使用两种方法来改变其形状&#xff1a;view()和reshape()。这两种方法的作用是相当类似的&#xff0c;但是它们在实现上有一些细微的区别。 1.view() view()方法是…

【C++】C++继承——切片、隐藏、默认成员函数、菱形

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C学习 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【C】STL…

行为型设计模式——责任链模式

摘要 责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象。 一、责任链模式意图 职责链模式&#xff08;Chain Of Responsibility&#xff09; 是一种行为设…

Uniapp实现APP云打包

一. 基础配置 二. APP图标配置 1. 点击浏览 选取图标(注&#xff1a;图片格式为png) 2. 点击自动生成所有图标并替换 三. 点击发行 并选择云打包 四. 去开发者中心获取证书 我这里是已经获取好的&#xff0c;没有获取的话&#xff0c;按照提示获取即可&#xff0c;非常简单…

axios和vite在本地开发环境配置代理的两种方式,五分钟学会

如果你使用vue或者react开发&#xff0c;就得使用axios吧&#xff0c;然后为了解决跨域问题&#xff0c;就得使用vite配置吧&#xff0c;那怎么协调配置它们两个才能正常工作呢&#xff1f; 正常的流程&#xff1a;配置axios的baseURL&#xff0c;然后配置vite的proxy 第一种…

【论文阅读】Directional Connectivity-based Segmentation of Medical Images

目录 摘要介绍方法效果结论 论文&#xff1a;Directional Connectivity-based Segmentation of Medical Images 代码&#xff1a;https://github.com/zyun-y/dconnnet 摘要 出发点&#xff1a;生物标志分割中的解剖学一致性对许多医学图像分析任务至关重要。 之前工作的问题&…

Linux 实训4 正则表达式

将实训4 &#xff1a;正则表达式的完成情况提交实验报告。 创建并输入文本文件 a bcd 1 233 abc123 defrt456 123abc 12568teids abcfrt568 "Open Source" is a good mechan1sm to develop programs. apple is my favorite food. Football game is not …

数据结构----结构--非线性结构--树

数据结构----结构–非线性结构–树 一.树&#xff08;Tree&#xff09; 1.树的结构 树是一对多的结构 2.关于树的知识点 1.根节点&#xff1a;树最上面的节点 2.中间节点&#xff1a;树中间的节点 3.叶子节点&#xff1a;树最下面的节点 如下图 4.边&#xff1a;在树中…

弱信号的采样与频谱分析(修订中...)

1.频谱混叠效应 - 波形数据抽样 这是一组经过抽样的数据的频谱&#xff0c;红圈圈出的两条谱线&#xff0c;是我们需要关注的特征谱线。这个信号与右侧的临近信号比较&#xff0c;求频率比值&#xff0c;比值恒定与理论推导相符。再5取1降低采样率后&#xff0c;大致相同的频率…

虹科案例 | 虹科MSR实现易碎艺术品安全运输——开发有效减少冲击和振动的新工艺

【案例】在CTI研究项目中使用带有加速度传感器的虹科MSR165数据记录仪对冲击振动进行风险评估 项目背景&#xff1a; 全球艺术品运输量持续增长。在运输过程中&#xff0c;画作面临着诸多压力和风险&#xff0c;如冲击和振动。在博物馆搬运这些画作、装卸包装箱、卡车在颠簸的…

Android 视频通话分析总结

1、WireShark 解析视频流 1.1 安装插件 下载rtp_h264_extractor.lua文件&#xff0c;放入Wireshark安装目录 下载地址&#xff1a;https://download.csdn.net/download/tjpuzm/88381821 在init.lua中添加如下代码 dofile(DATA_DIR.."rtp_h264_extractor.lua") 重新…

淘宝的数据使用和数字化进阶过程

宝在数字化转型的过程中&#xff0c;数据使用和数字化进阶均经历了几个不同的发展阶段&#xff0c;这些经历对致力于数字化转型的企业有更多借鉴意义。 1 淘宝数据API使用的5个阶段 淘宝的数据使用经历了5个阶段&#xff0c;如图所示&#xff0c;以下分别进行介绍。 1.依靠数…

苹果手机数据恢复软件哪款好用?看到就是赚到!

手机中储存的数据包含了许多重要的照片、视频、文件等&#xff0c;更重要的是这些数据中所承载着的珍贵记忆。但在我们使用手机的过程中&#xff0c;难以避免一些意外&#xff0c;手机中的数据可能会因为误删除、手机故障、手机恢复出厂设置等原因丢失。 这时候&#xff0c;如…

[chrome devtools]Console面板

点解开发者工具控制台【Console】后&#xff0c;在最右侧找到点击出现如下面板&#xff1a; 【1】是否在控制台显示网络相关的日志信息&#xff0c;比如get请求 【2】刷新或者跳转页面时&#xff0c;原先控制台已显示的日志是否继续保留在控制台上&#xff0c;就是刷新页面控…

批处理数值计算实战,以及打印乘法表

文章目录 计算2的N次方转二进制最大公约数和最小公倍数打印乘法表 计算2的N次方 二进制转换是经常遇到的一个需求&#xff0c;批处理可以非常便捷地完成这个工作。而二进制转化过程中&#xff0c;第一步就是和 2 n 2^n 2n比较大小&#xff0c;所以在实现这个功能之前&#xff…

基于微信小程序的自驾游拼团小程序的设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…