0
点赞
收藏
分享

微信扫一扫

[Vuex]前后端分离Vue路由拦截器

sin信仰 2022-03-16 阅读 41
vue.js前端

文章目录

1.Vuex 初探

参考文章:开始 | Vuex (vuejs.org)

1.1 vuex 介绍

背景

我们在使用vue去写前端的时候,肯定遇到过对不同组件之间传递变量值的需求,但是我们又不能很高校地去解决。vuex就是用来解决这种需求的,让我们的组件们拥有共享变量。

vuex 作用

  • vuex的核心是提供了store容器,容器嘛,容器就是用来装东西的,这里装的可以理解成超级全局变量,每个vue组件都能在这个store仓库中共享超级全局变量。
  • 但是store可不止这个功能,因为vuex的功能是管理 状态state 而不是单单管理变量的

vuex 优点

为什么我要用超级全局变量来说呢?因为它和全局变量是不一样的:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。【从java的角度理解就是这些变量都是私有private,只能set()get()方法去修改,不能直接赋值】

安装

script : 不常用

<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

npm :

npm install vuex --save

yarn :

yarn add vuex@next --save

1.2 store 的使用

我们前面讲到 Vuex 的核心就是 store,所以对于我们来说,store就能够满足小项目的需求了。

目录准备

我们一般会在src下建立store目录,在里面创建一个index.js文件来使用vuex。

当然我们也可以在main.js中使用,但是考虑到代码耦合度,分开使用更佳
在这里插入图片描述

当然官方有最规范的目录结构,因为在一个完整项目中store内容一定很多,把整个store放在index.js中是不合理的,所以需要拆分。

store:.
│  actions.js
│  getters.js
│  index.js
│  mutations.js
│  mutations_type.js   ##该项为存放mutaions方法常量的文件,按需要可加入
│
└─modules
        Astore.js

简单使用

store/index.js中定义:

//导入这个是为了Vue.use(Vuex) 挂载vuex对象用来访问
import Vue from 'vue'

//导入vuex包
import Vuex from 'vuex'

//挂载Vuex
Vue.use(Vuex)

// 创建一个新的 store 实例
export default new Vuex.Store({
    state: {
        
        //存放的键值对就是要管理的状态
        user: {
            account: "window.localStorage.getItem()"
        },
        
    },
    //方法,一般包含功能性方法和状态变量的set()get()方法
    mutations: {
        loginSuccess (state, account) {
            state.user.account = account
            window.localStorage.setItem('account',JSON.stringify(account))
        },
        //修改状态变量只能通过这种方式
        setAccount (state, account) {
    		this.user.account = account
		}
    }
})

vue组件中使用:

// 调用状态变量
console.log(this.$store.state.user.account)
// 调用状态方法  第一个实参是方法名,第二个实参开始是参数列表
this.$store.commit('loginSuccess',this.account)
this.$store.commit('setAccount','xxx')

2.localStorage使用

参考文章:Window.localStorage - Web API 接口参考 | MDN (mozilla.org)

2.1 localStorage介绍

window.localStorage 和 window.sessionStorage 都可以用来存放全局变量。但是区别就在于window.sessionStorage在页面关闭的时候就会被回收,而window.localStorage是直接存放在本地浏览器的cookie里,每次vue启动都会扫描本地浏览器的cookie去找有没有要找的属性值。

另外,localStorage 中的键值对总是以字符串的形式存储。 (需要注意, 和js对象相比, 键值对总是以字符串的形式存储意味着数值类型会自动转化为字符串类型).

2.2 localStorage语法

一般写window.localStorage更好,当然不加window应该也没问题

下面的代码片段访问了当前域名下的本地 Storage对象,并通过 Storage.setItem() 对象,并通过 Storage.setItem()增加了一个数据项目。这个数据会直接被添加到本地浏览器的cookie中

放置localStorage 项

localStorage.setItem('myCat', 'Tom');

获取 localStorage 项

let cat = localStorage.getItem('myCat');

移除指定 localStorage 项

localStorage.removeItem('myCat');

移除所有的 localStorage 项

localStorage.clear();

3.路由钩子函数[导航守卫]

参考文章:Vue-Router路由钩子函数(导航守卫) - 简书 (jianshu.com)

3.1 导航守卫介绍

导航表示路由正在从单个页面跳转到另一个页面的过程,这个过程可以添加操作来保证用户是否有权限进行跳转路由。

路由钩子函数一共三种:

  1. 全局钩子,一般可以写在main.js下方或者路由index.js下方:beforeEach、afterEach、beforeResolve

  2. 单个路由进入的钩子:beforeEnter

  3. 进入组件的钩子:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

3.2 全局守卫的使用

无论访问哪一个路径,都会触发全局的钩子函数,位置是调用router的方法

router.beforeEach() 进入前触发

router.afterEach() 进入后触发

当前项目仅依赖router.beforeEach()

/**
* @Param to : 即将要进入的目标路由对象
* @Param from : 正在离开的路由
* @Param next : 必须要调用的方法,next()表示允许进入to这个路由对象,
*               next(false)表示不能进入,next({path:'/'})定向到某地址
*/
router.beforeEach((to,from,next)=>{
    xxxx
})

若没有调用next() 则beforeEach钩子不能被resolved调用

解决刷新页面不执行beforeEach()拦截

