zoukankan      html  css  js  c++  java
  • 理解 vue-router的beforeEach无限循环的问题

    在理解beforeEach无限循环之前,我们先来看一下beforeEach相关的知识点,该篇文章的项目是基于 express+vue+mongodb+session实现注册登录 这篇文章项目基础之上进行讲解的,因为登录完成后,会跳转到列表页面,那么在跳转到列表页面之前,我们会使用 router.js 使用beforeEach来判断下,如果登录成功,并且session在有效期内的话,就跳转到下一个页面去,否则的话,就重定向到登录页面去。
    app/index/router.js 代码如下:

    import Vue from 'vue';
    import VueRouter from 'vue-router';
    
    // 告诉 vue 使用 vueRouter
    Vue.use(VueRouter);
    
    const routes = [
      {
        path: '/list',
        name: 'list',
        component: resolve => require(['./views/list'], resolve)
      },
      {
        path: '*', // 其他没有的页面都重定向到 home页面去
        redirect: '/login'
      },
      {
        path: '/login',
        name: 'login',
        component: resolve => require(['./views/login'], resolve)
      },
      {
        path: '/regist',
        name: 'regist',
        component: resolve => require(['./views/regist'], resolve)
      }
    ]
    
    var router = new VueRouter({
      base: '/app/index', // 配置单页应用的基路径
      routes: routes
    });
    
    router.beforeEach((to, from, next) => {
      console.log(to);   // 即将要进入路由的对象
      console.log(from); // 当前导航要离开的路由对象
      console.log(next); // 调用next该方法,才能进入下一个路由
      next();
    });
    export default router;

    如上代码写完成后,我们从登录页面点击登录,登录成功后,会跳转至列表页面。在跳转之前会打印上面的信息。

    console.log(to); 打印的信息如下:

    console.log(from); 打印的信息如下:

    如上代码,调用 next()方法才能进入下一个路由,否则的如果写了beforeEach方法,但是没有调用next()方法的话,页面会空白,不会跳转到任何页面的。默认不写 router.beforeEach((to, from, next) => {}) 的话,它是默认跳转到指定页面去的,当然如果有这个方法的话,应该会覆盖默认的方法。因此如果写了调用了该方法的话,切记记得调用 next() 方法。

    next(false); 如果next方法添加一个false的话,那么就会中断当前的导航跳转。修改完成后,我们重新刷新 localhost:8081/list 这个页面的话,会看到页面一片空白,最后我们打印下 console.log(to); 的信息如下:

    打印 console.log(from); 打印信息如下所示:

    next('/') 或者 next({ path: '/' }); 跳转到一个不同的地址,当前的导航会被中段,然后会进入 path那个新的导航。

    如上是基本的beforeEach的语法,那么在具体跳转到那个页面去,我想在beforeEach中判断下,如果用户登录成功的话,并且session在有效期的话,那么就跳转到指定的页面去,否则的话,就重定向到登录页面去。
    先看登录成功后的代码如下:

    this.$http.post('/reglogin/login', obj).then((res) => {
      if (res.body.code === 0) {
        // 登录成功
        const msg = res.body.msg || '登录成功!!!';
        localStorage.setItem('username', 1);
        this.messageFunc('success', msg);
        setTimeout(() => {
          this.$router.push({
            path: '/list'
          });
        }, 2000);
      } else {
        // 登录失败
        const errorMsg = res.body.errorMsg || '登录失败';
        this.messageFunc('warning', errorMsg);
      }
    });

    登录成功后,我们会把 username 保存到 localStorage 中,我们就可以在 beforeEach中来判断 localStorage 中是否有username了,当然如果登录过期的话或者注销的话,需要把本地存储的 username该字段置为null即可。

    因此我router.js代码会改成如下所示:

    router.beforeEach((to, from, next) => {
      console.log(localStorage.getItem('username'));
      if (localStorage.getItem('username') === null) {
        console.log('出现死循环了');
        // 重定向到登录页面去
        next({
          path: '/login'
        });
      } else {
        console.log('我是来测试的');
      }
    });

    如上代码后会, 当我们刷新下 http://localhost:8081/#/login 后会出现死循环,如下所示:

    如上并且页面是空白的,因为当我们刷新 http://localhost:8081/#/login 后先会执行 router.beforeEach()该方法,因为我们还没有登录,所以获取到本地存储的username为null,因此一直重定向到 /login 登录页面去,因此会一直出现死循环,按道理来说重定向到登录页面去的时候,页面是登录页面,不应该是空白,但是有可能出现死循环了,导致一直重定向,最后什么原因导致空白了。

    但是如果我们改成如下代码就一切正常了,如下代码:

    router.beforeEach((to, from, next) => {
      /*
      console.log(localStorage.getItem('username'));
      if (localStorage.getItem('username') === null) {
        console.log('出现死循环了');
        // 重定向到登录页面去
        next({
          path: '/login'
        });
      } else {
        console.log('我是来测试的');
      }
      */
      if (true) {
        // 如果为true的话,会重定向到指定页面去,否则的话会重定向到登录页面去
        next();
      } else {
        next({
          path: '/login'
        });
      }
    });

    如上代码,我直接写死了为true,则直接调用 next()方法跳转到下一个路由,就不会再调用 beforeEach()方法了。如果为false的话,则跳转到 登录('/login') 页面去。

    因此为了解决 全局 判断用户是否登录跳转的问题,我们可以使用如下方法解决:

    router.beforeEach((to, from, next) => {
      if (localStorage.getItem('username')) { // 如果已经登录的话
        next();
      } else {
        if (to.path === '/login') { // 如果是登录页面的话,直接next()
          next();
        } else { // 否则 跳转到登录页面
          next({
            path: '/login'
          });
        }
      }
    });

    当然在登录接口中,登录成功后,要使用 localStorage 保存用户名,如下 app/index/views/login.vue 接口如下代码:

    this.$http.post('/reglogin/login', obj).then((res) => {
      if (res.body.code === 0) {
        // 登录成功
        const msg = res.body.msg || '登录成功!!!';
    
        // 这里需要使用 localStorage 保存用户名 
        localStorage.setItem('username', 1);
    
        this.messageFunc('success', msg);
        setTimeout(() => {
          this.$router.push({
            path: '/list'
          });
        }, 2000);
      } else {
        // 登录失败
        const errorMsg = res.body.errorMsg || '登录失败';
        this.messageFunc('warning', errorMsg);
      }
    });

    当然 点击注销的时候 也要删除该 username了,如下代码:

    // 注销
    logout() {
      this.$http.post('/reglogin/logout', {}).then((res) => {
        if (res.body.code === 1 && res.body.session) {
          // 说明注销成功 跳转到登录页面去
          this.$message({
            message: '注销成功',
            type: 'success'
          });
          localStorage.removeItem('username');
          setTimeout(() => {
            this.$router.push({
              path: '/login'
            });
          }, 1000);
        }
      });
    }

    我们首先看 beforeEach 代码,

    router.beforeEach((to, from, next) => {
      if (localStorage.getItem('username')) { // 如果已经登录的话
        next();
      } else {
        if (to.path === '/login') { // 如果是登录页面的话,直接next()
          next();
        } else { // 否则 跳转到登录页面
          next({
            path: '/login'
          });
        }
      }
    });

    to 参数是到哪里去的含义,因此当我们刷新登录页面的时候,from 的值路径为 '/', to 的path为 '/login', 因此调用next方法,还是登录页面,不会出现死循环,和我们上面讲的如下代码原理是一样的:

    router.beforeEach((to, from, next) => {
      if (true) {
        // 如果为true的话,会重定向到指定页面去,否则的话会重定向到登录页面去
        next();
      } else {
        next({
          path: '/login'
        });
      }
    });

    然后当我登录成功后,/login 接口会使用 localStorage 保存username信息,然后在跳转页面之前会继续调用 beforeEach方法,然后会判断:

    if (localStorage.getItem('username')) { // 如果已经登录的话
      next();
    } 

    说明有username的值,会执行下一个路由跳转,因此能跳转成功。

  • 相关阅读:
    node获取请求参数的方法get与post请求
    express框架路由未导出错误:Router.use() requires a middleware function but got a Object
    移动端学习之理解WEB APP、Native APP、Hybrid APP以及React Native/uniapp包括H5、小程序等的区别与共通之处
    微信小程序
    “You may need an appropriate loader to handle this file type”
    vue-cli Cannot find module 'less'
    Node 跨域问题 Access to XMLHttpRequest at 'http://localhost:8080/api/user/login' from origin 'http://localhost:808
    Access denied for user 'root'@'localhost' (using password: YES)
    nrm : 无法加载文件 C:Users......因为在此系统上禁止运行脚本。
    继承树追溯
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/10125535.html
Copyright © 2011-2022 走看看