[vue-router4进阶] 0.过渡动效

2021-11-01  本文已影响0人  林哥学前端

现在我们开始学习一些vue-router的高级一点的内容,这节课我们一起学习如何在页面跳转时添加一些过渡动效。
我们还是继续在vue-router4快速入门的例子的基础上改,先把之前的嵌套路由的代码去掉,就剩下一个简单的首页、列表页和用户详情页。
添加过渡效果需要用到vue自带的内置组件transition,transition组件的作用就是在它的里面的内容发生变化时,增加过渡效果,具体用法在这里
给页面跳转增加过渡效果的方式跟之前的版本区别比较大,这里要在router-view上使用v-slot获取对应的组件,使用component动态组件来渲染这个组件,然后用transition包裹住这个动态组件:

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

这样在页面切换时,动态组件的内容发生了变化,这里我们定义了一个名字是fade的transition,就会有一个fade的过渡效果了,不过我们需要用css定义这个fade效果:

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

transition大概就是这样一个用法,这里定义的过渡时,如果组件离开页面,就直接消失,如果组件进入页面就有个0.5秒的透明度动画。
这么写好以后,点击跳转页面,发现并没有效果。原来,使用transition时,页面的vue文件的template下必须只有一个根元素
比如index.vue应该是:

<template>
  <div class="page">
    <div>这里是首页</div>
    <router-link to="/list">点击跳转到列表页</router-link>
  </div>
</template>

只有一个根div,这样改完之后就有淡入的fade效果了。
为了效果更好一点,让每个页面都全屏大小,定位在顶部。
添加一个class,叫page

.page {
  position: absolute;
  width: 100%;
  height: 100vh;
  left: 0;
  top: 0;
}

每个页面的根元素上都加上这个class,淡入的效果就完成了。

淡入的效果还是不太好看,下面按照官网的例子,做一个进入下层页面从右边滑过来、进入上层页面从左边滑过来的例子,
这时候,transition的效果是动态的,一共两个,slide-left和slide-right,我们在route配置时候的meta里增加一个属性,表示transition的效果,默认是slide-left
router.js

  {
    path: '/index',
    component: () => import('./views/index'),
    name: 'index',
    meta: {
      title: '首页',
      keepAlive: true,
      transition: 'slide-left',  // 增加
    },
  },

然后在App.vue里面,动态设置transition的name属性:

    <router-view v-slot="{ Component, route }">
      <transition :name="route.meta.transition"> // name是动态绑定的
        <component :is="Component" />
      </transition>
    </router-view>

在router.js中增加导航守卫,动态的更改route里面meta的transition的值:

router.afterEach((to, from) => {
  // 新增
  const toDepth = to.path.split('/').length
  const fromDepth = from.path.split('/').length
  to.meta.transition = toDepth < fromDepth ? 'slide-right' : 'slide-left'
})

这样过渡的效果就是动态的了,在slide-left和slide-right之间变化,
最后在加上效果的css代码:

.slide-left-enter-active {
  transition: transform 0.5s ease;
}
.slide-left-leave-active {
  transition: none;
}
.slide-left-enter-from,
.slide-left-leave-to {
  transform: translate3d(100vw, 0, 0);
}
.slide-right-enter-active {
  transition: transform 0.5s ease;
}
.slide-right-leave-active {
  transition: none;
}
.slide-right-enter-from,
.slide-right-leave-to {
  transform: translate3d(-100vw, 0, 0);
}

这就完成了,
最后效果就是进入用户详情页,页面时从右边滑过来,从用户详情页返回,页面是从左边滑过来。
下面把整个项目的代码贴出来
App.vue

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

<script>
export default {
  name: 'App',
}
</script>

<style>
.slide-left-enter-active {
  transition: transform 0.5s ease;
}
.slide-left-leave-active {
  transition: none;
}
.slide-left-enter-from,
.slide-left-leave-to {
  transform: translate3d(100vw, 0, 0);
}
.slide-right-enter-active {
  transition: transform 0.5s ease;
}
.slide-right-leave-active {
  transition: none;
}
.slide-right-enter-from,
.slide-right-leave-to {
  transform: translate3d(-100vw, 0, 0);
}
.page {
  position: absolute;
  width: 100%;
  height: 100vh;
  left: 0;
  top: 0;
}
</style>

router.js

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

const routes = [
  {
    path: '/index',
    component: () => import('./views/index'),
    name: 'index',
    meta: {
      title: '首页',
      keepAlive: true,
      transition: 'slide-left', // 新增
    },
  },
  {
    path: '/list',
    component: () => import('./views/list'),
    name: 'list',
    meta: {
      title: '用户列表',
      keepAlive: true,
      transition: 'slide-left', // 新增
    },
  },
  {
    path: '/userDetail/:id',
    component: () => import('./views/userDetail'),
    name: 'userDetail',
    meta: {
      title: '用户详情',
      keepAlive: true,
      transition: 'slide-left', // 新增
    },
  },
]

const router = createRouter({
  history: createWebHistory(),
  routes,
})

router.afterEach((to, from) => {
  // 新增
  const toDepth = to.path.split('/').length
  const fromDepth = from.path.split('/').length
  to.meta.transition = toDepth < fromDepth ? 'slide-right' : 'slide-left'
})

export default router

index.vue

<template>
  <div class="page">
    <div>这里是首页</div>
    <router-link to="/list">点击跳转到列表页</router-link>
  </div>
</template>

<script>
export default {}
</script>

<style></style>

list.vue

<template>
  <div class="page">
    <div>这里是列表页</div>
    <router-link to="/index">点击跳转到首页</router-link>
    <ul>
      <li v-for="item in userList" :key="item.id">
        <router-link
          :to="{
            name: 'userDetail',
            params: {
              id: item.id,
            },
            query: {
              name: item.name,
            },
          }"
          >点击查看{{ item.name }}</router-link
        >
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      userList: [
        {
          name: '亚历山大',
          id: '01',
        },
        {
          name: '凯撒',
          id: '02',
        },
        {
          name: '屋大维',
          id: '03',
        },
      ],
    }
  },
}
</script>

<style></style>

userDetail.vue

<template>
  <div class="page">用户详情页获取到了id:{{ id }},他的名字是:{{ name }}</div>
</template>

<script>
export default {
  data() {
    return {
      id: '',
      name: '',
    }
  },
  mounted() {
    this.id = this.$route.params.id
    this.name = this.$route.query.name
  },
}
</script>

<style></style>

上一篇下一篇

猜你喜欢

热点阅读