vuex根据不一样的用户权限展现不一样的路由列表

需求描述

最近接到一个新的需求,要求将系统的用户进行分类,用户登录后根据不一样的用户权限展现不一样的功能列表。前端

这个功能在后台管理中很常见,大体的思路是vue

  1. 后台返回用户类型,前端根据用户类型生成该类用户能够访问的功能列表。
  2. 后台返回功能列表,前端进行循环渲染。

一个在前端生成功能列表,一个在后端返回,两个本质上相似,最终都是须要获得一个该用户的功能列表。可是二者都有一个不可忽视的东西,就是若是用户直接在地址栏输入会怎么样。vuex

技术选型

因为公司项目不算小,为了后期维护方便,我仍是选择了使用 vuex 完成上述的功能。后端

主要想法为在vuex中保存用户登录后的状态,以及用户可访问的路由列表,这样的话,不涉及到父子组件间的数据传递,能够很方便的在单个组件中获取到用户的权限路由列表。数组

Vuex

若是只是想简单的使用一个vuex,了解state,mutation,action就足够你使用app

在src文件夹下,建立一个store文件夹,若是项目简单,能够将state,mutations,actions,getters等写入到一个文件中ide

clipboard.png

主要代码很简单,只须要导入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主要功能是用来定义变量,表明你须要共享的一个状态。好比,我想要在每一个组件中 共享用户的路由列表,因此,我须要先在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用法的描述。
clipboard.png

上半段,将状态从根组件“注入”到每个子组件,咱们已经在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就帮了咱们很大的忙。
仍是先看官方上的文章解释
clipboard.png
咱们须要在组件的内部导入mapState,而后在computed属性里监听,以上图片无非就是说了几种状况

  • 若是你只是想单纯的使用state里的变量,那你用箭头函数的形式,会更加简单
  • countAlias:'count'//至关于给state里的count变量起了一个别名叫countAlias,调用时使用countAlias
  • 若是你须要在共享变量里添加一个其它的变量做为返回结果时,这时不可以使用箭头函数,而是常规的函数才能操做。由于箭头函数自己是没有this这个东西哒。
  • 若是state中有不少的变量,并且,你也不打算给它们起别名,或者作其它的操做,你可使用数组的形式。向state传递一个字符串的数组,state会本身一一的对应。
    mapState(['pressionList','userLogin'])

clipboard.png是数组,因此中间是 [],不是{}

mutation

有了以上的基础,咱们能够获取到一个共享的状态了,可是若是咱们须要在共享的状态上作点小动做怎么办呢?
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辅助函数

clipboard.png

也是三种状况,你能够以字符串数组的形式调用mutation里定义的事件,也能够给事件起一个别名。这个也跟state相似

  • 事件不须要起别名,事件名与mutation名一致,而且没有接收变量这种状况下,可使用
    ...mapMutations(['changePressionList'])
    注意,这里是[],以字符串数组的形式调用
  • 在须要传值的状况下,也可使用字符串数组的形式传递。可是调用时,须要传递相应的参数。

    <button @click="pressionList(list)">改变</button>
    data(){
        return {
            list:[{ path: "/B", name: "页面B" }]
        }
    }
    methods:...mapMutations([
        'pressionList'
    ])
  • add:'increment' 至关于给mutation中定义的increment事件起了一个add别名,在组件中调用时,直接调用 add便可。

action

有了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用法一致。再也不赘述

路由限制

咱们根据以上的作法,咱们获得了一个有效的路由列表。咱们能够在首页里循环这个列表,有哪一个路由咱们就渲染哪一个路由
底部路由代码

clipboard.png
即便如此,若是有人直接在地址栏里输入了他不能访问的路由,咱们该怎么办呢?
这里就须要两个知识

  • 动态添加路由
  • 改变路由文件

动态添加路由欠着吧~~

改变路由文件很简单,只须要在路由文件末尾添加一个匹配全部路由的
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'
}, )

我的公众号

对我感兴趣的盆友,也能够关注个人我的公众号---小嘀咕影院官网。会不按期更新技术知识,旅行游记以及影视推荐

clipboard.png

相关文章
相关标签/搜索