Element-Plus主题切换动画实现

最近,我注意到ElementPlus官网上的主题切换方式颇具创意,特别是那过渡动画效果,让人眼前一亮。
经过一番网络搜寻,我找到了实现Element-UI官网主题切换动画的基本方法。首先,我们创建一个HTML文件,添加一个按钮,并编写简单的背景颜色切换代码,以此模拟主题的切换效果。

实现

基本效果

为实现element-plus主题切换这样一个动画效果,我们可以使用到web api提供的一个

View Transitions API

mdn上官方的详细介绍 View Transitions API - Web API | MDN

首先我们起一个 html 文件,写一个按钮,以及简单的背景颜色切换,来模拟主题的切换

可以看到实现了最简单的主题切换效果。

document.startViewTransition

想要实现过渡效果,需要先用到一个 JavaScript 的原生方法:document.startViewTransition。

这个方法是用来做动画过渡效果的。

通过调用 API,让浏览器为新旧两种不同视图分别捕获并建立了快照 (即 ::view-transition-old(root)旧快照 和 ::view-transition-new(root) 新快照),而后新旧两快照在 ::view-transition-image-pair(root) 容器中完成转场动画的过渡。动画结束后则删除其相关伪元素 (快照和容器)

过渡动画效果

我们可以应用一下这个 API

现在去切换主题颜色,发现有过渡效果了~

圆形扩散过渡动画

接下来实现圆形过渡的效果,其实这个动画最终是展示::view-transition-new(root)这个伪元素,所以我们只需要让这个伪元素有原型扩散的过渡动画即可~

那圆形扩散动画咋做呢?其实很简单,只需要将伪元素的半径,从0 -> 100%即可

代码如下:

并且我们需要取消掉 document.startViewTransition默认的动画效果,不然它会导致我们自定义的动画效果无效~


最终得到圆形扩散的效果

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <style>
    :root {
      /* 默认亮主题 */
      --bg-color: #fff;
      background-color: var(--bg-color);
    }

    :root.dark {
      /* 暗主题 */
      --bg-color: #000;
    }

    ::view-transition-new(root),
    ::view-transition-old(root) {
      /* 关闭默认动画 */
      animation: none;
    }
  </style>
</head>

<body>
  <button id="themeButton">切换主题</button>
  <script>
    const themeButton = document.getElementById("themeButton");
    themeButton.addEventListener("click", (e) => {
      // 执行切换主题的操作
      const transition = document.startViewTransition(() => {
        // 动画过渡切换主题色
        document.documentElement.classList.toggle("dark");
      });

      // document.startViewTransition 的 ready 返回一个 Promise
      transition.ready.then(() => {
        // 获取鼠标的坐标
        const { clientX, clientY } = e;

        // 计算最大半径
        const radius = Math.hypot(
          Math.max(clientX, innerWidth - clientX),
          Math.max(clientY, innerHeight - clientY)
        );

        // 圆形动画扩散开始
        document.documentElement.animate(
          {
            clipPath: [
              `circle(0% at ${clientX}px ${clientY}px)`,
              `circle(${radius}px at ${clientX}px ${clientY}px)`,
            ],
          },
          // 设置时间,已经目标伪元素
          {
            duration: 500,
            pseudoElement: "::view-transition-new(root)",
          }
        );
      });
    });
  </script>
</body>

</html>

