vue-router4过度动画无效解决方案

推荐 23619次阅读 1820人点赞 作者: WuBin 发布时间: 2021-02-23 13:37:20
扫码到手机查看

在初次使用vue3 + vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操作配置都成了过去式了。所以借手头正在做的项目,进行简单的总结。

官方给出的结构

开始前,请仔细阅读vue-router-transition使用的官方文档https://next.router.vuejs.org/zh/guide/advanced/transitions.html

在 Vue Router API 从 v3(Vue2)到 v4(Vue3)的重写过程中,大部分的 Vue Router API 都没有变化,但是在迁移你的程序时,你可能会遇到一些破坏性的变化。

keep-alive和transition的变化官方说明

transitionkeep-alive现在必须通过v-slotAPI 在RouterView内部使用:

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

关于内置组件<component :is>请见我的另一篇文章component加:is实现动态组件的渲染

Component就是作用域插槽中的一个属性,这个是由router-view这个组提供的 ,你可以查看一下插槽作用域这部分文档https://cn.vuejs.org/v2/guide/components-slots.html#作用域插槽,Component就是你的路由表中的路由组件;为什么必须是Component可以查看文档https://next.router.vuejs.org/api/#route

router/index.js中对路由的配置

import { createRouter, createWebHashHistory } from 'vue-router';
import Detail from 'components/detail/detail';
import MainList from 'components/main-list/main-list';

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
   // 定义当访问的时候,默认跳转到的路由
    {
      path: '/',
      redirect: '/home'
    },
    {
      path: '/home',
      name: 'mainlist',
      component: MainList,
      // 路由元信息定义每个路由进入退出的不同动画
      meta: { transition: 'aside-right' }
    },
    {
      path: '/detail',
      name: 'detail',
      component: Detail,
      meta: { transition: 'aside-right' }
    }
  ]
});

export default router;

关于过度动画不生效

过度动画不生效情况可能有两种:

