欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue實(shí)現(xiàn)項(xiàng)目主題切換功能的兩種方案詳解

 更新時(shí)間:2025年09月19日 09:42:56   作者:前端小超超  
在現(xiàn)代前端項(xiàng)目開發(fā)中,主題切換已成為提升用戶體驗(yàn)的核心功能之一,無論是適配用戶白天?/?夜間的使用場景、滿足企業(yè)級(jí)產(chǎn)品的品牌定制需求,還是應(yīng)對(duì)不同設(shè)備的顯示環(huán)境,靈活的主題系統(tǒng)都能讓產(chǎn)品更具競爭力,所以本文介紹了Vue實(shí)現(xiàn)項(xiàng)目主題切換功能的兩種方案

引言

在現(xiàn)代前端項(xiàng)目開發(fā)中,主題切換已成為提升用戶體驗(yàn)的核心功能之一 —— 無論是適配用戶白天 / 夜間的使用場景、滿足企業(yè)級(jí)產(chǎn)品的品牌定制需求,還是應(yīng)對(duì)不同設(shè)備的顯示環(huán)境,靈活的主題系統(tǒng)都能讓產(chǎn)品更具競爭力。在 Vue 3 項(xiàng)目中,基于 CSS 變量與組合式 API(Composables)的主題切換方案最為常見,以下將詳細(xì)拆解兩種實(shí)現(xiàn)思路,并結(jié)合實(shí)際項(xiàng)目需求分析選型邏輯。

方案一:基于 CSS 類名切換的主題系統(tǒng)

該方案的核心思路是通過預(yù)定義不同主題的 CSS 類(如.theme-dark),在切換時(shí)為根元素添加 / 移除對(duì)應(yīng)類名,觸發(fā)全局 CSS 變量的替換,適合主題樣式固定、擴(kuò)展需求較少的中小型項(xiàng)目。

步驟 1:搭建全局樣式文件結(jié)構(gòu)

首先在/src/assets下新建styles文件夾并創(chuàng)建theme.scss文件 —— 選擇 SCSS 而非普通 CSS,是因?yàn)?SCSS 支持變量嵌套、混入等特性,后續(xù)若需擴(kuò)展主題樣式(如添加主題專屬組件樣式),可更高效地維護(hù)。

theme.scss文件:

// 默認(rèn)使用淺色主題
:root{
  --bg-color:#ffffff;
  --text-color: #333333;
}
 
// 深色主題
.theme-dark{
  --bg-color:#333333;
  --text-color: #ffffff;
}
 
// 自定義主題
.theme-custom{ 
  --bg-color: red;
  --text-color: #333333;
}
 
// 全局應(yīng)用背景色
body{
  background-color: var(--bg-color);
  color: var(--text-color);
  transition: background-color 0.5s ease-in-out; // 添加過渡效果,平滑過渡
}

步驟 2:全局導(dǎo)入樣式文件

在 Vue 入口文件main.ts中導(dǎo)入theme.scss—— 入口文件導(dǎo)入可確保樣式全局生效,無需在每個(gè)組件中重復(fù)引入,避免代碼冗余。同時(shí),該步驟需在createApp之前執(zhí)行,確保組件渲染時(shí)主題樣式已加載。

import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import './assets/styles/theme.scss'; // 導(dǎo)入全局主題樣式:確保主題變量全局可訪問
 
const app = createApp(App)
 
app.use(createPinia())
app.use(router)
 
app.mount('#app')

步驟 3:在頭部組件實(shí)現(xiàn)主題切換交互

頭部組件是用戶高頻操作區(qū)域,在此添加主題切換按鈕可提升易用性。核心邏輯是通過useTheme組合式 API 封裝主題切換方法,同時(shí)結(jié)合 Pinia 存儲(chǔ)用戶信息、定時(shí)器更新當(dāng)前時(shí)間,確保功能模塊化。

<script lang="ts" setup>
import router from '@/router';
import { ref, onMounted, watchEffect, computed, onUnmounted } from 'vue'
import type { Ref } from 'vue'
import { getUserInfo } from '@/api/home';
import { useUserStore } from '@/stores/user';
import { useTheme } from '@/composables/useTheme';
 
const { currentTheme, changeTheme } = useTheme();
 
