Vuex 如何使用
安装
cnpm i vuex -S
引用
在scr下键store文件夹:
建立index.js
import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import user from './modules/user'
import permission from './modules/permission'
import getters from './getters'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
app,
user,
permission
},
getters
})
export default store
store 涉及modules 定义
app.js
import Cookies from 'js-cookie'
const app = {
state: {
sidebar: {
opened: !+Cookies.get('sidebarStatus')
},
visitedViews: []
},
mutations: {
TOGGLE_SIDEBAR: state => {
if (state.sidebar.opened) {
Cookies.set('sidebarStatus', 1)
} else {
Cookies.set('sidebarStatus', 0)
}
state.sidebar.opened = !state.sidebar.opened
},
ADD_VISITED_VIEWS: (state, view) => {
if (state.visitedViews.some(v => v.path === view.path)) return
state.visitedViews.push({ name: view.name, path: view.path })
},
DEL_VISITED_VIEWS: (state, view) => {
let index
for (const [i, v] of state.visitedViews.entries()) {
if (v.path === view.path) {
index = i
break
}
}
state.visitedViews.splice(index, 1)
}
},
actions: {
ToggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
},
addVisitedViews({ commit }, view) {
commit('ADD_VISITED_VIEWS', view)
},
delVisitedViews({ commit, state }, view) {
return new Promise((resolve) => {
commit('DEL_VISITED_VIEWS', view)
resolve([...state.visitedViews])
})
}
}
}
export default app
user.js
import {getInfo, login, logout} from '@/api/login'
import {getToken, removeToken, setToken} from '@/utils/auth'
import {default as api} from '../../utils/api'
import store from '../../store'
import router from '../../router'
const user = {
state: {
nickname: "",
userId: "",
avatar: 'https://www.gravatar.com/avatar/6560ed55e62396e40b34aac1e5041028',
role: '',
menus: [],
permissions: [],
},
mutations: {
SET_USER: (state, userInfo) => {
state.nickname = userInfo.nickname;
state.userId = userInfo.userId;
state.role = userInfo.roleName;
state.menus = userInfo.menuList;
state.permissions = userInfo.permissionList;
},
RESET_USER: (state) => {
state.nickname = "";
state.userId = "";
state.role = '';
state.menus = [];
state.permissions = [];
}
},
actions: {
// 登录
Login({commit, state}, loginForm) {
return new Promise((resolve, reject) => {
api({
url: "login/auth",
method: "post",
data: loginForm
}).then(data => {
if (data.result === "success") {
//cookie中保存前端登录状态
setToken();
}
resolve(data);
}).catch(err => {
reject(err)
})
})
},
// 获取用户信息
GetInfo({commit, state}) {
return new Promise((resolve, reject) => {
api({
url: '/login/getInfo',
method: 'post'
}).then(data => {
//储存用户信息
commit('SET_USER', data.userPermission);
//cookie保存登录状态,仅靠vuex保存的话,页面刷新就会丢失登录状态
setToken();
//生成路由
let userPermission = data.userPermission ;
store.dispatch('GenerateRoutes', userPermission).then(() => {
//生成该用户的新路由json操作完毕之后,调用vue-router的动态新增路由方法,将新路由添加
router.addRoutes(store.getters.addRouters)
})
resolve(data)
}).catch(error => {
reject(error)
})
})
},
// 登出
LogOut({commit}) {
return new Promise((resolve) => {
api({
url: "login/logout",
method: "post"
}).then(data => {
commit('RESET_USER')
removeToken()
resolve(data);
}).catch(() => {
commit('RESET_USER')
removeToken()
})
})
},
// 前端 登出
FedLogOut({commit}) {
return new Promise(resolve => {
commit('RESET_USER')
removeToken()
resolve()
})
}
}
}
export default user
permission.js
import {asyncRouterMap, constantRouterMap} from '@/router/index'
/**
* 判断用户是否拥有此菜单
* @param menus
* @param route
*/
function hasPermission(menus, route) {
if (route.menu) {
/*
* 如果这个路由有menu属性,就需要判断用户是否拥有此menu权限
*/
return menus.indexOf(route.menu) > -1;
} else {
return true
}
}
/**
* 递归过滤异步路由表,返回符合用户菜单权限的路由表
* @param asyncRouterMap
* @param menus
*/
function filterAsyncRouter(asyncRouterMap, menus) {
const accessedRouters = asyncRouterMap.filter(route => {
//filter,js语法里数组的过滤筛选方法
if (hasPermission(menus, route)) {
if (route.children && route.children.length) {
//如果这个路由下面还有下一级的话,就递归调用
route.children = filterAsyncRouter(route.children, menus)
//如果过滤一圈后,没有子元素了,这个父级菜单就也不显示了
return (route.children && route.children.length)
}
return true
}
return false
})
return accessedRouters
}
const permission = {
state: {
routers: constantRouterMap, //本用户所有的路由,包括了固定的路由和下面的addRouters
addRouters: [] //本用户的角色赋予的新增的动态路由
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers
state.routers = constantRouterMap.concat(routers) //将固定路由和新增路由进行合并, 成为本用户最终的全部路由信息
}
},
actions: {
GenerateRoutes({commit}, userPermission) {
//生成路由
return new Promise(resolve => {
//roles是后台传过来的角色数组,比如['管理员','文章']
const role = userPermission.roleName;
const menus = userPermission.menuList;
//声明 该角色可用的路由
let accessedRouters
if (role === '管理员') {
//如果角色里包含'管理员',那么所有的路由都可以用
//其实管理员也拥有全部菜单,这里主要是利用角色判断,节省加载时间
accessedRouters = asyncRouterMap
} else {
//否则需要通过以下方法来筛选出本角色可用的路由
accessedRouters = filterAsyncRouter(asyncRouterMap, menus)
}
//执行设置路由的方法
commit('SET_ROUTERS', accessedRouters)
resolve()
})
}
}
}
export default permission
store 涉及getter 定义
getters.js
const getters = {
sidebar: state => state.app.sidebar,
visitedViews: state => state.app.visitedViews,
nickname: state => state.user.nickname,
userId: state => state.user.userId,
avatar: state => state.user.avatar,
role: state => state.user.role,
menus: state => state.user.menus,
permissions: state => state.user.permissions,
permission_routers: state => state.permission.routers,
addRouters: state => state.permission.addRouters
}
export default getters
在main.js 中引入store:
在页面中使用vuex
vuex 总结:
一个完整的vuex module 需要包括四个部分state,getters actions mutations,
state用来存放需要操作的数据;
gettes类似于计算属性(很少使用);
改变操作数据的方式只能通过提交至mutations;
一种是异步,通过this.$store.dispach 调用定义在actions中的方法,最后提交到mutation中的相关方法。
另外一种是同步的直接通过commit来触发mutation相关方法调用。