1、transition样式不正确,没加appear(https://v3.cn.vuejs.org/api/built-in-components.html#transition apper属性等详解);

2、组件上没有加keep-alive;

组件上没有加keep-alive的时候,会出现进入的动画正常,而退出时候的动画无效;从DOM结构上看就是DOM节点一瞬间被删除了;

transition样式不正确可能导致进入动画无效,但是退出动画有效,组件会一瞬间显示;

综合上面的情况,加上本人在项目中实践(如vue-router写在App.vue中):

<router-view v-slot="{ Component }">
     <transition name="aside-right" appear>
            <!--  加入keep-alive保证进入退出都有动画 -->
            <!--  exclude排除缓存的组件,让该detail组件不缓存数据 -->
            <keep-alive exclude="detail">
              <component :is="Component" />
            </keep-alive>
     </transition>
</router-view>

这里detail是组件文件名,如果组件名是singer-detail.vue,那么这里就填写:

<keep-alive exclude="singer-detail">

从右边进入/退出的样式

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

.aside-right-enter-from,
.aside-right-leave-to {
    transform: translate(100%, 0);
}

关于如何配置vue-router4 请见另一篇文章  vue-router4使用

当然也可以使用路由元信息定义每个组件的过度动画:

<!-- 这里Component就是指的router中注册的组件, route就是每个路由配置的数组routes -->
    <router-view v-slot="{ Component, route }">
      <transition :name="route.meta.transition" appear>
        <!--  加入keep-alive保证进入退出都有动画 -->
        <!--  exclude排除缓存的组件,让detail组件不缓存数据 -->
        <keep-alive exclude="detail">
          <component :is="Component" @closeDetail=".." :all="传入参数"/>
        </keep-alive>
      </transition>
    </router-view>

实现仿原生APP页面过度效果:左侧页面向右滑入,底部页面向左偏移

让我们放慢动画执行时间,先看一下,当路由切换时发生了什么:

.aside-right-enter-from,
.aside-right-leave-to {
  // 进入和退出时候,底部的页面(组件执行的动画)
  &.main-list{
    transform: translate(-10%, 0);
  }
  // 当执行动画时 对主页和详细页区别对待
  &.detail{
    transform: translate(100%, 0);
  }
}

(补充)进入动画生效,移除动画无效

我还遇到一种情况,就是进入时候动画生效,路由返回的时候动画无效,但是在路由上加上keep-alive(缓存)就会生效,效果表现是直接将节点元素删除而不执行动画的情况。具体效果如下(如查看不了,请点击此处的备用链接):

可以看到,进入的时候动画正常,但是退出的时候,瞬间将singer-detail的DOM节点删除了,导致动画不生效。奇怪的是,如果在路由上加上keep-alive,动画会正常进入退出。

singer组件:

 <router-view v-slot="{ Component }">
    <transition appear name="slide">
    <!-- 
    仅仅加上<keep-alive>缓存结果就会正常执行进入、退出动画
    如果一旦加上exclude或者不加keep-alive就会直接删除DOM不执行退出动画
    -->
     <keep-alive exclude="singerDetail">
        <component :is="Component"
                   :singer="selectedSinger"
        ></component>
     </keep-alive>
    </transition>
</router-view>

下面来看一下这个问题产生的原因,很奇妙,竟然跟一句注释有关,先来看一下组件之间的关联:

{
    path: '/singer',
    component: Singer,
    children: [
      {
        path: ':id',
        component: SingerDetail
      }
    ]
  },

singer组件(父组件)

<router-view v-slot="{ Component }">
  <transition appear name="slide">
    <!-- <keep-alive exclude="singerDetail">
     保留或者去掉切换组件时要重执行created()
     -->
      <component :is="Component"
                 :singer="selectedSinger"
      ></component>
    <!-- </keep-alive>-->
  </transition>
</router-view>

singerDetail组件:

<template>
  <!-- 因为通过二级路由实现,所以放在views下 注意!就是这条注释!!不要在这个位置加任何注释! -->
  <section class="singer-detail">
    <music-list
      :songs="songs"
      :title="title"
      :pic="pic"
      :loading="loading"
    ></music-list>
  </section>
</template>

这里在singer-detail组件中,又引入了一个Music-list组件。我们可以发现 在最外层section上面有一条注释!造成退出动画失效的元凶就是它!!如果大家像我一样喜欢加注释,不要在template的第一层加注释!

<template>
  <section class="singer-detail">
    <!-- 因为通过二级路由实现,所以放在views下  这样就没问题了-->
    <music-list

要像上面一样,切记不要直接在template的第一层直接加注释,会导致transition动画无效!!如果你也遇到类似问题,不妨检查一下这个点。感谢ustb黄轶老师。

具体原因先留个坑,以后再更新。

关于keep-alive

<keep-alive>是Vue的一个内部组件,适合用来缓存不需要实时更新的组件,这样可以保留组件状态避免重新渲染。keep-alive是一个缓存的机制,keep-alive要配合router-view使用

参数:

  • include :接受字符串或正则表达式,这里是需要被缓存的组件名
  • exclude :接受字符串或正则表达式,这里是不需要缓存的组件名
  • max :接受数字,最多可以缓存多少组件实例

使用keep-alive后,会导致一个问题比如详细页,是需要根据请求的ID重新获取数据的,而keep-alive会让组件保存状态,在需要重新请求数据的时候,依然走的缓存。从而导致了数据的不更新

这时候就需要使用include或者exclude参数,根据定义路由时候,其中组件的name,进行筛选

keep-alive缓存时include中的名字必须与组件上的名字完全一致,组件没有写名字或者名字不一致就会导致缓存失效,每次进入组件都触发created生命周期
// 全局组件中
<keep-alive include="history">
      <router-view></router-view>
</keep-alive>
组件中
export default {
  name: "history",/*此处的name必须有且与include中的一致*/
  components: {
    VTable
},

include使该标签作用于所有name属性的值跟此标签 include的属性值一致的vue页面

exclude使该标签不作用于所有name属性的值跟此标签 exclude的属性值一致的vue页面

使用include/exclude 属性需要给所有vue类的name赋值(注意不是给route的name赋值),否则 include/exclude不生效

比如:

export default {
 name:'a', // include 或 exclude所使用的name
 data () {
 return{
    }
  },
}
 // 保持 name为a和b的组件
<keep-alive include="a,b">
        <router-view/> vue2.0写法
</keep-alive>

vue2.0版本后,keep-alive内置组件已经封装了两个属性,include和exclude表示那些组件需要缓存那些组件不需要缓存,用法大致如下:

<keep-alive include="test-keep-alive">
  <!-- 将缓存name为test-keep-alive的组件 -->
  <component></component>
</keep-alive>
 
<keep-alive include="a,b">
  <!-- 将缓存name为a或者b的组件,结合动态组件使用 -->
  <component :is="view"></component>
</keep-alive>
 
<!-- 使用正则表达式,需使用v-bind -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>
 
<!-- 动态判断 -->
<keep-alive :include="includedComponents">
  <router-view></router-view>
</keep-alive>
 
<keep-alive exclude="test-keep-alive">
  <!-- 将不缓存name为test-keep-alive的组件 -->
  <component></component>
</keep-alive>

路由内组件派发事件的监听以及传递值

<router-view v-slot="{ Component }">
          <transition name="aside-right" appear>
            <!--  加入keep-alive保证进入退出都有动画 -->
            <!--  exclude排除缓存,让其不缓存数据 -->
            <keep-alive exclude="detail">
              <!-- 监听组件内派发的closeDetail事件 -->
              <component :is="Component"  @closeDetail="indexShareConfig" :all="要传递的数据"/>
            </keep-alive>
          </transition>
</router-view>

detail.vue组件

methods: {
    closeDetail() {
      // 关闭时候向外发送事件
      this.$emit('closeDetail');
    },
}

相关资料

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:keep-alivevue-router
推荐阅读
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    8337次阅读 531人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • Vue

    盘点Vue2和Vue3的10种组件通信方式

    Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异;本文将通过选项式API组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式。

    3474次阅读 255人点赞 发布时间: 2022-08-19 09:40:16 立即查看
  • JS

    几个高级前端常用的API

    推荐4个前端开发中常用的高端API,分别是MutationObserver、IntersectionObserver、getComputedstyle、getBoundingClientRect、requ...

    13422次阅读 867人点赞 发布时间: 2021-11-11 09:39:54 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    12217次阅读 392人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    10562次阅读 846人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    14437次阅读 1153人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    14342次阅读 1167人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    27483次阅读 2157人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    23619次阅读 1820人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录