通过<RouterView/>来切换页面组件时,transition如何生效?

场景

在使用Vue提供的transition组件来实现页面切换时的过渡效果时,直接使用了transition来包裹路由,结果发现了一个问题,新页面进入时的动画效果成功实现了,而旧页面离开的动画却失效了。

子页面1:

Page1.Vue 复制代码
<template>
    <div class="page1">
        page1
    </div>
</template>

<style scoped>
.page1 {
    width: 100%;
    height: 100%;
    border: 1px solid #000;
    background-color: pink;
    text-align: center;
    font-size: 50px;
}
</style>

子页面2:

Page2.vue 复制代码
<template>
    <div class="page2">
        page2
    </div>
</template>

<style scoped>
.page2 {
    width: 100%;
    height: 100%;
    background-color: blue;
    text-align: center;
    font-size: 50px;
}
</style>

主页面:

App.vue 复制代码
<template>
<div class="container">
      <div class="tabs">
    <router-link to="/page1">page1</router-link>
    <router-link to="/page2">page2</router-link>
  </div>
  <div class="page">
      <transition name="fade" mode="out-in">
          </router-view>
      </transition>
  </div>
</div>
</template>

<style>
.container {
  margin: 0 auto;
  width: 800px;
  height: 600px;
  border: 1px solid #000;
}
.page {
  width: 100%;
  height: calc(100% - 60px);
}
.tabs {
  height: 40px;
  width: 200px;
  margin: 0 auto;
  background: green;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 20px;
  margin-bottom: 20px;
}
a {
  color: #fff;
  font-size: 20px;
}
.fade-enter-active {
  transition: all 0.5s ease-in-out;
}
.fade-enter-from {
  opacity: 0;
  transform: translateX(100%);
}
.fade-enter-to {
  opacity: 1;
  transform: translateX(0);
}
.fade-leave-active {
  transition: all 0.5s ease-in-out;
}
.fade-leave-from {
  opacity: 1;
  transform: translateX(0);
}
.fade-leave-to {
  opacity: 0;
  transform: translateX(-100%);
}
</style>

页面效果如下: 切换页面 .fade-enter相关CSS成功执行,.fade-leave相关CSS执行失败.(如图)

解决方法

后来我从别人那获取到了解决方法:用 RouterView 包裹 Transition 配合 Component 实现过渡效果。

vue 复制代码
<template>
    <router-view v-slot="{ Component }">
      <transition>
        <component :is="Component" />
      </transition>
    </router-view>
<template/>

改为这样子后,无论是进入还是里离开都能正确执行了。

原因

Vue3 官方文档 Transition一节中,给出了transition组件的触发条件(满足其一):

  • v-if 所触发的切换
  • v-show 所触发的切换
  • 由特殊元素 <component> 切换的动态组件
  • 改变特殊的 key 属性

意思就是说<transition> 组件要正常工作,包裹的内容必须是 "可复用" 的元素或组件

问题根源:router-view 是一个 "动态渲染出口"

其关键在于router-view本身不可复用,它的核心行为如下:

  • 当路由切换时,销毁旧组件实例创建新组件实例
  • router-view 本身不会 "更新",而是直接替换内部的组件内容。

当直接写 <transition><router-view /></transition> 时,路由更新,transition还没有来得及给旧组件添加离开的效果时,旧的组件实例已经销毁了,这时新的组件实例创建,transition能够正常捕获到该组件实例。而解决方法是通过作用域插槽 "v-slot={Component}" ,把当前路由对应的组件实例暴露出来, 然后使用 component来动态渲染,由于 <component> 本身是一个 "可复用" 的容器,它不会被销毁,只是改变内部渲染的组件。可以让 <transition> 正常监听组件的 "离开" 和 "进入",从而执行完整的过渡动画。

总结

总之,路由切换过渡动画的核心是让 <transition> 能正常捕获组件的 "离开" 与 "进入" 状态(满足官方给出的触发条件)。避开直接包裹 <router-view> 的误区,同时呢也需要注意样式隔离、动画执行顺序等细节,这样就能实现完整的路由过渡效果。

相关推荐
jason_yang2 小时前
vue3中createApp多个实例共享状态
javascript·vue.js
老华带你飞2 小时前
海产品销售系统|海鲜商城购物|基于SprinBoot+vue的海鲜商城系统(源码+数据库+文档)
java·前端·数据库·vue.js·论文·毕设·海鲜商城购物系统
7***A4433 小时前
Vue自然语言处理应用
前端·vue.js·自然语言处理
徐小夕4 小时前
耗时一周,我把可视化+零代码+AI融入到了CRM系统,使用体验超酷!
javascript·vue.js·github
明教教主张5G4 小时前
Vue响应式原理(13)-ref实现原理解析
前端·vue.js
kungggyoyoyo5 小时前
TRAE中国版SOLO模式上线!我用它从0到1开发了一款AI小说编辑器
前端·vue.js·trae
什么时候吃饭5 小时前
vue2、vue3父子组件嵌套生命周期执行顺序
前端·vue.js
低保和光头哪个先来5 小时前
场景2:Vue Router 中 query 与 params 的区别
前端·javascript·vue.js·前端框架
hhcccchh6 小时前
学习vue第七天 从单页面应用(SPA)进化为后台管理系统架构
vue.js·学习·系统架构