详细讲解 Vue3 路由组件的动态动效(路由动画)

1. 基础路由动画实现

<!-- App.vue -->
<template>
  <!-- 
    router-view 的 v-slot 可以获取到:
    - Component:要渲染的组件
    - route:当前路由信息
  -->
  <router-view v-slot="{ Component, route }">
    <!-- 
      transition 组件用于添加过渡效果
      name:过渡效果的名称,对应 CSS 类名前缀
      mode:过渡模式
        - out-in:旧内容先消失,新内容再出现
        - in-out:新内容先出现,旧内容再消失
    -->
    <transition 
      name="fade" 
      mode="out-in"
    >
      <!-- 
        动态组件,用于渲染路由对应的组件
        :key 可以强制组件重新渲染
      -->
      <component 
        :is="Component" 
        :key="route.path" 
      />
    </transition>
  </router-view>
</template>

<style>
/* 进入和离开的过渡效果 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

/* 
  进入前和离开后的状态
  opacity: 0 表示完全透明
*/
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

/* 
  进入后和离开前的状态
  opacity: 1 表示完全不透明
*/
.fade-enter-to,
.fade-leave-from {
  opacity: 1;
}
</style>

2. 多种过渡效果

<template>
  <router-view v-slot="{ Component, route }">
    <!-- 根据路由元信息选择不同的过渡效果 -->
    <transition 
      :name="route.meta.transition || 'fade'" 
      mode="out-in"
    >
      <component :is="Component" :key="route.path" />
    </transition>
  </router-view>
</template>

<style>
/* 1. 淡入淡出效果 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

/* 2. 滑动效果 */
.slide-enter-active,
.slide-leave-active {
  transition: all 0.5s ease;
}
/* 从右侧滑入 */
.slide-enter-from {
  transform: translateX(100%);
}
/* 向左侧滑出 */
.slide-leave-to {
  transform: translateX(-100%);
}

/* 3. 缩放效果 */
.scale-enter-active,
.scale-leave-active {
  transition: all 0.5s ease;
}
.scale-enter-from,
.scale-leave-to {
  transform: scale(0.9);
  opacity: 0;
}
</style>

3. 路由配置示例

// router/index.js
const routes = [
  {
    path: '/',
    component: Home,
    // 在路由元信息中指定过渡效果
    meta: {
      transition: 'fade',
      // 可以指定更多配置
      transitionMode: 'out-in',
      transitionDuration: 500
    }
  },
  {
    path: '/about',
    component: About,
    meta: {
      transition: 'slide'
    }
  },
  {
    path: '/contact',
    component: Contact,
    meta: {
      transition: 'scale'
    }
  }
]

4. 动态过渡效果(根据导航方向)

<template>
  <router-view v-slot="{ Component }">
    <transition 
      :name="transitionName"
      mode="out-in"
    >
      <component :is="Component" :key="$route.path" />
    </transition>
  </router-view>
</template>

<script setup>
import { ref, watch } from 'vue'
import { useRouter } from 'vue-router'

const router = useRouter()
const transitionName = ref('slide-right')

// 监听路由变化,根据导航深度决定动画方向
watch(
  () => router.currentRoute.value,
  (to, from) => {
    // 获取路由深度
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length

    // 根据深度变化决定动画方向
    transitionName.value = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
)
</script>

<style>
/* 向右滑动 */
.slide-right-enter-active,
.slide-right-leave-active {
  transition: all 0.5s ease;
}
.slide-right-enter-from {
  transform: translateX(-100%);
}
.slide-right-leave-to {
  transform: translateX(100%);
}

/* 向左滑动 */
.slide-left-enter-active,
.slide-left-leave-active {
  transition: all 0.5s ease;
}
.slide-left-enter-from {
  transform: translateX(100%);
}
.slide-left-leave-to {
  transform: translateX(-100%);
}
</style>

5. 实际应用场景

<!-- 移动端页面切换效果 -->
<template>
  <router-view v-slot="{ Component, route }">
    <!-- 
      移动端常见的页面切换效果:
      1. 前进:从右向左滑入
      2. 后退:从左向右滑入
      3. 层级切换:缩放效果
    -->
    <transition 
      :name="getTransitionName(route)"
      mode="out-in"
      @before-enter="onBeforeEnter"
      @enter="onEnter"
      @leave="onLeave"
    >
      <component :is="Component" :key="route.path" />
    </transition>
  </router-view>
</template>

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'

const router = useRouter()
const routeHistory = ref([]) // 记录路由历史

// 根据路由历史判断是前进还是后退
const getTransitionName = (route) => {
  const currentIndex = routeHistory.value.indexOf(route.path)
  const lastRoute = routeHistory.value[routeHistory.value.length - 1]
  
  // 更新路由历史
  routeHistory.value.push(route.path)
  
  // 判断导航方向
  if (currentIndex === -1) {
    // 新路由:前进
    return 'slide-left'
  } else if (currentIndex < routeHistory.value.indexOf(lastRoute)) {
    // 后退
    return 'slide-right'
  } else {
    // 层级切换
    return 'scale'
  }
}

// 动画钩子
const onBeforeEnter = (el) => {
  // 可以在这里添加初始样式
  el.style.opacity = 0
}

const onEnter = (el, done) => {
  // 可以使用 GSAP 等动画库
  gsap.to(el, {
    opacity: 1,
    duration: 0.5,
    onComplete: done
  })
}

const onLeave = (el, done) => {
  gsap.to(el, {
    opacity: 0,
    duration: 0.5,
    onComplete: done
  })
}
</script>

6. 使用建议

1.选择合适的过渡模式

// 1. out-in:适合大多数场景,避免内容重叠
mode: 'out-in'

// 2. in-out:特殊效果,新内容从旧内容上方滑入
mode: 'in-out'

// 3. 默认:同时进行,可能造成内容重叠
mode: undefined

2.控制过渡时间

/* 不要设置太长的过渡时间,影响用户体验 */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease; /* 建议 300-500ms */
}

3.处理过渡过程中的交互

// 禁用过渡期间的点击事件
const isTransitioning = ref(false)

const onBeforeEnter = () => {
  isTransitioning.value = true
}

const onAfterEnter = () => {
  isTransitioning.value = false
}

这些示例涵盖了 Vue3 路由动画的主要使用场景:

  • 基础页面切换动画
  • 方向感知的动画
  • 移动端常见过渡效果
  • 自定义动画效果

记住要注意:

  • 动画时长要适中
  • 选择合适的过渡模式
  • 考虑性能影响
  • 移动端和桌面端可能需要不同的动画效果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值