[vue-router4进阶] 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>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容