const userStore = useUserStore()
 
interface IUserInfo {
  adminid: string,
  adminname: string,
  checkedKeys: any[],
  role: number
}
const userInfo: Ref<IUserInfo> = ref({
  adminid: '',
  adminname: '',
  checkedKeys: [],
  role: -1
})
 
// 1.使用 ref 創(chuàng)建一個(gè)響應(yīng)式的當(dāng)前時(shí)間  toLocaleString()是格式化日期和時(shí)間的方法
const currentTime = ref(new Date().toLocaleString())
// 2.定義一個(gè)函數(shù)來更新時(shí)間
function updateTime(){
  currentTime.value = new Date().toLocaleString()
}
 
onMounted(async () => {
  // 3.設(shè)置一個(gè)定時(shí)器,每一秒更新一遍時(shí)間
  const time = setInterval(updateTime,1000)
 
  onUnmounted(()=>{
    // 4.在組件卸載時(shí)清除定時(shí)器,避免內(nèi)存泄漏
    clearInterval(time)
  })
 
  const res = await getUserInfo({
    adminname: userStore.userInfo.adminname
  })
  userInfo.value = res.data.data[0]
})
 
const logout = (() => {
  localStorage.removeItem('userInfo')
  router.replace('/login')
})
</script>
<template>
  <div class="header-manage">
    <h1>HEADER</h1>
    <div class="admin-manage">
      <div class="theme-switch">
        <button @click="changeTheme('light')">淺色主題</button>
        <button @click="changeTheme('dark')">深色主題</button>
        <button @click="changeTheme('custom')">自定義主題</button>
        <p class="theme-text">當(dāng)前主題:{{ currentTheme }}</p>
      </div>
      <div class="admin-con">
        <el-icon>
          <i-ep-Stopwatch />
        </el-icon>
        <span>{{ currentTime }}</span>
      </div>
      <div class="admin-con">
        <el-icon>
          <i-ep-User />
        </el-icon>
        <span>{{ userStore.userInfo.adminname }}</span>
      </div>
      <div class="admin-con" style="cursor: pointer;">
        <el-icon>
          <i-ep-SwitchButton />
        </el-icon>
        <span @click="logout">退出登錄</span>
      </div>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.header-manage {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color:var(--text-primary-color) //全局主題顏色
}
 
.admin-manage {
  display: flex;
 
  .theme-switch { 
 
    .theme-text{
      color: var(--text-secondary-color);
    }
  }
}
 
.admin-con {
  margin-left: 30px;
  display: flex;
  align-items: center;
 
  span {
    font-size: 14px;
    margin-left: 8px;
  }
}
</style>

方案二:基于 TypeScript 配置的動(dòng)態(tài)主題系統(tǒng)

該方案的核心思路是通過 TypeScript 定義主題配置接口,將主題變量集中管理,切換時(shí)直接通過 JS 動(dòng)態(tài)修改根元素的 CSS 變量,無需預(yù)定義 CSS 類,靈活性更高,適合主題變量多、需頻繁擴(kuò)展的中大型項(xiàng)目。

步驟 1:搭建主題配置文件

/src下新建theme文件夾并創(chuàng)建index.ts—— 用 TypeScript 定義主題接口與配置,既能通過類型約束避免變量名錯(cuò)誤,又能將所有主題變量集中管理,后續(xù)修改或新增主題時(shí),只需更新配置文件即可。

// 主題配置接口(添加索引簽名)
interface ThemeConfig {
  "--bg-color": string;
  "--text-primary-color": string;
  "--text-secondary-color": string;
  "--text-tertiary-color": string;
  "--text-disabled-color": string;
  "--button-bg-color": string;
  "--button-text-color": string;
  // 索引簽名:允許用字符串鍵訪問(關(guān)鍵?。?
  [key: string]: string;
}
 
// 主題類型定義
export type ThemeType = 'light' | 'dark' | 'custom'
 
