常用Vue UI框架的主題切換

来源:https://www.cnblogs.com/wdyyy/archive/2022/12/04/vue_darkmode.html
-Advertisement-
Play Games

在如今,很多網頁已經可以手動切換明亮模式和黑暗模式,網頁的主題切換已經成為了一個常用的需求,因此,本文將從常見框架的處理方式總結一些相關的操作,並探究其本質。 ...


在如今,很多網頁已經可以手動切換明亮模式和黑暗模式,網頁的主題切換已經成為了一個常用的需求,因此,本文將從常見框架的處理方式總結一些相關的操作,並探究其本質。


AntD 的方式

AntD 的 config-provider 似乎不能直接修改主題,目前網路上的教程有兩類,一類是通過 less 的修改變數修改來完成,另一類是操作 DOM 改變對文件的引用,由於 ant-design-vue 已經提供了黑暗主題,而且直接修改 less 文件的變數涉及到了太多變數,不太方便,因此參考了 @杭州程式員張張的文章,使用動態添加 CSS 引用 DOM 的方式實現黑暗主題的切換,原理是添加一個 DOM,引用我們自定義的 CSS 樣式,後面的引用會覆蓋前面的引用,在切換到亮色主題時把這個 DOM 刪除。

1. 創建黑暗主題文件

在目錄下的適當位置創建一個黑暗主題的文件,後面要引用這個文件,這裡直接把官方黑暗主題複製過來就可以了,它的位置在 node_modules\ant-design-vue\dist\antd.dark.min.css,假設我們把它複製到了 public/styles/dark.css 中。

2. 創建切換主題的函數

有了主題文件,我們就可以創建切換主題的函數了,在目錄中的合適位置創建一個 js 文件,例如 src/utils/theme.ts,其中的代碼為:

const darkThemeSwitch = () => {
    // id要與前面一致
    const theme_element = document.querySelector('#dark-theme-style');
    if (!theme_element) {
        const new_dark_Theme = document.createElement('link')
        new_dark_Theme.setAttribute('rel', 'stylesheet');
        //剛剛設置的css路徑
        new_dark_Theme.setAttribute('href', '/styles/dark.css');
        // id可以自由設置
        new_dark_Theme.setAttribute('id', 'dark-theme-style');
        const docHead = document.querySelector('head');
        docHead?.append(new_dark_Theme);
    } else {
        const parentNode = theme_element?.parentNode;
        parentNode?.removeChild(theme_element);
    }
}

export default darkThemeSwitch;

3. 切換主題

然後,我們在需要切換主題的地方使用這個方法就可以了:

<template>
    <a-button @click="toggleDark">切換主題</a-button>
</template>

<script setup lang="ts">
    import darkThemeSwitch from '../utils/theme';
    const toggleDark = () => {
        darkThemeSwitch();
    };
</script>

Quasar 的方式

quasar 的主題切換非常簡單,只要使用 quasar 官方提供的 dark 插件就可以了,使用方法如下:

import { useQuasar } from 'quasar'
const $q = useQuasar()

// get status
console.log($q.dark.isActive) // true, false

// get configured status
console.log($q.dark.mode) // "auto", true, false

// set status
$q.dark.set(true) // or false or "auto"

// toggle
$q.dark.toggle()

通過研究 Quasar 的源碼,可以發現,Quasar 的黑暗有兩種設置方式,自動和手動,在自動模式下,插件通過監聽 prefers-color-scheme: dark 的狀態來決定當前網頁的主題,通過這種方式,可以實現網頁跟隨系統主題自動變換淺色和深色模式,對應部分的代碼如下:

Plugin.mode = val
if (val === 'auto') {
  if (Plugin.__media === void 0) {
    Plugin.__media = window.matchMedia('(prefers-color-scheme: dark)')
    Plugin.__updateMedia = () => { Plugin.set('auto') }
    Plugin.__media.addListener(Plugin.__updateMedia)
  }

  val = Plugin.__media.matches
}

上面的代碼中,Plugin.mode 代表設置方式,Plugin.__media 的值預設就是 void 0,這裡的判斷的作用是當第一次執行時給相應的 Media 添加一個監聽來獲得實時的變化。這裡調用的 Plugin.set('auto') 就是手動設置的函數,這個函數接受一個布爾值,然後根據布爾值的真假對主題進行設置,相應的實現如下:

