阿里云主机折上折
  • 微信号
Current Site:Index > Routing transition animation changes

Routing transition animation changes

Author:Chuan Chen 阅读数:59282人阅读 分类: Vue.js

Route Transition Animation Variations

Route transition animations are a crucial means of enhancing user experience in Vue.js applications. Through well-designed animations, page transitions can become more natural and fluid, guiding user attention while maintaining application continuity. Vue Router seamlessly integrates with Vue's transition system, offering multiple ways to implement route transitions.

Basic Route Transition Implementation

The simplest route transition can be achieved using Vue's <transition> component. When routes switch, Vue automatically adds enter/leave transition class names to the old and new components:

<router-view v-slot="{ Component }">
  <transition name="fade" mode="out-in">
    <component :is="Component" />
  </transition>
</router-view>

Corresponding CSS styles:

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

This basic transition suits most simple scenarios, where the transition property can be adjusted to control animation duration, easing functions, and other parameters.

Dynamic Transition Effects

Different transition effects can be applied based on route navigation direction, requiring a combination of Vue Router's navigation guards and component state:

// router.js
const router = createRouter({
  history: createWebHistory(),
  routes: [...],
})

router.beforeEach((to, from) => {
  const toDepth = to.meta.depth || 0
  const fromDepth = from.meta.depth || 0
  to.meta.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
})

Then use dynamic transition names in the component:

<router-view v-slot="{ Component, route }">
  <transition :name="route.meta.transitionName || 'fade'">
    <component :is="Component" />
  </transition>
</router-view>

Corresponding CSS:

.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
  transition: all 0.5s ease;
}

.slide-left-enter-from {
  transform: translateX(100%);
}

.slide-left-leave-to {
  transform: translateX(-100%);
}

.slide-right-enter-from {
  transform: translateX(-100%);
}

.slide-right-leave-to {
  transform: translateX(100%);
}

Transition Control Based on Route Meta Information

The meta field in routes allows finer control over transition behavior for each route:

const routes = [
  {
    path: '/',
    component: Home,
    meta: {
      transition: 'zoom'
    }
  },
  {
    path: '/about',
    component: About,
    meta: {
      transition: 'fade'
    }
  }
]

Usage in components:

<router-view v-slot="{ Component, route }">
  <transition :name="route.meta.transition || 'fade'">
    <component :is="Component" />
  </transition>
</router-view>

Combining Transitions and Animations

Vue's transition system supports using both CSS transitions and animations simultaneously, which is useful for more complex effects:

<transition 
  name="bounce"
  enter-active-class="animate__animated animate__bounceIn"
  leave-active-class="animate__animated animate__bounceOut"
>
  <router-view />
</transition>

Here, the Animate.css library is used, but custom animations can also be created:

