最近接到一个新的需求,要求将系统的用户进行分类,用户登录后根据不一样的用户权限展现不一样的功能列表。前端
这个功能在后台管理中很常见,大体的思路是vue
一个在前端生成功能列表,一个在后端返回,两个本质上相似,最终都是须要获得一个该用户的功能列表。可是二者都有一个不可忽视的东西,就是若是用户直接在地址栏输入会怎么样。vuex
因为公司项目不算小,为了后期维护方便,我仍是选择了使用 vuex 完成上述的功能。后端
主要想法为在vuex中保存用户登录后的状态,以及用户可访问的路由列表,这样的话,不涉及到父子组件间的数据传递,能够很方便的在单个组件中获取到用户的权限路由列表。数组
若是只是想简单的使用一个vuex,了解state,mutation,action就足够你使用app
在src文件夹下,建立一个store文件夹,若是项目简单,能够将state,mutations,actions,getters等写入到一个文件中ide
主要代码很简单,只须要导入Vue,Vuex,而且调用Vue.use(Vuex)。函数
结合官方解释的我的理解,一个vuex文件就是一个仓库,它包含着你须要共享的变量、有关的事件、以及能够执行这些事件的行为,咱们把这些导出去,在单个组件中引入,咱们即可以在单个组件中对共享的变量进行改变。工具
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const state = { userLogin:false//共享变量 } export default new Vuex.Store({ state })
state主要功能是用来定义变量,表明你须要共享的一个状态。好比,我想要在每一个组件中 共享用户的路由列表,因此,我须要先在state中定义一个存放路由列表的变量。学习
1、vuex文件代码
store/index.js中
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const state = { pressionList: [{ path: "/A", name: "页面A" }],//用户容许登录的路由列表,为了方便记录,我写了一个默认值,这个能够不用 userLogin:false//用户登录状态 } export default new Vuex.Store({ state })
2、main.js文件代码
main.js中直接引入 store文件,并进行全局注册便可。这样在每一个组件中你均可以调用state里的共享变量啦。
import Vuex from 'vuex' import store from './store/index/' Vue.user(Vuex) new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
那怎么样在组件中读出state的变量呢?有两种方法:直接获取、或者使用mapState辅助工具。
插播一条题外话
咱们作为一枚程序猿,必需要试着去读API,一次读不懂就多读几回。再读不懂请教别人,再去读一次,你会发现每次读都有不一样的收获。
如下为vuex官方API,我会试着带一点API里的东西讨论此次需求的生成。
https://vuex.vuejs.org/zh/guide/
3、单个组件中读取state
如下为官方API提供对state用法的描述。
上半段,将状态从根组件“注入”到每个子组件,咱们已经在main.js里完成了。
主要看下半段,在computed属性里,监听state中的变量,而后经过this.$store.state获取
套入到咱们的需求中,咱们须要获取用户的路由列表,以及登录状态
3.1 直接获取
computed: { pressionList(){ return this.$store.state.pressionList }, userLogin(state){ return state.userLogin//或者接收一个state类型的变量,直接调用state里的共享属性 } }
此时咱们已经获取到了state里的状态,此时它就像一个data里定义的变量,咱们可使用数据双向绑定的形式调用它。如:我想要输出用户登录的状态。或者在事件中展现这个状态。
<div>{{userLogin}}</div> methods:{ login(){ console.log(this.userLogin) } }
3.2 借助mapState辅助工具获取
假如说state里保存了不少个共享的状态,咱们都须要怎么办呢,这样一个一个写太复杂,这时候,mapState就帮了咱们很大的忙。
仍是先看官方上的文章解释
咱们须要在组件的内部导入mapState,而后在computed属性里监听,以上图片无非就是说了几种状况
是数组,因此中间是 [],不是{}
有了以上的基础,咱们能够获取到一个共享的状态了,可是若是咱们须要在共享的状态上作点小动做怎么办呢?
mutation就帮咱们作这些事件,咱们须要把对共享状态须要作的事件写到mutation中,而后在组件中调用mutation里的事件,就能够了。
一样的,能够去官网看一下关于mutation的介绍。这里就不放图了,直接上代码
1、定义mutation
store/index.js
const mutations = { changePressionList(state,list){ state.pressionList = list; } } export default new Vuex.Store({ state, mutations//一样就 })
mutation里的事件第一个参数确定是state,用来调用共享的全部变量,后面能够接收一个其它的参数。
这里我是须要改变 共享路由的值,因此我须要接收到一个新的值来替换掉旧的值
我的理解时间
mutation是用来定义一个事件的,咱们须要对共享变量作的一系列的动做。可是,这个事件本身是不会去执行的,像methods里定义的一个事件同样,你须要去触发它。而mutation触发的方法就是用commit。如你想单击的时候触发mutation事件,你须要在单击事件里使用commit调用 mutation事件。
2、调用mutation
一样两种方式,直接调用、借助mapMutations辅助函数
2.1 直接调用
若是你理解了获取state变量,这个mutation调用会简单不少。
既然mutation是一个事件,因此,咱们须要在methods里去写
<button @click="changePress">更改用户路由</button> methods:{ changePress(){ let B= [{ path: "/B", name: "页面B" }]; this.$store.commit('changePressionList',B) } }
由于个人mutation定义的事件里接收了一个参数,那我调用的时候就须要传递一个参数。
commit 第一个参数是你须要调用的mutation事件,第二个是mutation事件里须要的一些参数。
点击页面上的改变按钮,你会发现输出的pressionList变量会发生改变。
我这个只是简单的用法,还有更深层次的,想学习的能够去官网查看
2.2 借助mapMutations辅助函数
也是三种状况,你能够以字符串数组的形式调用mutation里定义的事件,也能够给事件起一个别名。这个也跟state相似
在须要传值的状况下,也可使用字符串数组的形式传递。可是调用时,须要传递相应的参数。
<button @click="pressionList(list)">改变</button> data(){ return { list:[{ path: "/B", name: "页面B" }] } } methods:...mapMutations([ 'pressionList' ])
有了state、mutation的基础,咱们就能够实现咱们的第一个功能。在用户登录成功后,修改userLogin的状态,而后将用户的路由列表写入。
1、定义action
action与mutation相似,可是他是用来提交mutation的。至关于咱们在action里提交mutation,而后咱们再调用action。
action接收到的第一个参数,是一个与store对象有相同的方法和属性的context对象,包括commit,state,getters方法等等。
利用解构赋值,咱们也能够只用context其中的一个方法,如commit,因此咱们会常常的看到({commit,state})样式的代码
若是须要传递参数,能够在后面添加
const actions = { changePress({commit},list){ commit('changePressionList',list) } }
2、调用action
与muation不一样的是,调用action中的事件使用的是dispatch,意思是分发mutation中的事件。
调用方法也是在methods中,分为两种,与mutation用法一致。再也不赘述
咱们根据以上的作法,咱们获得了一个有效的路由列表。咱们能够在首页里循环这个列表,有哪一个路由咱们就渲染哪一个路由
底部路由代码
即便如此,若是有人直接在地址栏里输入了他不能访问的路由,咱们该怎么办呢?
这里就须要两个知识
动态添加路由欠着吧~~
改变路由文件很简单,只须要在路由文件末尾添加一个匹配全部路由的
path为/* 表示,当用户在地址栏直接 输入一个错误的地址时,如路由文件中并无abcd这个页面,可是用户在地址栏输入了/abcd,这时会自动跳到登录页面。
export default new Router({ routes: [{ path: '/', name: 'Login', component: Login }, { path: '/Father', name: 'Father', component: Father }, { path: '/Child', name: 'Child', component: Child }, { path: '/Home', name: 'Home', component: Home }, { path: '/A', name: 'A', component: A }, { path: '/*', name: 'Login', component: Login } ], mode: 'history' }, )
对我感兴趣的盆友,也能够关注个人我的公众号---小嘀咕影院官网。会不按期更新技术知识,旅行游记以及影视推荐