Frontend Development 14 min read

Implementing Page Transition Animations in Vue Router (Mimicking Douyin App)

This article explains how to use Vue Router and the Transition component to create forward and backward page‑slide animations that mimic the Douyin app, covering router initialization, route definitions, nested routes, CSS animation rules, and the logic for detecting navigation direction.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implementing Page Transition Animations in Vue Router (Mimicking Douyin App)

With the improvement of mobile device performance, user experience of mobile apps has become smoother, and developers now aim to bring similar fluid page‑switching animations to web applications.

Although modern web pages have evolved far beyond the jQuery era, many still rely on UI libraries for basic animations such as modal dialogs. This is the third article in a series that imitates Douyin, focusing on optimizing user experience by implementing page‑transition animations and discussing the underlying principles and pitfalls.

Final Effect

Online preview: dy.ttentau.top/

GitHub repository: github.com/zyronon/douyin

Key source files: src/router/routes.ts and src/App.vue

1. Router Usage

1.1 Initialize Router

import Vue from 'vue'
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes,
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { top: 0 }
    }
  }
})

... // other setup code

const app = createApp(App)
app.use(router)

1.2 Define Routes

Static imports (using import at the top of the file) bundle all components into a single JavaScript file, while dynamic imports load each component on demand and generate separate chunks.

import Home from '../pages/home/index.vue'

Dynamic import example:

{ path: '/home', component: () => import('@/pages/home/index.vue') },

When many routes are defined, each dynamic component creates its own chunk; you can configure Vite or Vue CLI to group chunks as needed.

1.3 Router Outlet

<router-view></router-view>

The <router-view> tag renders the component matched by the current route. Placing it in App.vue makes all top‑level routes available.

1.4 Nested Routes

For admin panels or management systems, nested routes are defined by adding a children array to a parent route.

{
  path: '/layout',
  component: Layout,
  children: [
    { path: '/layout-child1', component: LayoutChild1 },
    { path: '/layout-child2', component: LayoutChild1 },
    { path: '/layout-child3', component: LayoutChild1 }
  ]
}

The child routes also need a <router-view> inside the parent component (e.g., Layout.vue ) to render the matched child component.

2. Transition Animation

Vue provides a built‑in Transition component. Combined with CSS transform and transition properties, we can slide pages horizontally.

2.1 Transition Component

<router-view v-slot="{ Component }">
  <transition :name="transitionName">
    <component :is="Component" />
  </transition>
</router-view>
<transition name="transitionName">
  <router-view></router-view>
</transition>

The name attribute determines which CSS classes Vue adds during the animation lifecycle (e.g., test-enter-from , test-enter-active , etc.).

2.2 Forward Animation CSS

// Final state (center)
.go-enter-to,
.go-leave-from { transform: translate3d(0, 0, 0); }

// Duration
.go-enter-active,
.go-leave-active { transition: all 0.3s; }

// Leaving page moves left
.go-leave-to { transform: translate3d(-100%, 0, 0); }

// Entering page starts from right
.go-enter-from { transform: translate3d(100%, 0, 0); }

2.3 Backward Animation CSS

.back-enter-to,
.back-enter-from { transform: translate3d(0, 0, 0); }
.back-enter-active,
.back-leave-active { transition: all 0.3s; }
.back-enter-from { transform: translate3d(-100%, 0, 0); }
.back-leave-to { transform: translate3d(100%, 0, 0); }

The forward animation slides the current page left and the next page from right to center; the backward animation does the opposite.

2.4 Determining Navigation Direction

We watch the reactive $route object. By comparing the index of to.path and from.path in the predefined routes array, we can decide whether the navigation is forward ( go ) or backward ( back ).

// Vue 2 example
watch: {
  '$route'(to, from) {
    const noAnimation = ['/', '/home', '/slide', '/me', '/attention', '/message', '/publish'];
    if (noAnimation.indexOf(from.path) !== -1 && noAnimation.indexOf(to.path) !== -1) {
      return this.transitionName = '';
    }
    const toDepth = routes.findIndex(v => v.path === to.path);
    const fromDepth = routes.findIndex(v => v.path === from.path);
    this.transitionName = toDepth > fromDepth ? 'go' : 'back';
  }
},
// Vue 3 example
const route = useRoute();
watch(
  () => route.path,
  (to, from) => {
    const noAnimation = ['/', '/home', '/slide', '/me', '/attention', '/message', '/publish'];
    if (noAnimation.includes(from) && noAnimation.includes(to)) {
      return (transitionName.value = '');
    }
    const toDepth = routes.findIndex(v => v.path === to);
    const fromDepth = routes.findIndex(v => v.path === from);
    transitionName.value = toDepth > fromDepth ? 'go' : 'back';
  }
);

Summary

By configuring Vue Router, defining static and dynamic routes, adding a <router-view> outlet, and using the Transition component with appropriate CSS, you can achieve smooth forward and backward page‑slide animations similar to the Douyin app. Adjust the CSS classes to create other animation styles as needed.

Further topics such as page caching are omitted for brevity and will be covered in a separate article.

frontendanimationJavaScriptVueroutertransition
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.