@keyframes slideIn {
  from { transform: translateY(20px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@keyframes slideOut {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(-20px); opacity: 0; }
}

.slide-enter-active {
  animation: slideIn 0.4s forwards;
}

.slide-leave-active {
  animation: slideOut 0.4s forwards;
}

Composite Transitions for Lists and Routes

When route transitions involve list item changes, richer effects can be achieved by combining <transition-group>:

<router-view v-slot="{ Component }">
  <transition name="page" mode="out-in">
    <component :is="Component" />
  </transition>
</router-view>

Inside child components:

<transition-group name="list" tag="ul">
  <li v-for="item in items" :key="item.id">
    {{ item.text }}
  </li>
</transition-group>

Corresponding styles:

.page-enter-active, .page-leave-active {
  transition: all 0.3s;
}
.page-enter-from, .page-leave-to {
  opacity: 0;
  transform: scale(0.95);
}

.list-move,
.list-enter-active,
.list-leave-active {
  transition: all 0.5s ease;
}

.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

.list-leave-active {
  position: absolute;
}

Complex Transitions Using JavaScript Hooks

For programmatically controlled complex transitions, JavaScript hooks can be used:

<router-view v-slot="{ Component }">
  <transition
    :css="false"
    @before-enter="beforeEnter"
    @enter="enter"
    @leave="leave"
  >
    <component :is="Component" />
  </transition>
</router-view>

JavaScript section:

methods: {
  beforeEnter(el) {
    el.style.opacity = 0
    el.style.transform = 'scale(0.9)'
  },
  enter(el, done) {
    gsap.to(el, {
      opacity: 1,
      scale: 1,
      duration: 0.5,
      ease: 'power2.out',
      onComplete: done
    })
  },
  leave(el, done) {
    gsap.to(el, {
      opacity: 0,
      scale: 1.1,
      duration: 0.3,
      ease: 'power2.in',
      onComplete: done
    })
  }
}

Here, the GSAP library is used for finer animation control, but the native Web Animations API can also be used.

Performance Optimization for Route Transitions

Complex route transitions may impact application performance, so the following points should be noted:

  1. Use CSS hardware acceleration whenever possible:
.transform-layer {
  will-change: transform;
  backface-visibility: hidden;
  perspective: 1000px;
}
  1. Avoid animating too many elements simultaneously; use the appear attribute to control initial render animations:
<transition appear @before-appear="customBeforeAppear">
  <!-- content -->
</transition>
  1. For complex scenarios, consider using <keep-alive> to cache component state:
<router-view v-slot="{ Component }">
  <transition name="fade" mode="out-in">
    <keep-alive>
      <component :is="Component" />
    </keep-alive>
  </transition>
</router-view>

Handling Nested Route Transitions

Nested routes require special handling of transition effects to ensure coordination between parent and child route animations:

<router-view v-slot="{ Component, route }">
  <transition :name="route.meta.transition || 'fade'">
    <component :is="Component" />
  </transition>
</router-view>

In child route components:

<router-view v-slot="{ Component }" class="child-view">
  <transition name="slide-up">
    <component :is="Component" />
  </transition>
</router-view>

Corresponding styles should ensure correct hierarchy:

.child-view {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}

.slide-up-enter-active,
.slide-up-leave-active {
  transition: all 0.3s ease-out;
}

.slide-up-enter-from {
  transform: translateY(20px);
  opacity: 0;
}

.slide-up-leave-to {
  transform: translateY(-20px);
  opacity: 0;
}

Combining Route Transitions with State Management

Storing transition states in Vuex or Pinia enables global unified transition control:

// store/transition.js
export const useTransitionStore = defineStore('transition', {
  state: () => ({
    type: 'fade',
    duration: 300
  }),
  actions: {
    setTransition(payload) {
      this.type = payload.type
      this.duration = payload.duration
    }
  }
})

Usage in components:

<script setup>
import { useTransitionStore } from '@/stores/transition'
const transition = useTransitionStore()
</script>

<template>
  <router-view v-slot="{ Component }">
    <transition 
      :name="transition.type"
      :duration="transition.duration"
      mode="out-in"
    >
      <component :is="Component" />
    </transition>
  </router-view>
</template>

Responsive Route Transitions

Dynamically adjust transitions based on viewport size or user preferences:

// Detect user preference
const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)'
).matches

// In components
const transitionName = ref(prefersReducedMotion ? 'fade' : 'slide')

watch(() => route.path, () => {
  if (prefersReducedMotion) return
  
  // Dynamically adjust transitions based on route changes
  if (route.path === '/about') {
    transitionName.value = 'zoom'
  } else {
    transitionName.value = 'slide'
  }
})

Advanced Route Transition Patterns

For scenarios requiring more complex control, combine Vue's render functions with custom directives:

app.directive('route-transition', {
  mounted(el, binding) {
    const { value } = binding
    el.style.transition = `all ${value.duration}ms ${value.easing}`
  },
  updated(el, binding) {
    const { value, oldValue } = binding
    if (value.active !== oldValue.active) {
      if (value.active) {
        el.classList.add('enter-active')
        el.classList.remove('leave-active')
      } else {
        el.classList.add('leave-active')
        el.classList.remove('enter-active')
      }
    }
  }
})

Using custom transition components:

const RouteTransition = {
  functional: true,
  render(h, { children }) {
    const data = {
      props: {
        name: 'custom-transition',
        mode: 'out-in'
      },
      on: {
        beforeEnter(el) {
          // Custom logic
        },
        afterEnter(el) {
          // Custom logic
        }
      }
    }
    return h('transition', data, children)
  }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.