nuxt-自定义路由跳转过渡动画

647 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

nuxt 框架与传统的 Vue SPA 相比,使用 SSR 将带来巨大的 SEO 提升,但基本框架依然是Vue。但是因为要做SEO,所以基本是基于服务端渲染的,有时路由跳转会等待一段时间,客户端最好进行提示或者展示过场动画,提示用户正在跳转。
本文记叙个人在nuxt中,等待路由跳转,使用过场动画的思路。

基本思路

思路主要是下面两个方面:
动画时间:既然是在路由跳转时启用的,那么自然是在全局路由守卫中对过场动画进行添加删除。
过场动画:因为是在全局路由守卫中使用,所以使用JS将过程动画封装成函数,进行调用,可以借鉴自定义vue指令的思路。

代码

  1. 首先,创建过场动画的vue组件,这个因人而异,不再赘述。
  2. 创建一个.js文件,目的是将上面过场动画的Vue组件封装成函数调用的形式,然后直接在路由守卫中调用函数即可。
  • 一开始,先导入Vue和过场动画组件,然后创建过场动画的组件构造器:
import Vue from 'vue'
import RouterAnimate from './routerAnimate.vue'
// 创建组件构造器
const constructor = Vue.extend(RouterAnimate)
  • 创建展示过场动画的函数,主要是以下步骤:
  • 判断环境,如果是在服务端,不执行任何操作
  • 确定过场动画的父级DOM元素,本文是document.body
  • 根据上面的构造器创建过场动画的实例
  • 在实例上添加关闭函数,这个因人而异,但既然时候用函数添加的过场动画,自然用函数关闭也是比较合理
  • 最后就是将实例中$el放到父级DOM元素里面,返回实例用于后续的关闭 整体代码:
const showRouterAnimate = () => {
  // 判断环境是否在服务端,如果是,不执行任何操作
  if (Vue.prototype.$isServer) {
    return false
  }
  // 确定过场动画的父级`DOM`元素
  const parent = document.body
  // 生成过场动画的实例
  const instance = new constructor({ el: document.createElement('div') });
  // 挂载关闭事件
  instance.close = close(parent)
  // 挂载组件元素
  parent.appendChild(instance.$el)
  // 添加类名,用于让过程动画逐渐出现,因人而异
  instance.$el.className += ' opacity-1'
  // 返回实例
  return instance
}
  • 接下来就是关闭函数,在上面的代码中可以看到,因为在实例上挂载了关闭函数,所以在路由守卫中只要得到过场动画的实例,就可以执行关闭。本文为了让过场动画有一个逐渐消失的过程,所以不会立即从HTML中删除过场动画,而是先加上消失的class,使用定时器延时删除:
function close (parent) {
  // 返回实例对应的关闭函数
  return () => {
    // 间隔时间
    const time = 1500
    // 判断父级元素和实例是否存在
    if (parent && this.$el) {
      // 添加消失的类名
      this.$el.className = 'opacity-0'
      // 创建定时器,等过场动画消失后,从html删除过场动画的元素
      const timerEndHidden = setTimeout(() => {
        clearTimeout(timerEndHidden)
        // 从html删除元素
        parent.removeChild(this.$el)
      }, time)
    }
  }
}
  1. 然后就是使用,因为不能允许有多个过场动画的存在,所以使用前必须判断,因为可以进一步封装成JSON或者Class来使用:
// 路由跳转过场动画
const routerAnimateInstance = {
  // 过场动画实例
  instance: null,
  // 开启函数
  open () {
    // 如果已经存在过场动画,则关闭
    this.instance && this.close()
    // 开启新的过场动画
    this.instance = showRouterAnimate()
  },
  // 关闭
  close () {
    // 判断实例是否存在
    if (this.instance) {
      // 关闭实例
      this.instance.close()
      // 实例置为null
      this.instance = null
    }
  }
}

这样,直接调用JSON中函数,可以保证过场动画不会出现多个。

  1. 最后就是在全局路由守卫中导入使用:
export default ({ app, store, redirect, req, route }) => {
  app.router.beforeEach((to, from, next) => {
    // 路由跳转前 开启动画
    routerAnimateInstance.open()
    next()
  })
  app.router.afterEach((to, from) => {
    // 路由条状完成 关闭动画
    routerAnimateInstance.close()
  })
}