Vue?UI框架的主題切換功能實現(xiàn)
在如今,很多網(wǎng)頁已經(jīng)可以手動切換明亮模式和黑暗模式,網(wǎng)頁的主題切換已經(jīng)成為了一個常用的需求,因此,本文將從常見框架的處理方式總結一些相關的操作,并探究其本質(zhì)。
AntD 的方式
AntD 的 config-provider
似乎不能直接修改主題,目前網(wǎng)絡上的教程有兩類,一類是通過 less 的修改變量修改來完成,另一類是操作 DOM 改變對文件的引用,由于 ant-design-vue 已經(jīng)提供了黑暗主題,而且直接修改 less 文件的變量涉及到了太多變量,不太方便,因此參考了這篇文章vue3點擊出現(xiàn)彈窗后背景變暗且不可操作的實現(xiàn)代碼,使用動態(tài)添加 CSS 引用 DOM 的方式實現(xiàn)黑暗主題的切換,原理是添加一個 DOM,引用我們自定義的 CSS 樣式,后面的引用會覆蓋前面的引用,在切換到亮色主題時把這個 DOM 刪除。
1. 創(chuàng)建黑暗主題文件
在目錄下的適當位置創(chuàng)建一個黑暗主題的文件,后面要引用這個文件,這里直接把官方黑暗主題復制過來就可以了,它的位置在 node_modules\ant-design-vue\dist\antd.dark.min.css
,假設我們把它復制到了 public/styles/dark.css
中。
2. 創(chuàng)建切換主題的函數(shù)
有了主題文件,我們就可以創(chuàng)建切換主題的函數(shù)了,在目錄中的合適位置創(chuàng)建一個 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 的源碼,可以發(fā)現(xiàn),Quasar 的黑暗有兩種設置方式,自動和手動,在自動模式下,插件通過監(jiān)聽 prefers-color-scheme: dark
的狀態(tài)來決定當前網(wǎng)頁的主題,通過這種方式,可以實現(xiàn)網(wǎng)頁跟隨系統(tǒng)主題自動變換淺色和深色模式,對應部分的代碼如下:
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
,這里的判斷的作用是當?shù)谝淮螆?zhí)行時給相應的 Media 添加一個監(jiān)聽來獲得實時的變化。這里調(diào)用的 Plugin.set('auto')
就是手動設置的函數(shù),這個函數(shù)接受一個布爾值,然后根據(jù)布爾值的真假對主題進行設置,相應的實現(xiàn)如下:
document.body.classList.remove(`body--${ val === true ? 'light' : 'dark' }`) document.body.classList.add(`body--${ val === true ? 'dark' : 'light' }`)
顯然,這里的實現(xiàn)方式也比較常規(guī),即在 body 標簽添加或刪除相應的樣式選擇器類名來實現(xiàn)主題的切換,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 也可以進行黑暗模式切換了,操作如下:
在
main.ts
引入官方的 CSS:import 'element-plus/theme-chalk/dark/css-vars.css'
更改 html
標簽的類,添加 dark
即為黑暗模式,去掉 dark 即為明亮模式,這一過程有很多實現(xiàn)方法,官方推薦使用 VueUse
這個函數(shù)庫中的 useDark
來實現(xiàn),這是一個非常強大的官方工具庫,里面提供了許多常用功能的實現(xiàn)以及一些小插件,非常值得學習,請參考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
組件來實現(xiàn)的,通過設置其 theme
屬性為 null
或者 darkTheme
(需要從 naive-ui 導入),可以更改其內(nèi)部組件的主題,配合 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
獲取系統(tǒng)的主題作為組件的主題:
<template> <n-config-provider :theme="theme"> <n-card> 當前操作系統(tǒng)的主題是 {{ 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>
讓我們來看一下它的實現(xiàn),好吧,我水平實在是有限,真的看不懂,但是看起來真的很厲害。
到此這篇關于Vue UI框架的主題切換功能實現(xiàn)的文章就介紹到這了,更多相關vue主題切換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!