// 主題配置
export const themeConfig: Record<ThemeType, ThemeConfig> = {
  light:{
    "--bg-color":'#ffffff', // 背景色
    "--text-primary-color": '#333333',// 主要文字色
    "--text-secondary-color":'#666666', // 次要文字色
    "--text-tertiary-color":'#999999', // 三級(jí)文字色
    "--text-disabled-color":'#cccccc', // 禁用文字色
    "--button-bg-color":'#42b983', // 按鈕背景色
    "--button-text-color":'#ffffff', // 按鈕文字色
  },
  dark:{
    "--bg-color":'#333333', // 背景色
    "--text-primary-color":'#ffffff', // 主要文字色
    "--text-secondary-color":'#cccccc', // 次要文字色
    "--text-tertiary-color":'#999999', // 三級(jí)文字色
    "--text-disabled-color":'#666666', // 禁用文字色
    "--button-bg-color":'#42b983', // 按鈕背景色
    "--button-text-color":'#ffffff', // 按鈕文字色
  },
  custom:{
     "--bg-color":'skyblue', // 背景色
    "--text-primary-color":'#333333', // 主要文字色
    "--text-secondary-color":'skyblue', // 次要文字色
    "--text-tertiary-color":'#999999', // 三級(jí)文字色
    "--text-disabled-color":'#cccccc', // 禁用文字色
    "--button-bg-color":'#42b983', // 按鈕背景色
    "--button-text-color":'#ffffff', // 按鈕文字色
  }
}
 
// 默認(rèn)主題
export const defaultTheme: ThemeType = 'light';

步驟 2:封裝主題切換組合式 API

/src/composables下新建useTheme.ts—— 用 Vue 的組合式 API 封裝主題切換邏輯,將 “主題初始化、主題應(yīng)用、主題切換” 等功能模塊化,后續(xù)任何組件需要使用主題功能,只需導(dǎo)入該 API 即可,避免代碼重復(fù)。

import type { ThemeType } from '@/theme'
import { themeConfig, defaultTheme } from '@/theme'
import { onMounted, ref } from 'vue'
 
export function useTheme() { 
  // 當(dāng)前主題,響應(yīng)式
  const currentTheme = ref<ThemeType>(defaultTheme)
 
  // 初始化:從localStorage中獲取保存的主題
  onMounted(() => {
    const theme = localStorage.getItem('app-theme') as ThemeType
    if (theme && Object.keys(themeConfig).includes(theme)) {
      currentTheme.value = theme
      applyTheme(theme) //應(yīng)用主題
    }
  })
 
  // 應(yīng)用主題(核心:給html加主題類名,觸發(fā)css變量切換)
  const applyTheme = (theme: ThemeType) => {
    // 先移除所有主題類
    document.documentElement.classList.remove('theme-light','theme-dark','theme-custom')
    // 添加當(dāng)前主題類(如果不是默認(rèn)主題)
    // if(theme !== 'light'){
    //   document.documentElement.classList.add(`theme-${theme}`)
    // }
 
    Object.keys(themeConfig[theme]).forEach(key => {
      document.documentElement.style.setProperty(`${key}`, themeConfig[theme][key]);
    });
 
    // document.documentElement.style.setProperty('--bg-color', themeConfig[theme].backgroundColor);
 
    // 存儲(chǔ)當(dāng)前主題
    localStorage.setItem('app-theme', theme)
  }
 
  // 切換主題
  const changeTheme = (theme: ThemeType) => {
    if(themeConfig[theme]){
      currentTheme.value = theme
      applyTheme(theme)
    }
  }
 
  return { currentTheme, changeTheme }
}

步驟 3:復(fù)用組件交互邏輯

與方案一的步驟 3 一致,在頭部組件中導(dǎo)入useTheme API,綁定按鈕點(diǎn)擊事件觸發(fā)changeTheme—— 由于方案二的主題邏輯已通過 API 封裝,組件層面無需修改任何交互代碼,只需復(fù)用現(xiàn)有按鈕即可實(shí)現(xiàn)主題切換,體現(xiàn)了模塊化的優(yōu)勢(shì)。

兩種方案對(duì)比與選型分析

