使用vue3實現(xiàn)element-plus的主題切換效果
先看實現(xiàn)效果

實現(xiàn)過程
前提需要引入好 element-plus,并導入element的黑色主題CSS
示例,再 main.js 中引入
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css' // 黑色主題
app.use(ElementPlus, {
locale: locale,
size: Cookies.get('size') || 'default'
})
接著編寫下面的基礎代碼
<template>
<div>
<el-switch v-model='value1' class='switch' @change='changeSwitch'>
<template #active-action>
<el-icon>
<Moon />
</el-icon>
</template>
<template #inactive-action>
<el-icon>
<Sunny />
</el-icon>
</template>
</el-switch>
</div>
</template>
<script setup>
let value1 = ref(false)
function changeSwitch() {
document.documentElement.classList.toggle('dark')
}
</script>
<style scoped lang='scss'>
.switch {
position: absolute;
left: 200px;
top: 200px;
}
</style>
現(xiàn)在當切換 switch 時,背景顏色會直接進行黑白切換

從動畫可以看到,現(xiàn)在是沒有任何過渡效果的
我們可以使用 document.startViewTransition 很簡單的就可以加上過渡效果,document.startViewTransition 接收一個函數(shù)參數(shù),再函數(shù)內(nèi)部寫上操作DOM的邏輯代碼即可實現(xiàn)一個默認的過度效果
function changeSwitch() {
document.startViewTransition(() => {
document.documentElement.classList.toggle('dark')
})
}
現(xiàn)在就有了一個默認的過渡效果

為什么使用了 document.startViewTransition 就會有一個動畫效果呢
MDN文檔:Document:startViewTransition() 方法 - Web API | MDN

通過調(diào)用 API,讓瀏覽器為新舊兩種不同視圖分別捕獲并建立了快照 (即 ::view-transition-old(root)舊快照 和 ::view-transition-new(root) 新快照),而后新舊兩快照在 ::view-transition-image-pair(root) 容器中完成轉(zhuǎn)場動畫的過渡。動畫結(jié)束后則刪除其相關(guān)偽元素 (快照和容器)。

我們也可以控制默認的動畫時長
::view-transition-old(root), /* 舊視圖*/
::view-transition-new(root) { /* 新視圖*/
animation-duration: 2s;
}
了解了這些,現(xiàn)在想點擊按鈕,實現(xiàn)一個擴散圓來實現(xiàn)主題切換效果,只需要根據(jù)按鈕位置,計算圓的半徑,然后設置 ::view-transition-new(root) 這個偽元素的動畫效果,讓圓從 0% 到 100%即可
完整代碼
<template>
<div>
<el-switch v-model='isDark' class='switch' ref='switchRef' @change='changeSwitch'>
<template #active-action>
<el-icon>
<Moon />
</el-icon>
</template>
<template #inactive-action>
<el-icon>
<Sunny />
</el-icon>
</template>
</el-switch>
</div>
</template>
<script setup>
import { ref } from 'vue'
let isDark = ref(false)
let switchRef = ref(null)
function changeSwitch() {
// 創(chuàng)建一個視圖過渡動畫,用于在切換深色模式時優(yōu)化用戶體驗
const transition = document.startViewTransition(() => {
// 切換HTML文檔的dark類,以激活或停用深色模式
document.documentElement.classList.toggle('dark')
})
// 當視圖過渡動畫準備就緒時執(zhí)行以下代碼
transition.ready.then(() => {
// 獲取switch組件的DOM元素,用于計算過渡動畫的起點
const switchElement = switchRef.value?.$el
// 計算switch組件中心點的坐標
const rect = switchElement.getBoundingClientRect()
const x = rect.left + rect.width / 2
const y = rect.top + rect.height / 2
// 計算過渡動畫結(jié)束時的圓半徑,確保覆蓋整個視口
const endRadius = Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y),
)
// 創(chuàng)建clipPath數(shù)組,定義了過渡動畫的起始和結(jié)束形狀
const clipPath = [
`circle(0 at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`,
]
// 在HTML文檔的根元素上啟動一個動畫,根據(jù)當前是否為深色模式來決定動畫的方向
document.documentElement.animate(
{
clipPath: isDark.value ? clipPath.reverse() : clipPath,
},
{
duration: 400, // 動畫持續(xù)時間
pseudoElement: isDark.value
? '::view-transition-old(root)'
: '::view-transition-new(root)', // 根據(jù)深色模式狀態(tài)選擇偽元素
},
)
})
}
</script>
<style>
::view-transition-new(root),
::view-transition-old(root) {
/* 關(guān)閉默認動畫,否則影響自定義動畫的執(zhí)行 */
animation: none !important;
}
/*黑暗模式下,讓舊節(jié)點的層級變高,否則會導致動畫出不來*/
.dark::view-transition-old(root) {
z-index: 100;
}
</style>
<style scoped>
.switch {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
</style>
circle 表示畫一個圓形,更多圖像可參考:clip-path - CSS:層疊樣式表 | MDN
以上就是使用vue3實現(xiàn)element-plus的主題切換效果的詳細內(nèi)容,更多關(guān)于vue3 element-plus主題切換的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在vue項目中(本地)使用iconfont字體圖標的三種方式總結(jié)
這篇文章主要介紹了在vue項目中(本地)使用iconfont字體圖標的三種方式總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
Element?el-date-picker?日期選擇器的使用
本文主要介紹了Element?el-date-picker?日期選擇器的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-04-04
Vue+ElementUI?封裝簡易PaginationSelect組件的詳細步驟
這篇文章主要介紹了Vue+ElementUI?封裝簡易PaginationSelect組件,這里簡單介紹封裝的一個Pagination-Select組件幾個步驟,結(jié)合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下2022-08-08