<think>嗯,用户想要在Vue3结合Element Plus封装一个Layout组件,结构是左边导航栏、面包屑,可折叠,右边上面是Header,下面是内容页。首先,我需要回忆一下Element Plus的组件库,特别是布局和导航相关的部分。 首先,布局方面,Element Plus有Container布局容器,包含el-container、el-header、el-aside、el-main这些组件,可以用来搭建整体结构。左边导航栏应该用el-aside,右边分成上下两部分,el-header和el-main。不过用户还提到了面包屑,这个可能需要使用el-breadcrumb组件,放在Header部分或者导航栏附近。 然后是导航菜单,Element Plus的el-menu组件支持垂直和水平模式,折叠功能可能需要使用collapse属性。记得菜单的数据可能需要通过v-for动态生成,使用路由配置或者自定义的数据结构。折叠按钮的话,可能需要一个触发按钮,点击后切换isCollapse的状态,进而控制el-menu的collapse属性。 面包屑的部分,用户希望放在左边导航栏里?或者右边Header里?通常面包屑是在内容区域的顶部,不过需要确认用户的具体需求。如果是左边导航栏可折叠,可能面包屑在Header区域更合适。比如右边上方是Header,里面包含折叠按钮、面包屑和用户信息等。 接下来考虑路由切换和内容显示,内容区域需要使用router-view来展示不同的页面组件。所以整个Layout组件的结构应该是外层用Container布局,左边el-aside包含导航菜单,右边el-container包含el-header和el-main,el-main里放router-view。 另外,折叠功能需要同步处理el-aside的宽度变化,当折叠时,宽度可能从200px变为64px,或者更小,可以通过绑定:width属性,根据isCollapse的值动态调整。同时,菜单的collapse属性也要绑定这个状态。 面包屑组件el-breadcrumb需要根据当前路由动态显示路径,可能需要使用vue-router的路由匹配信息,比如$route.matched来生成面包屑的项。或者用户可能需要自己维护一个面包屑的数据结构,根据路由变化更新。 样式方面,可能需要固定Header的高度,设置侧边栏的宽度过渡效果,让折叠看起来平滑。还有,Header部分可能需要flex布局来排列折叠按钮、面包屑和用户信息,使其左右对齐。 最后,封装这个Layout组件需要考虑可复用性,比如通过插槽让用户自定义Header内容或者导航菜单的内容。或者提供props来控制是否显示面包屑、折叠按钮的位置等。 可能还需要处理响应式的问题,比如在小屏幕下自动折叠菜单,不过用户暂时没提,可能先不考虑。 总结步骤:搭建布局结构,集成导航菜单和折叠功能,添加面包屑,设置路由视图,处理样式和动态交互。</think>我将分步骤为您讲解如何基于Vue3+Element Plus实现Layout组件封装: 一、基础结构搭建 ```html <template> <el-container class="layout-container"> <!-- 左侧导航区 --> <el-aside :width="isCollapse ? '64px' : '200px'"> <div class="logo">{{ isCollapse ? 'Logo' : 'System Name' }}</div> <el-menu :collapse="isCollapse" :collapse-transition="false" router unique-opened > <!-- 菜单项通过v-for循环生成 --> <el-sub-menu v-for="item in menuList" :key="item.path" :index="item.path"> <template #title> <el-icon><component :is="item.icon"/></el-icon> <span>{{ item.title }}</span> </template> <el-menu-item v-for="subItem in item.children" :key="subItem.path" :index="subItem.path" > {{ subItem.title }} </el-menu-item> </el-sub-menu> </el-menu> </el-aside> <!-- 右侧内容区 --> <el-container> <el-header> <!-- Header区域 --> <div class="header-left"> <el-icon @click="toggleCollapse"> <Expand v-if="isCollapse" /> <Fold v-else /> </el-icon> <el-breadcrumb separator="/"> <el-breadcrumb-item v-for="(item, index) in breadcrumbList" :key="index" > {{ item.meta.title }} </el-breadcrumb-item> </el-breadcrumb> </div> <div class="user-info">用户信息</div> </el-header> <el-main> <!-- 内容区域 --> <router-view v-slot="{ Component }"> <transition name="fade"> <component :is="Component" /> </transition> </router-view> </el-main> </el-container> </el-container> </template> ``` 二、核心功能实现 1. 折叠功能 ```javascript const isCollapse = ref(false) const toggleCollapse = () => { isCollapse.value = !isCollapse.value } ``` 2. 动态面包屑(使用vue-router) ```javascript import { useRoute } from 'vue-router' const route = useRoute() const breadcrumbList = computed(() => { return route.matched.filter(item => item.meta?.title) }) ``` 3. 菜单数据示例 ```javascript const menuList = ref([ { path: '/system', title: '系统管理', icon: 'Setting', children: [ { path: '/user', title: '用户管理' }, { path: '/role', title: '角色管理' } ] } ]) ``` 三、样式优化建议 ```css /* 布局样式 */ .layout-container { height: 100vh; .el-aside { transition: width 0.3s; background: #304156; .logo { height: 60px; display: flex; align-items: center; justify-content: center; color: white; } } .el-header { display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid #eee; } } /* 菜单样式 */ .el-menu { border-right: none; background: #304156; :deep(.el-sub-menu__title), :deep(.el-menu-item) { color: #bfcbd9; &:hover { background: #263445 } } } ``` 四、扩展建议 1. 添加权限控制:通过v-if动态渲染菜单项 2. 响应式处理:监听窗口大小自动折叠菜单 3. 路由缓存:配合keep-alive提升切换体验 4. 主题切换:通过CSS变量实现动态换肤 这个布局方案的特点: - 使用Element Plus的Container布局容器 - 导航菜单支持多级嵌套 - 平滑的折叠过渡动画 - 自动生成面包屑导航 - 内置路由视图切换 - 完善的样式隔离方案 实际开发中建议将菜单数据抽离为独立文件,并通过Pinia/Vuex进行状态管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值