對(duì)比維度方案一(CSS 類名切換)方案二(TS 配置動(dòng)態(tài)修改)
實(shí)現(xiàn)原理預(yù)定義主題類,通過添加 / 移除類名切換集中管理 TS 配置,動(dòng)態(tài)修改 CSS 變量
靈活性新增主題需修改 CSS 文件,擴(kuò)展成本高新增主題只需添加 TS 配置,擴(kuò)展成本低
TypeScript 支持無類型約束,易出現(xiàn)變量名錯(cuò)誤接口 + 類型約束,避免變量錯(cuò)誤
維護(hù)成本主題樣式分散在 CSS 中,維護(hù)難度高主題配置集中在 TS 中,維護(hù)更高效
持久化實(shí)現(xiàn)需額外編寫邏輯保存類名內(nèi)置 localStorage 保存,邏輯更簡潔
適用場景主題少、需求穩(wěn)定的中小型項(xiàng)目主題多、需頻繁擴(kuò)展的中大型項(xiàng)目

從實(shí)際項(xiàng)目需求出發(fā),方案二的優(yōu)勢(shì)更為明顯:一是 TypeScript 的類型約束降低了協(xié)作中的錯(cuò)誤率;二是集中式配置讓主題維護(hù)更高效(如后續(xù)新增 “企業(yè)主題”,只需在themeConfig中添加配置);三是動(dòng)態(tài)修改 CSS 變量無需預(yù)定義類名,減少了 CSS 代碼冗余。因此,最終選擇方案二作為項(xiàng)目的主題切換實(shí)現(xiàn)方案。

以上就是Vue實(shí)現(xiàn)項(xiàng)目主題切換功能的兩種方案詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue項(xiàng)目主題切換的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Element Card 卡片的具體使用

    Element Card 卡片的具體使用

    這篇文章主要介紹了Element Card 卡片的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Vue3中操作ref的四種使用方式示例代碼(建議收藏)

    Vue3中操作ref的四種使用方式示例代碼(建議收藏)

    這篇文章主要介紹了Vue3中操作ref的四種使用方式示例代碼(建議收藏),本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • 詳解vue-router 命名路由和命名視圖

    詳解vue-router 命名路由和命名視圖

    這篇文章主要介紹了詳解vue-router 命名路由和命名視圖,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-06-06
  • 解決前端調(diào)用后端接口返回200但數(shù)據(jù)返回的是html標(biāo)簽

    解決前端調(diào)用后端接口返回200但數(shù)據(jù)返回的是html標(biāo)簽

    這篇文章主要給大家介紹了關(guān)于如何解決前端調(diào)用后端接口返回200但數(shù)據(jù)返回的是html標(biāo)簽的相關(guān)資料,文中通過圖文將解決的過程介紹的非常詳細(xì),對(duì)同樣遇到這個(gè)問題的朋友具有一定的參考解決價(jià)值,需要的朋友可以參考下
    2024-05-05
  • vue-cli2打包前和打包后的css前綴不一致的問題解決

    vue-cli2打包前和打包后的css前綴不一致的問題解決

    這篇文章主要介紹了vue-cli2打包前和打包后的css前綴不一致的問題解決,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • 如何用vite動(dòng)態(tài)導(dǎo)入vue的路由配置詳解

    如何用vite動(dòng)態(tài)導(dǎo)入vue的路由配置詳解

    這篇文章主要介紹了如何用vite動(dòng)態(tài)導(dǎo)入vue的路由配置的相關(guān)資料,動(dòng)態(tài)導(dǎo)入路由模仿了uniapp的頁面配置文件結(jié)構(gòu),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-04-04
  • 在vue項(xiàng)目中配置你自己的啟動(dòng)命令和打包命令方式

    在vue項(xiàng)目中配置你自己的啟動(dòng)命令和打包命令方式

    這篇文章主要介紹了在vue項(xiàng)目中配置你自己的啟動(dòng)命令和打包命令方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue中import from的來源及省略后綴與加載文件夾問題

    Vue中import from的來源及省略后綴與加載文件夾問題

    這篇文章主要介紹了Vue中import from的來源--省略后綴與加載文件夾,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Vue實(shí)現(xiàn)搖一搖功能(兼容ios13.3以上)

    Vue實(shí)現(xiàn)搖一搖功能(兼容ios13.3以上)

    這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)搖一搖功能,兼容ios13.3以上,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • Vue+scss白天和夜間模式切換功能的實(shí)現(xiàn)方法

    Vue+scss白天和夜間模式切換功能的實(shí)現(xiàn)方法

    這篇文章主要介紹了Vue+scss白天和夜間模式切換功能的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01

最新評(píng)論