vue2路由拦截器

全局路由守卫

// main.js 或 router.js
router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  if (to.meta.requiresAuth && !token) {
    next({ path: '/login', query: { redirect: to.fullPath } })
  } else {
    next()
  }
})
  • to.meta.requiresAuth:判断目标路由是否需要权限

  • token:模拟登录状态

  • next():控制跳转逻辑

路由配置中的 meta 字段

const routes = [
  {
    path: '/dashboard',
    component: Dashboard,
    meta: { requiresAuth: true }
  },
  {
    path: '/login',
    component: Login
  }
]
  • meta.requiresAuth: true 表示该路由需要登录权限

全局前置守卫 router.beforeEach

这是最常用的守卫,通常用于:

登录验证

router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  if (to.meta.requiresAuth && !token) {
    next({ path: '/login', query: { redirect: to.fullPath } })
  } else {
    next()
  }
})
  • 检查是否登录

  • 如果未登录,跳转到登录页

  • 登录后可重定向回原页面

权限控制

if (to.meta.role && !userHasRole(to.meta.role)) {
  next('/403') // 无权限页面
}
  • 根据 meta.role 判断用户是否有访问权限

页面标题设置

document.title = to.meta.title || '默认标题'

Vue2修改页面标题-CSDN博客

加载动画控制

startLoading() // 显示 loading 动画
next()

全局后置守卫 router.afterEach

用于处理跳转完成后的逻辑:

router.afterEach((to, from) => {
  stopLoading() // 关闭 loading 动画
  window.scrollTo(0, 0) // 页面回到顶部
})

一个简单的加载动画示例

1. 安装 Element UI(如果尚未安装)

npm install element-ui

2. 在 main.js 中引入 Element UI

import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI)

3. 在 router.jsmain.js 中添加路由守卫

import router from './router'
import { Loading } from 'element-ui'

let loadingInstance = null

router.beforeEach((to, from, next) => {
  // 显示加载动画
  loadingInstance = Loading.service({
    lock: true,
    text: '页面加载中...',
    spinner: 'el-icon-loading',
    background: 'rgba(0, 0, 0, 0.3)'
  })

  next()
})

router.afterEach(() => {
  // 关闭加载动画
  if (loadingInstance) {
    loadingInstance.close()
  }
})

补充说明

  • Loading.service() 会创建一个全屏加载动画

  • loadingInstance.close() 用于关闭动画,确保不会残留

  • 你可以根据路由 meta 字段决定是否显示动画(比如某些页面不需要)

自定义加载动画组件示例

1. 创建组件 LoadingOverlay.vue

<template>
  <div v-if="visible" class="loading-overlay">
    <div class="spinner"></div>
    <p>页面加载中...</p>
  </div>
</template>

<script>
export default {
  props: {
    visible: {
      type: Boolean,
      default: false
    }
  }
}
</script>

<style scoped>
.loading-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.4);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 9999;
}
.spinner {
  width: 50px;
  height: 50px;
  border: 6px solid #ccc;
  border-top-color: #42b983;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}
</style>

2. 在 Vuex 中添加 loading 状态(例如在 AppModule

// store/modules/AppModule.js
export default {
  namespaced: true,
  state: {
    loading: false
  },
  mutations: {
    setLoading(state, payload) {
      state.loading = payload
    }
  }
}

3. 在 App.vue 中使用组件并绑定 Vuex 状态

<template>
  <div id="app">
    <router-view />
    <LoadingOverlay :visible="loading" />
  </div>
</template>

<script>
import LoadingOverlay from '@/components/LoadingOverlay.vue'
import { mapState } from 'vuex'

export default {
  components: { LoadingOverlay },
  computed: {
    ...mapState('AppModule', ['loading'])
  }
}
</script>

4. 在路由守卫中控制 loading 状态

import store from '@/store'

router.beforeEach((to, from, next) => {
  store.commit('AppModule/setLoading', true)
  next()
})

router.afterEach(() => {
  setTimeout(() => {
    store.commit('AppModule/setLoading', false)
  }, 500) // 延迟关闭,避免闪烁
})

效果说明

  • 页面跳转时显示一个全屏遮罩和旋转动画

  • 路由完成后自动关闭

  • 可根据需要扩展为请求级 loading、模块级 loading 等

路由级守卫(单个路由)

用于某个路由单独控制

const router = new VueRouter({
  routes: [
    {
      path: '/admin',
      component: Admin,
      beforeEnter: (to, from, next) => {
        const isAdmin = checkAdmin()
        if (isAdmin) {
          next()
        } else {
          next('/not-authorized')
        }
      }
    }
  ]
})
  • beforeEnter:只在进入该路由时触发

组件内守卫

export default {
  name: 'Profile',
  beforeRouteEnter(to, from, next) {
    next(vm => {
      vm.fetchUserData()// 组件实例还没创建,需通过 next(vm)
    })
  },
  beforeRouteUpdate(to, from, next) {
    this.fetchUserData()// 路由参数变化时重新加载数据
    next()
  },
  beforeRouteLeave(to, from, next) {
    const answer = window.confirm('确定要离开吗?')
    if (answer) {
      next()
    } else {
      next(false)
    }
  }
}
  • beforeRouteEnter:组件创建前

  • beforeRouteUpdate:路由参数变化时

  • beforeRouteLeave:离开当前组件前

登录状态判断示例(结合 sessionStorage)

router.beforeEach((to, from, next) => {
  const userId = sessionStorage.getItem('userId')
  if (to.meta.requireAuth && !userId) {
    next({ path: '/login', query: { redirect: to.fullPath } })
  } else {
    next()
  }
})

结合 axios 请求拦截器(非路由,但常一起使用)

axios.interceptors.request.use(config => {
  const token = localStorage.getItem('token')
  if (token) {
    config.headers.Authorization = token
  }
  return config
})

axios.interceptors.response.use(response => {
  if (response.data.code === 401) {
    router.replace({ path: '/login' })
  }
  return response
})

常见用途总结

功能守卫位置示例
登录验证beforeEach检查 token
权限控制beforeEach / beforeEnter判断角色
页面标题beforeEach设置 document.title
页面加载动画beforeEach / afterEach显示/关闭 loading
数据初始化beforeRouteEnter / beforeRouteUpdate调用 API
离开确认beforeRouteLeave弹窗确认
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值