Vue3項目中實現(xiàn)主題切換真的很簡單!?。?/h1>
一、原理
換膚能夠?qū)崿F(xiàn)的終極密碼是——CSS變量,可以為每個主題設(shè)定一組CSS變量,包含這個主題的所有顏色、字體等信息,當(dāng)需要切換主題時,只需要更改使用的CSS變量組即可。
- 聲明變量。在 :root 偽類中聲明 CSS 變量,這樣就能在全局范圍內(nèi)使用變量:
:root {
--main-color: #06c;
}
- 使用變量。在你的 CSS 中,使用
var()
函數(shù)來使用 CSS 變量:
.header {
background-color: var(--main-color);
}
二、demo實現(xiàn)
下面我們用Vue3+Element-plus為例,來實現(xiàn)一波高亮模式+暗黑模式兩個主題色,可參考element-plus暗黑模式介紹。
2.1 引入主題色樣式
在src/styles下面新建theme.scss,把默認暗黑主題色引入進來,并可以在其里面覆蓋原有變量或新增一些變量
// theme.scss
/** element內(nèi)置暗黑主題 */
@use 'element-plus/theme-chalk/src/dark/css-vars.scss' as *;
// 可以進行一些樣式的覆蓋
html {
--v-bg-color: #cfcccc; // 新增
}
html.dark {
--v-bg-color: #141414; // 新增
--el-color-primary: #409eff; // 覆蓋
}
在main.ts中引入默認主題色和暗黑模式主題色
// main.ts 文件
import { createApp } from 'vue';
import ElementPlus from 'element-plus';
// element默認主題
import 'element-plus/dist/index.css'
import './style.css';
// 公共樣式,包含自定義暗黑模式,element重置樣式
import './styles/index.scss';
import App from './App.vue';
const app = createApp(App);
app.use(ElementPlus);
app.mount('#app')
此時在瀏覽器控制臺就可以看到很多變量
2.2 主題色切換能力
主題切換能力其核心關(guān)注點為:
- 利用provide注入當(dāng)前主題及修改主題的方法,然后在組件中通過inject獲取主題及主題修改方法;
- 利用localStorage持久化存儲主題;
- 改變html的class屬性,進而決定使用哪一套主題;
<script setup lang="ts">
import {provide, ref, onMounted} from 'vue';
import SwitchDark from './components/SwitchDark.vue';
// 改變屬性,確定使用哪一套樣式
const addThemeAttribute = (theme: string) => {
const html = document.documentElement;
html.setAttribute('class', theme);
}
const theme = ref(localStorage.getItem('myTheme') || 'light');
onMounted(() => {
addThemeAttribute(theme.value);
});
const setTheme = (newTheme: string) => {
// 改變主題
theme.value = newTheme;
addThemeAttribute(newTheme);
localStorage.setItem('myTheme', newTheme);
};
provide('theme', {
theme,
setTheme
});
</script>
<template>
<SwitchDark />
<div class="bg">
我是內(nèi)容
</div>
</template>
<style scoped>
.bg {
background-color: var(--v-bg-color);
width: 200px;
height: 200px;
}
</style>
2.3 切換按鈕
切換主題色肯定需要一個按鈕,下面利用el-switch實現(xiàn)了一個簡單的切換按鈕,并利用setTheme來切換對應(yīng)的主題。
<template>
<el-switch
v-model="isDark"
inline-prompt
@change="changeTheme"
:active-icnotallow="Sunny"
:inactive-icnotallow="Moon"
size="large"
/>
</template>
<script setup lang="ts">
import {inject, Ref, computed} from 'vue';
import {Sunny, Moon} from '@element-plus/icons-vue';
const {theme, setTheme} = inject<{theme: Ref<string>, setTheme: (newTheme: string) => void}>('theme') || {};
const isDark = computed(() => theme?.value === 'dark');
const changeTheme = () => {
console.log(theme?.value)
if (theme?.value === 'light') {
setTheme?.('dark');
} else {
setTheme?.('light');
}
};
</script>
<style scoped>
</style>