document.body.classList.remove(`body--${ val === true ? 'light' : 'dark' }`)
document.body.classList.add(`body--${ val === true ? 'dark' : 'light' }`)

顯然,這裡的實現方式也比較常規,即在 body 標簽添加或刪除相應的樣式選擇器類名來實現主題的切換,quasar 值得我們學習的地方在於它把所有的功能集成到 useQuasar 中,用戶可以方便地使用各種插件,而不需要寫很多代碼。完整的代碼如下:

import defineReactivePlugin from '../utils/private/define-reactive-plugin.js'
import { isRuntimeSsrPreHydration } from './Platform.js'

const Plugin = defineReactivePlugin({
    // 插件的屬性
    isActive: false,
    mode: false
}, {
    __media: void 0,
    // 插件的核心方法
    set(val) {
        if (__QUASAR_SSR_SERVER__) { return }

        Plugin.mode = val
        // 自動主題切換
        if (val === 'auto') {
            if (Plugin.__media === void 0) {
                Plugin.__media = window.matchMedia('(prefers-color-scheme: dark)')
                Plugin.__updateMedia = () => { Plugin.set('auto') }
                Plugin.__media.addListener(Plugin.__updateMedia)
            }

            val = Plugin.__media.matches
        }
        else if (Plugin.__media !== void 0) {
            Plugin.__media.removeListener(Plugin.__updateMedia)
            Plugin.__media = void 0
        }

        Plugin.isActive = val === true
        // 手動指定主題
        document.body.classList.remove(`body--${val === true ? 'light' : 'dark'}`)
        document.body.classList.add(`body--${val === true ? 'dark' : 'light'}`)
    },
    // 主題的切換
    toggle() {
        if (__QUASAR_SSR_SERVER__ !== true) {
            Plugin.set(Plugin.isActive === false)
        }
    },

    install({ $q, onSSRHydrated, ssrContext }) {
        const { dark } = $q.config

        if (__QUASAR_SSR_SERVER__) {
            this.isActive = dark === true

            $q.dark = {
                isActive: false,
                mode: false,
                set: val => {
                    ssrContext._meta.bodyClasses = ssrContext._meta.bodyClasses
                        .replace(' body--light', '')
                        .replace(' body--dark', '') + ` body--${val === true ? 'dark' : 'light'}`

                    $q.dark.isActive = val === true
                    $q.dark.mode = val
                },
                toggle: () => {
                    $q.dark.set($q.dark.isActive === false)
                }
            }

            $q.dark.set(dark)
            return
        }

        $q.dark = this

        if (this.__installed === true && dark === void 0) {
            return
        }

        this.isActive = dark === true

        const initialVal = dark !== void 0 ? dark : false

        if (isRuntimeSsrPreHydration.value === true) {
            const ssrSet = val => {
                this.__fromSSR = val
            }

            const originalSet = this.set

            this.set = ssrSet
            ssrSet(initialVal)

            onSSRHydrated.push(() => {
                this.set = originalSet
                this.set(this.__fromSSR)
            })
        }
        else {
            this.set(initialVal)
        }
    }
})

export default Plugin

ElementUI 的方式

在 2.2.0 版本,Element UI 也可以進行黑暗模式切換了,操作如下:

  1. main.ts 引入官方的 CSS:import 'element-plus/theme-chalk/dark/css-vars.css'

  2. 更改 html 標簽的類,添加 dark 即為黑暗模式,去掉 dark 即為明亮模式,這一過程有很多實現方法,官方推薦使用 VueUse 這個函數庫中的 useDark 來實現,這是一個非常強大的官方工具庫,裡面提供了許多常用功能的實現以及一些小插件,非常值得學習,請參考VueUse的官方文檔:

    <template>
        <el-button @click="toggleDark()">切換主題</el-button>
    </template>
    
    <script setup lang="ts">
        import { useDark, useToggle } from '@vueuse/core';
    
        const isDark = useDark();
        const toggleDark = useToggle(isDark);
    </script>
    
    

NaiveUI 的方式

