vue 实现Element Plus的炫酷主题切换

效果图

.vue

bash 复制代码
<template>
  <view class="flex-end">
    <div class="wxy-switch" :class="{'wxy-switch-checked':showView}"
    @click="themeSwitch" >
      <div class="wxy-switch-round"></div>
    </div>
  </view>
</template>

<script setup>
import {ref } from 'vue'

const showView = ref(false)

const themeSwitch = (e) => {
  showView.value = !showView.value;
  // 如果不支持 startViewTransition 直接切换
  if (!document.startViewTransition) {
  	document.documentElement.classList.toggle("dark");
  	return
  }

  const transition =  document.startViewTransition(() => {
    document.documentElement.classList.toggle("dark");
  });

  transition.ready.then(() => {
    const { clientX, clientY } = e
    const radius = Math.hypot(
      Math.max(clientX, window.innerWidth - clientX),
      Math.max(clientY, window.innerHeight - clientY)
    )
    
    const isDark = document.documentElement.classList.contains("dark");
    const clipPath = [
      `circle(0px at ${clientX}px ${clientY}px)`,
      `circle(${radius}px at ${clientX}px ${clientY}px)`,
    ]
    document.documentElement.animate(
      { clipPath: isDark ? clipPath.reverse() : clipPath },
      { 
        duration: 500,
        fill: "both",
        pseudoElement: isDark ? "::view-transition-old(root)" : "::view-transition-new(root)"
      }
    )
  });
}
</script>

<style scoped>
.flex-end{
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.wxy-switch{
  --w:40px;
  --h:20px;

  position: relative;
  width: var(--w);
  height: var(--h);
  background-color: #D6D6D6;
  border-radius: 25px;
  transition: background-color 0.3s;
}

.wxy-switch-checked{
  background-color: #39b54a;
}

.wxy-switch-round{
  position: absolute;
  top: 0;
  bottom: 0;
  left: 1.5px;
  width: calc(var(--h) - 3px);
  height: calc(var(--h) - 3px);
  margin: auto 0;
  background: #fff;
  border-radius: 50%;
  transition: left 0.3s;
}

.wxy-switch-checked .wxy-switch-round{
  left: calc(100% - var(--h) + 1.5px);
}
</style>

.css

bash 复制代码
body{
  margin: 0;
}

:root {
  --theme-bg-color: #fff;
  --theme-text-color: #333;
}

:root.dark {
  --theme-bg-color: #333;
  --theme-text-color: #fff;
}

::view-transition-new(root),
::view-transition-old(root) {
  animation: none;
}

.dark::view-transition-old(root) {
  z-index: 9999;
}

#app {
  min-height: 100vh;
  background-color: var(--theme-bg-color);
  color: var(--theme-text-color);
  text-align: center;
  padding: 2rem;
}

div,a{
  box-sizing: border-box;
}

遇到问题可以看我主页加我,很少看博客,对你有帮助别忘记点赞收藏。

相关推荐
铁皮饭盒1 小时前
3行代码搞定页面截图,Bun.WebView真的简单
javascript
kyriewen14 小时前
我手写了一个 EventEmitter,面试官追问了 6 个问题——第 4 个我没答上来
前端·javascript·面试
山河木马15 小时前
矩阵专题2-怎么创建视图矩阵(uViewMatrix)
javascript·webgl·计算机图形学
tangdou36909865516 小时前
AI真好玩系列-2分钟快速了解DeepAgents | Quick Guide to DeepAgents in 2 Minutes
前端·javascript·后端
张元清16 小时前
React useIntersectionObserver Hook:懒加载与可见性检测(2026)
javascript·react.js
彭于晏爱编程16 小时前
纯 JS + Node,一个下午手搓了能读懂公司代码的 AI 助手,老板以为我转行了
前端·javascript
妙码生花17 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十四):眨眼小人登录页制作
前端·javascript·ai编程
妙码生花17 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十三):前端路由初始化
前端·javascript·ai编程
PBitW18 小时前
GPT训练我的第四天,被打惨了!!!😭😭😭
前端·javascript·面试
DarkLONGLOVE18 小时前
快速上手 Pinia!Vue3 极简状态管理使用教程
javascript·vue.js