原因是router的beforeEach方法定义在vue渲染router之后,如果router.beforeEach放在new Vue之后,因为vue渲染在刷新页面的时候不重复,所以不会重新渲染router,也就无法进入router的钩子函数。因此要修改成下面的顺序:路由钩子在前,vue渲染在后。

//在每次访问路由前调用
router.beforeEach((to,from,next)=>{
   if (to.meta.requireAuth) {
       if(store.state.user.account ) {
          next()
       } else {
          next({
             name: 'login',
             query: {redirect: to.fullPath}
          })
       }
   } else {
      next()
   }
})

//每次调用beforeEach后再渲染页面
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

4.vue的登录拦截器实现

4.1 实现理论

  1. 我们在登录组件提交登录信息的时候,获取后端返回的结果,如果返回信息为成功登录,我们就把当前登录信息放入vuex的store状态变量中,同时把信息存进localStore,让vue放进浏览器的cookie中,这样我们在退出页面一段时间内,仍然能直接登录。
  2. 当我们访问其他需要权限的路由的时候(比如访问 我的空间 这种需要用户登录后才能进入的页面),需要在进入该路由页面之前使用beforeEach钩子函数判断当前浏览器是否有登录信息,如果没有说明没有登录,重定向到login页面,不放行路由。安装

4.2 安装

npm install vuex --save

参考文章:Vue + Spring Boot 项目实战(六):前端路由与登录拦截器_Evan-Nightly的博客-CSDN博客

4.1 配置store

  1. 在src下创建store文件夹,在store文件夹中创建index.js:
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

//创建store对象
export default new Vuex.Store({
    state: {
        
        //如果本地浏览器有登录信息就直接获取
        user: {
            account: window.localStorage.getItem('account'),
        },
        
    },
    
    //方法
    mutations: {
        //成功登录才会进来这里
        loginSucess (state, account) {
            //先把登录信息放进store.state的状态变量中方便后面调用
            state.user.account = account
            //把登录信息放进localStorage,让vue放进浏览器cookie中
            window.localStorage.setItem('account',JSON.stringify(account))
        }
    }
    
})
  1. 在main中注入store的index文件
    在这里插入图片描述

  2. 让vue渲染的时候挂载store
    在这里插入图片描述

4.2 使用localStore

在自己的登录组件login.vue中:

login() {
     if (this.isAccount && this.isPwd) {
        var salt = bcrypt.genSaltSync(11)
        this.password = bcrypt.hashSync(this.password, salt)
         
        //在请求判断是否为网站合法用户的时候加入判断如果成功,调用store的成功登录方法,把登录信息放入cookie中
        this.$http.post("/user/login", {
            account: this.account,
            password: this.password
        }).then((res) => {
            //如果成功登录就调用loginSuccess方法
            if(res.data == "OK"){
            	this.$store.commit('loginSuccess',this.account)
            }
        })
    }
},

4.3 配置路由

  1. 设定history的模式
    在这里插入图片描述

  2. 以下场景作为假设场景,假设我们需要 登录之后 才能访问 我的空间。 那么给/myspace路由一个参数放在meta中,也就是该路由需要验证身份权限。
    在这里插入图片描述

  3. 在main.js中调用路由的钩子函数

router.beforeEach((to,from,next)=>{
   //如果当前要跳转的路由需要认证,则认证
   if (to.meta.requireAuth) {
       //如果vuex中保存有登录信息,就说明登陆过,放行
       if(store.state.user.account) {
          next()
       //如果没有登录到,就强制重定向到login
       } else {
          next({
             name: 'login',
             query: {redirect: '/login'}
          })
       }
   //如果不需要认证就放行
   } else {
      next()
   }
})

4.4 结果检查

未能成功登录的情况

不允许进入,自动重定向到login
在这里插入图片描述

并且爆出异常:
在这里插入图片描述

成功登录,后端返回ok后
在这里插入图片描述

刷新页面后有缓存响应并成功获取

304状态码就是从cookie中获取到信息。
在这里插入图片描述

5.异常解决

5.1 Cannot read properties of undefined (reading ‘$store’)

TypeError: Cannot read property ' s t o r e ′ o f u n d e f i n e d V u e 中 ⋅ 无 法 使 用 t h i s . store' of undefined Vue中·无法使用this. storeofundefinedVue使this.store访问Vuex的全局数据 - 一只小鲸鱼 - 博客园 (cnblogs.com)

错误原因

异步请求中的then后使用function(){},this不指向全局vue

}).then(function(res){
    if(res.data == 'OK'){
        console.log(res.data)
        this.$store.commit('loginSuccess',this.account)
    } 
})

解决方法

then后使用 (res)=>{}

}).then( (res) =>{
    if(res.data == 'OK'){
        console.log(res.data)
        this.$store.commit('loginSuccess',this.account)
    }
})

5.2 NavigationDuplicated: Avoided redundant navigation to current location: “/XXX“

意思是在Vue中为了节约资源,一样的内容不会重复加载(浏览器如果发现请求地址一样也不会跳)。所以当你请求跳转相同的路径时,不会直接拼接上去URL上,给你一个警告。

未解决,网络方法均无效。

5.3 [vuex] unknown mutation type: XXX

检查方法名是否一致。

5.4 Error: Redirected when going from “/login” to “/mySpace” via a navigation guard.

报错不影响功能,凑合着吧

举报

相关推荐

0 条评论