NaiveUI 的黑暗主題是通過其提供的 Config Provider 組件來實現的,通過設置其 theme 屬性為 null 或者 darkTheme(需要從 naive-ui 導入),可以更改其內部組件的主題,配合 Global Style 組件,可以設置全局的主題:

<template>
  <n-config-provider :theme="theme">
    <n-card>
      <n-space>
        <n-button @click="theme = darkTheme">
          深色
        </n-button>
        <n-button @click="theme = null">
          淺色
        </n-button>
      </n-space>
    </n-card>
    <!-- 加上這個後可以切換全局主題 -->
    <n-global-style />
  </n-config-provider>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { darkTheme } from 'naive-ui'
import type { GlobalTheme } from 'naive-ui'

const theme = ref<GlobalTheme | null>(null)
</script>

還可以通過 useOsTheme 獲取系統的主題作為組件的主題:

<template>
  <n-config-provider :theme="theme">
    <n-card> 當前操作系統的主題是 {{ osTheme }}。 </n-card>
  </n-config-provider>
</template>

<script lang="ts">
import { defineComponent, computed } from 'vue'
import { useOsTheme, darkTheme } from 'naive-ui'

export default defineComponent({
  setup () {
    const osThemeRef = useOsTheme()
    return {
      theme: computed(() => (osThemeRef.value === 'dark' ? darkTheme : null)),
      osTheme: osThemeRef
    }
  }
})
</script>

讓我們來看一下它的實現,好吧,我水平實在是有限,真的看不懂,但是看起來真的很厲害。

本文來自博客園,作者:凍羊,轉載請註明原文鏈接:https://www.cnblogs.com/wdyyy/p/vue_darkmode.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、寫在前 知識學了就忘!不用就忘!我太健忘!特此記錄!用於複習打卡!Redis乾就完事了! 二、來辣! Redis做非同步隊列:一般list結構做隊列,rpush生產消息,lpop消費消息,當lpop沒有消息的時候,要適當sleep一會兒;如果不sleep,就用blpop,會阻塞;生產一次消費多次, ...
  • 1.3 Apache Hadoop的重要組成 Hadoop=HDFS(分散式文件系統)+MapReduce(分散式計算框架)+Yarn(資源協調框架)+Common模塊 Hadoop HDFS:(Hadoop Distribute File System )一個高可靠、高吞吐量的分散式文件系統 比如 ...
  • 和一個真正iOS開發的區別? 學習iOS的這段時間, 我一直在思考和感受著自己和一個真正做了幾年iOS的dev之間的區別. 同時也在反向思考, 我自己和一個新學Android的人, 又有什麼區別. 也許在技術轉型中, 這些學習的思考和陣痛都是有共性和不可避免的. 在此分享一下感受, 如果有人也有技術 ...
  • 最近在開發時,遇到相同的頁面,很多函數和佈局也大差不多,所以向在路由註冊時就給他們分配不同的路由,通過一些判斷走不同的邏輯獲取數據。 ...
  • /** * 替換字元串,預設替換 ""。傳遞 regExps,一個正則表達式數組。 * * @param source 被修剪的字元串 * @param regExps 正則表達式,找到匹配的字元串,然後替換掉 * @param replacement 不傳遞,預設被替換的字元串是 ""。傳遞的數組 ...
  • 作為後端程式員,瞭解和掌握一些前端知識也是必不可少的,本章就和大家分享Vue的一些基礎知識,希望能夠對Vue小白有所幫助。話不多說,下麵我們直接進入主題。 一、Vue簡介 Vue簡介:1、JavaScript框架;2、簡化Dom操作;3、響應式的數據驅動(頁面是由數據來生成的,當數據改變以後頁面會同 ...
  • JQuery04 6.jQuery的DOM操作02 6.9常用遍歷節點方法 取得匹配元素的所有子元素組成的集合:children(),該方法只考慮子元素而不考慮任何後代元素 取得匹配元素後面的同輩元素的集合:next()/nextAll() 如果是next方法,就是拿到指定元素後面的一個元素,如果是 ...
  • 在 javascript 中內置了一個 Date 對象,可用於實現一些日期和時間的操作。 本文整理 js 日期對象的詳細功能,使用 js 日期對象獲取具體日期、昨天、今天、明天、每月天數、時間戳等,以及常用的日期時間處理方法。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...