1、在项目目录下建立store目录,store目录下家里index.js文件,在index.js文件中安装vuex,且注册store仓库等相关的插件
这是index.js代码
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
const store = new Vuex.Store({
plugins: [
createPersistedState({
storage: window.sessionStorage, //这里是将state中的user对象存放在浏览器本地存储中
reducer(val) {
return {
// 只储存state中的user
user: val.user
}
}
})
],
modules,
getters
})
export default store
2、因为项目可能页面多较复杂,所以state和mutations,actions等不能写在同一个文件下,这个时候可以利用modules来区分开来,使用起来更加的简洁明了
这是getters代码
const getters = {
sidebar: state => state.app.sidebar,
language: state => state.app.language,
size: state => state.app.size,
device: state => state.app.device,
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
introduction: state => state.user.introduction,
roles: state => state.user.roles,
user: state => state.user.user,
permission_routes: state => state.permission.routes,
errorLogs: state => state.errorLog.logs,
baseApi: state => state.api.baseApi,
dictionary: state => state.user.dictionary,
updateAvatarApi: state => state.api.updateAvatarApi
}
export default getters
这是user.js代码
import { getInfo, login, logout } from '@/api/auth' //这里是登录接口
import { getToken, removeToken, setToken } from '@/utils/auth'
import router, { resetRouter } from '@/router'
import { getDictionary, getBasePort } from '@/api/commonApi' //这里是调用的后台接口,数据字典
const state = {
count: 0,
userId: 1234,
token: getToken(),
name: '',
avatar: '',
introduction: '',
roles: [],
user: {},
loadMenus: false,
dictionary: {}
}
// const user = {
// state: {
// token: getToken(),
// user: {},
// roles: [],
// // 第一次加载菜单时用到
// loadMenus: false
// }
// }
const mutations = {
ADD_COUNT: (state, amount) => {
if (amount) {
state.count = 0
return
}
state.count++
},
SET_DICTIONARY: (state, data) => {
state.dictionary = { ...state.dictionary, ...data }
},
SET_USERINFO: (state, data) => {
state.user = data
},
SET_TOKEN: (state, token) => {
state.token = token
},
SET_INTRODUCTION: (state, introduction) => {
state.introduction = introduction
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLES: (state, roles) => {
state.roles = roles
},
SET_LOAD_MENUS: (state, loadMenus) => {
state.loadMenus = loadMenus
}
}
const actions = {
/**
* 页面初始化,加载数据字典
*/
loadDitionary({ commit, state }, code) {
return new Promise((resolve, reject) => {
const params = 'ship status,biz status,purpose,fixtrue status,emailAnalyCode,Fixture Rate Unit,vessel service status,voyage type,voyage status' +
',sailing record type,loadStatus,vessel history type,loadarea,disloadarea,ship ais status,positionStatus,Freight Index,Bunker Index,Group Type' +
',consumption type,dataStatus,fence type,loadStatus,S&P Fixture Type,Analysis Series'
getDictionary(params).then(e => {
commit('SET_DICTIONARY', e.data)
resolve(true)
}).catch(error => {
reject(error)
})
getBasePort().then(res => {
if (res.data) {
const data = res.data.map(item => {
return { name: item.name, code: item.code }
})
commit('SET_DICTIONARY', { 'load area': data, 'load area detail': res.data })
resolve(true)
}
})
})
},
// user login
login({ commit }, userInfo) {
const { username, password, code, uuid } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password: password, code, uuid }).then(response => {
const { data } = response
commit('SET_TOKEN', data.token)
setToken(data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
// get user info
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const { data } = response
if (!data) {
reject('Verification failed, please Login again.')
}
const { roles, user } = data
// roles must be a non-empty array
if (!roles || roles.length <= 0) {
reject('getInfo: roles must be a non-null array!')
}
commit('SET_USERINFO', user)
commit('SET_ROLES', roles)
// commit('SET_NAME', name)
// commit('SET_AVATAR', avatar)
// commit('SET_INTRODUCTION', introduction)
resolve(data)
}).catch(error => {
reject(error)
})
})
},
updateLoadMenus({ commit }) {
return new Promise((resolve, reject) => {
commit('SET_LOAD_MENUS', true)
})
},
// user logout
logout({ commit, state, dispatch }) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resetRouter()
// reset visited views and cached views
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485
dispatch('tagsView/delAllViews', null, { root: true })
resolve()
}).catch(error => {
reject(error)
})
})
},
// remove token
resetToken({ commit }) {
return new Promise(resolve => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resolve()
})
},
// dynamically modify permissions
changeRoles({ commit, dispatch }, role) {
return new Promise(async resolve => {
const { roles } = await dispatch('getInfo')
resetRouter()
// generate accessible routes map based on roles
const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })
// dynamically add accessible routes
router.addRoutes(accessRoutes)
// reset visited views and cached views
dispatch('tagsView/delAllViews', null, { root: true })
resolve()
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
modules中的其他js同user.js类似,分别用作不同的模块
3、页面中的使用用例
<template>
<div>
<el-button @click="Add">Add</el-button>
<div>{{ userId }}</div>
<div>{{ count }}</div>
<!-- 一个按钮,点击一次count变量加一,userId是直接获取store中的state状态 -->
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex' // mapState mapMutations 是vuex的两个辅助函数,还有mapGetters等
import store from '@/store'
export default {
computed: mapState({
// Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
// 就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
userId: state => store.getters.user.gender, // 这里在index.js中可以看到在浏览器临时存储了user.js的state状态
count: state => state.user.count // 直接获取store中user分支下的count状态
}),
methods: {
Add() {
if (store.state.user.count > 9) {
store.commit('user/ADD_COUNT', true)
} else {
store.commit('user/ADD_COUNT')
}
},
// 这里使用的是mapMutations辅助函数,映射了el-button的点击事件
// ...mapMutations([
// 'user/ADD_COUNT'
// ])
//mapMutations辅助函数的第二种方式
...mapMutations({
ADD_COUNT: 'user/ADD_COUNT'
})
}
}
</script>
<style lang='scss' scoped>
</style>
注意:mutations并不是只能使用同步操作,但是官方特意说明,只能使用同步操作,因为是为了代码的维护,具体可以查看vue官方文档,如果有任何的异步操作请使用actions,去操作mutation
4、action的触发使用dispatch
this.$store.dispatch('user/loadDitionary')
分发的是user.js中的loadDionnary方法