实测在Nuxt中自定义loading加载效果,搭配nuxt/axios拦截器

首先说一下我用的loading是一个第三方json动画库,底层用了window和document对象,在服务端会报错,只能在客户端跑。所以在服务端运行的请求钩子是不能进行loading效果的

先引入第三方动画库lottiefiles

  • 我的版本是^1.5.6
    npm install @lottiefiles/lottie-player

  • 在plugins下创建一个Loading文件夹,Loading下创建一个lottiePlayer.js全局引入该模块

// 引入lottiefiles
import '@lottiefiles/lottie-player'
  • 在nuxt.config.js中的plugins模块中引入
module.exports = {
  plugins: [
    // 自定义loading
    { src: '~/plugins/Loading/lottiePlayer.js', ssr: false }, // 使用了window对象,所以关闭服务端渲染
  ],
}

在plugins/Loading下创建一个loading.vue,并挂载到Vue实例原型上

  • Loading/loading.vue
<template>
  <div v-show="loading" class="loading-page">
    <lottie-player
      v-show="isShow"
      class="lottie"
      src="https://assets8.lottiefiles.com/packages/lf20_nm1huacl.json"
      background="transparent"
      speed="1.5"
      style="width: 300px; height: 300px"
      loop
      autoplay
    />
    <lottie-player
      v-show="!isShow"
      class="lottie"
      src="https://assets4.lottiefiles.com/private_files/lf30_weidduaf.json"
      background="transparent"
      speed="1"
      style="width: 300px; height: 300px"
      loop
      autoplay
    />
  </div>
</template>

<script>
export default {
  data: () => ({
    loading: false,
    // 随机展示两者中的一个
    isShow: Math.floor(Math.random() * 2)
  })
}
</script>

<style lang="less" scoped>
.loading-page {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  overflow: hidden;
  z-index: 99999;
  .lottie {
    position: absolute;
    top: 47%;
    left: 51%;
    transform: translate(-51%, -47%);
  }
  &::before {
    position: absolute;
    content: "";
    width: 100%;
    height: 100%;
    // background-color: #bebebe;
    background: rgba(235, 235, 235, 0.8);
    backdrop-filter: blur(5px);
    filter: Alpha(Opacity=90);
    opacity: 0.9;
  }
}
</style>

  • Loading/index.js 挂载
import Vue from 'vue'

// 自定义loading
import Loading from './loading.vue'
// 空实例
let instance = null

const loading = {
  install(Vue) {
    if (!instance) {
      // 构造器
      const MyLoading = Vue.extend(Loading)
      instance = new MyLoading({
        // 创建一个div,挂载上去
        el: document.createElement('div')
      })

      document.body.appendChild(instance.$el)
    }

    instance.loading = false // 默认为false

    // 自定义方法
    const customMethods = {
      start() {
        instance.loading = true
      },
      finish() {
        instance.loading = false
      }
    }

    // 挂载到自定义方法vue上
    if (!Vue.$loading) {
      Vue.$loading = customMethods
      // 挂载到原型上
      Vue.prototype.$loading = Vue.$loading
    } else {
      console.log('$loading方法被占用')
    }
  }
}
Vue.use(loading)
  • 然后在nuxt.config.js中的plugins注册一下,注意:要取消nuxt原来的loading效果,因为它原来在 n u x t 挂载的也是 nuxt挂载的也是 nuxt挂载的也是loading
//nuxt.config.js
export default {
	
  // 使用自定义loading,正好nuxt不用在this实例上添加$loading了
  loading: false,
  plugins: [
    // 自定义loading
    { src: '~/plugins/Loading/lottiePlayer.js', ssr: false }, // 使用了window对象
    { src: '~/plugins/Loading/index.js', ssr: false }, // 使用了document对象
  ],
}

在axios拦截器中添加loading

//api/interceptor.js
import Vue from 'vue'
import {
  message
} from 'ant-design-vue'

export default ({ store, route, redirect, $axios, req }) => {
  $axios.onRequest(config => {
    // 开启加载, 只有客户端才有window document 对象。配合plugins只在客户端中开启
    if (process.client) {
      Vue.prototype.$loading.start()
    }

    const accessToken = store.state.accessToken
    // 请求头添加token
    if (accessToken) {
      // Authorization: Bearer token
      config.headers.Authorization = `Bearer ${accessToken.replace(/"/g, '')}`
    }

    return config
  })

  $axios.onResponse(res => {
     // 客户端拦截打印   结束加载
    if (process.client) {
      console.log('客户端拦截数据:', res.data)
      setTimeout(() => {
        Vue.prototype.$loading.finish()
      }, 300)
    }
    if ((res.status !== 200 || res.data.code !== 20000) && process.client) {
      // !!! 服务端错误提示不生效,因为服务端没有document对象,所以在asyncData中请求的数据要注意!!!
      message.error(res.message || res.data.message || '数据响应异常', 1)
    }
    // 服务端不能执行message
    if (res?.data.code !== 20000 && process.server) {
      console.error('服务端:', res?.data.message || '数据响应异常')
      console.error('服务端错误数据:', res.data)
    }

    return res.data
  })

  $axios.onError(error => {
    // 结束加载, 只有客户端才有window document 对象。配合plugins只在客户端中开启
    if (process.client) {
      Vue.prototype.$loading.finish()
    }
    const { response: res } = error
    // 权限过期 -> 重定向
    if (res.status === 401 && res.data.code === 1401) {
      let isLock = true
      if (isLock && store.state.refreshToken) {
        isLock = false
        // 发送请求到认证客户端,通过刷新令牌获取新令牌
        redirect(`${process.env.authURL}/refresh?redirectURL=${redirectURL(route, req)}`)
      } else {
        isLock = true
        // 没有刷新令牌,跳转到登录页
        // 重置用户状态
        // console.log('跳转到登录页')
        store.commit('RESET_USER_STATE')
        // 跳转到登录页
        redirect(`${process.env.authURL}?redirectURL=${redirectURL(route, req)}`)
      }
      message.error(res.data.message, 1)
      if (process.client) {
        Vue.prototype.$loading.start()
      }
      return Promise.reject(res.data.message || 'Error')
    }
    message.error(res.data.message, 1)
    return Promise.reject('令牌过期,重新登录')
  })
}

// 获取重定向地址
const redirectURL = (route, req) => {
  // 客户端
  if (process.client) {
    return window.location.href
  }
  // 服务端
  return `${process.env.NODE_ENV === 'production' ? 'https://' : 'http://'}` + req.headers.host + route.fullPath
}

加载数据效果(在客户端请求数据时生效)
在这里插入图片描述
各位老板点赞三连


更多推荐:wantLG的《普歌-实测Nuxt坑,配置@nuxt/axios、拦截器、代理跨域,请求


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wantLG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值