前端使用tailwindcss 快速实现主题切换方案

3,675 阅读3分钟

我正在参加「掘金·启航计划」

使用Tailwind CSS在黑暗模式下为你的网站设计样式。

现在,黑暗模式是许多操作系统的第一流功能,为你的网站设计一个黑暗版本以配合默认设计,变得越来越普遍。

为了使这一点尽可能简单,Tailwind包括一个暗色变体,让你在启用暗色模式时以不同的方式设计你的网站:

大家可以看一下,这是vue.js的官网切换主题功能,两个主题(白天/黑夜),通过开关切换换肤。官网是是更换主题后永久更换,刷新后主题也是更换后的。我们可以通过后台存储,将主题类型存储起来,也可以通过浏览器存储,短暂的存储主题类型,以达到主题更换的需求。 在这里插入图片描述 在这里插入图片描述 根据这个思路我想在我原有的项目上增加一个这个功能,这样项目看起来比较高大上。话不多少,直接开干。

前提

因为我当前的项目是一个前台项目,但是呢 我又不想写css,只能使用tailwindcss 进行样式调整,我是用的技术栈是:vue3+pinia+ts

 "pinia": "^2.0.33",
 // 持久化
 "pinia-plugin-persistedstate": "^3.1.0",
"tailwindcss": "^3.2.7"
安装 Tailwind CSS: npm install tailwindcss --save-dev 或 yarn add tailwindcss。

开始使用之前我们需要搞清楚步骤:

  1. 监听主题切换
  2. 根据行为保存当前需要展示的主题 pinia中
  3. 根据pinia 中保存的当前主题 修改html的class

搞清楚之后 开始整活:

1. 监听主题切换

项目要是有看不懂的css 可以ps回头我会单独讲解。需要理解的我会给注释。

<template>
<div class="w-[140px] overflow-hidden">
     <div
         v-for="item in themeArr"
         :key="item.id"
         @click="onItemClick(item)"
         class="flex items-center p-1 cursor-pointer rounded
          hover:bg-zinc-100/60 dark:hover:bg-zinc-800"
     >
         <m-svg-icon
             :name="item.icon"
             class="w-1.5 h-1.5 mr-1"
             fillClass="fill-zinc-900 dark:fill-zinc-300"
         ></m-svg-icon>
         <span class="text-zinc-900 dark:text-zinc-300 text-sm">{{ item.name }}</span>
     </div>
 </div>
</template>
<script setup>
// 下面的文件将会展示pinia 中的写法
import { storeToRefs } from "pinia"
import appStore from "@/store"
import { computed } from "vue"
const useThemeTypeStore = storeToRefs(appStore.useThemeTypeStore)

// 定义当前主题列表
const themeArr = [
    {
        id: 0,
        type: 'light',
        icon: "theme-light",
        name: "极简白",
    },
    {
        id: 1,
        type: 'dark',
        icon: "theme-dark",
        name: "极夜黑",
    },
    {
        id: 2,
        type: 'system',
        icon: "theme-system",
        name: "跟随系统",
    },
]

const onItemClick = (item) => {
    appStore.useThemeTypeStore.changeThemeType(item.type)
}
cons
</script>

2. 根据行为保存当前需要展示的主题 pinia中theme.js

改js只是提供持久化和 选择主题样式,大家可以自己定义相关js。

import { defineStore } from "pinia"
import { ref } from "vue"
const useThemeTypeStore = defineStore("themeType", () => {
    const themeType = ref('light')
    const changeThemeType = (newTheme: any) => {
        themeType.value = newTheme
    }
    return { themeType, changeThemeType }
},{
	// 持久化
    persist: [
        {
            // 存储到sessionStorage
            paths: ["themeType"],
            storage: sessionStorage,
            key:'themeType'
        }
    ],
})
export default useThemeTypeStore

utils/theme.ts

import appStore from "@/store"
import { watch } from "vue"

// 系统监听变量
let matchMedia: any = ""
const watchSystemThemeChange = () => {
    // 仅需一次初始化
    if (matchMedia) return
   // Window 的 matchMedia() 方法返回一个新的 MediaQueryList 对象,表示指定的媒体查询 (en-US)字符串解析后的结果。返回的 MediaQueryList 可被用于判定 Document 是否匹配媒体查询,或者监控一个 document 来判定它匹配了或者停止匹配了此媒体查询。
    matchMedia = window.matchMedia("(prefers-color-scheme: dark)")
    matchMedia.onchange = () => {
        changeTheme('system')
    }
}
/**
 * 变更主题
 * @param theme
 */
const changeTheme = (theme: any) => {
    let themeClassName = ""
    switch (theme) {
        case 'light':
            themeClassName = "light"
            break
        case 'dark':
            themeClassName = "dark"
            break
        case 'system':
            // 调用方法监听系统主题变化
            watchSystemThemeChange()
            themeClassName = matchMedia.matches ? "dark" : "light"
            break
    }
    // 修改 html中class
    const html = document.querySelector("html")
    if (html) {
        html.className = themeClassName
    }
}
// 监听pinia 里面定义的 变量
export const useTheme = () => {
    watch(
        () => appStore.useThemeTypeStore.themeType,
        val => {
            changeTheme(val)
        },
        {
            immediate: true,
        }
    )
}

3. 根据pinia 中保存的当前主题 修改html的class

代码详解: 现在,只要HTML树中较早出现dark:{class}类,它们就会被应用,而不是根据prefers-color-scheme来应用。

tailwindcss 内置的 Dark Mode 由两部分组成:

  • dark 修饰符,用于指定暗黑模式下的样式
  • darkMode 配置,指定暗黑模式的应用标识 使用 dark 修饰符指定样式
<div class="bg-white dark:bg-slate-800 rounded-lg px-6 py-8 ring-1 ring-slate-900/5 shadow-xl">
  <div>
    <span class="inline-flex items-center justify-center p-2 bg-indigo-500 rounded-md shadow-lg">
      <svg class="h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"><!-- ... --></svg>
    </span>
  </div>
  <h3 class="text-slate-900 dark:text-white mt-5 text-base font-medium tracking-tight">Writes Upside-Down</h3>
  <p class="text-slate-500 dark:text-slate-400 mt-2 text-sm">
    The Zero Gravity Pen can be used to write in any orientation, including upside-down. It even works in outer space.
  </p>
</div>

tailwindcss 通过 extractor 提取 html 和 js 中的 class,变体 class .dark:bg-slate-800 作为独立项被提出。 默认情况下, tailwindcss 通过媒体查询自动跟随系统切换暗黑模式。也可以设置 darkMode 改用类策略,手动切换暗黑模式。

需要注意的是 tailwindcss 支持颜色透明度修改器,也就是用 bg-slate-700/50 这样的写法给背景加透明度 background-color: rgb(55 65 81 / 0.5) 。因此色值定义中需要保留 <alpha-value> 占位符供 tailwindcss 实现透明度修改器,同时把 CSS 变量赋值为 rgb 或 hsl 的组成值即可。

在这里插入图片描述

在这里插入图片描述