使用 vue-router 全局守卫钩子函数,根据登录状态进行路由拦截以及滚动条回到页面顶部

一、登录状态路由拦截

1.首先安装 vue-router 依赖

npm install vue-router

2.在 main.js 文件中,引入 router,挂载到根节点上

import router from './router'

new Vue({
  router,
  store,
  render: h => h(Febs)
}).$mount('#app')

3.如何在 router 文件中做路由拦截呢?

const whiteList = ['/login']  // 定义白名单

// 全局前置守卫
router.beforeEach((to, from, next) => {
  if (whiteList.indexOf(to.path) !== -1) {
    // 清除数据
  }
  if (!userInfo && to.path !== '/login') {
    next('/login')
  } else {
    next()
  }
}

4.如果我们的登录不是一个单独的路由,而是一个登录弹框呢?那对于未登录的用户,我们将禁止用户页面跳转,并且弹出登录弹框,用于提示用户需要登录才能操作。

const authPages = ['/order'] // 需要登录的路由

router.beforeEach((to, from, next) => {
  // 判断需要登录的路由 防止通过直接改变 url 进入相应页面
  if (authPages.includes(to.path) && !store.state.user.userInfo.userId) {
    store.commit('setLoginVisible', true) // 打开登录
    next({ path: from.path || '/' }) // 将路由重置为 from.path
    return
  }
  next()
})

5.那我们如何全局调用登录弹框呢?首先主体架构下,引入登录组件。

<!-- 登录 -->
<login :isShow="loginVisible" v-if="loginVisible" />

export default {
  computed: {
    ...mapState({
      loginVisible: state => state.user.loginVisible,
    })
  },
}

使用 Vuex 全局存储【登录框】数据状态。

<!-- src/store/modules/user.js -->
const user = {
  state: {
    loginVisible: false, // 登录弹窗显示
  },
  mutations: {
    setLoginVisible: (state, loginVisible) => {
      state.loginVisible = loginVisible
    },
  }
}
export default user

Login 子组件中,通过 el-dialog 组件中 visible 属性来决定是否显示登录弹框信息。

<el-dialog
  title="登录"
  class="login"
  modal-append-to-body
  :visible.sync="isShow"
  :before-close="handleClose"
  :close-on-click-modal="false"
>
  .....
</el-dialog>

除了上述的路由拦截方法之外,当然我们也可以在路由跳转时进行判断是否登录。

goToModule (item) {
  if (this.$utils.checkLogin()) {
    this.$router.push({ path: item.url })
  }
},

// 检查当前是否登录
checkLogin (openLoginDialog = true) {
  if (!store.state.user.userInfo.userId && openLoginDialog) {
    store.commit('setLoginVisible', true) // 未登录是打开登录弹窗
  }
  return !!store.state.user.userInfo.userId
},

补充:Vue-router 路由介绍

vue-router 提供的导航守卫注意用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的,单个路由独享的,或者组件级的。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。

(一)全局守卫

使用 router.beforeEach 注册一个全局前置守卫。当一个导航栏触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) {
    next({ name: 'Login' })
  } else {
    next()
  }
})
router.afterEach((to, from) => {
  // ...
})
  • to: Route: 即将要进入的目标 路由对象

  • from: Route: 当前导航正要离开的路由

  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

  1. next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。

  2. next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

  3. next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: truename: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。

  4. next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

(二)路由独享守卫

待补充

(三)组件内守卫

你可以在路由组件内直接定义以下路由导航守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave。

beforeRouteEnter: 在渲染该组件的对应路由被 confirm 前调用,不能获取组件实例 this,因为当前守卫执行前,组件实例还没被创建。

beforeRouteUpdate:在当前路由改变,但该组件被复用时调用。

export default {
  ......
  // 路由跳回来前判断是否需要刷新列表
  beforeRouteUpdate (to, from, next) {
    if (to.meta.needRefresh) {
      this.$refs.tableList.getList()
      delete to.meta.needRefresh
    } 
    next()
  },
}

这里我们可以看到根据 to.meta.needRefresh 来刷新列表,这里需要 router 配合。

export default [
  {
    path: 'registerMaintain',
    name: 'registerMaintain',
    meta: {
      needRefresh: true,
    },
    component: RegisterMaintain,
    children: [
      ......
    ]
  },
]

beforeRouteLeave:导航离开该组件的对应路由时调用,可以访问组件实例 this。

// 增改详组件离开前判断是否需要给主页面组件加刷新标识
beforeRouteLeave (to, from, next) {
  this.needRefresh && (to.meta.needRefresh = true)
  next()
},

二、滚动条回到页面顶部

点击页面进行路由切换时,将页面中的滚动条滚动到页面顶部。这个时候我们就要介绍 Vue-router 中的 afterEach 钩子函数。

router.afterEach(() => {
  // 切换路由页面回归顶部(滚动的是内容层,加定时器,不然路由立刻切换的时候无法获取dom节点)
  setTimeout(() => {
    const dom = document.querySelector('.framework-wrapper')
    // IE下没有scrollTo属性,要做兼容判断
    if (dom && dom.scrollTo) {
      document.querySelector('.framework-wrapper').scrollTo(0, 0)
    } else {
      document.querySelector('.framework-wrapper').scrollTop = 0
    }
  }, 0)
})

当然我们也可以将其封装为一个工具方法来调用。

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值