初识 vuex
写在前面
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
我为什么使用vuex
当我们的应用遇到多个组件共享状态时 Vuex 可以帮助我们管理共享状态
本笔记只做参考, 官方学习入口点击这里
不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。
一个简单地 vuex
预热前奏
// store.js
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
const state = {} // 数据仓库
const mutations = {} // 操作方法
const actions = {} // 操作方法命令
const getters = {} // 数据计算
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
这几个属性是干啥玩意儿呢?
state 仓库数据,用于存储数据
mutations 操作仓库数据的方法集合,建议用于对仓库单个数据的操作
actions 派发事件 | 可执行的其他操作 | 可用异步代码或多个事件派发【简言之: 生而为数据的复杂操作】
getters 仓库数据的计算属性,形如组件中的 computed 的使用
以上是一个基本的 vuex 仓库,要想在项目中使用,我们还需要在 main.js 中引入并挂载
// main.js
import store from "./store.js" // 引入
new Vue({
store, // 挂载
render: h => h(App)
}).$mount("#app");
为了更加清晰地使用vuex,我们初步对文件代码进行分离
分离 & 使用
分离
# 目录
|-- store
|-- index.js
|-- state.js
|-- mutations-type.js
|-- mutations.js
|-- actions.js
index.js 使用 vuex 入口
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import * as getters from './getters'
import * as actions from './actions'
Vue.use(Vuex)
export default new Vuex.Store({
state,
mutations,
getters,
actions
})
state.js 数据集结地
const state = {
list: [],
tempList: []
}
export default state
mutations-type.js 事件名
export const SET_LIST = 'SET_LIST'
export const SET_TEMP_LIST = 'SET_TEMP_LIST'
mutations.js 管家
import * as types from './mutations-type'
const mutations = {
/*************************************
*** 变更state中的某数据状态
*************************************/
[types.SET_LIST](state, list) {
state.list = list
},
[types.SET_TEMP_LIST](state, list) {
state.tempList = list
}
}
export default mutations
actions.js 带Buff的管家
import axios from "axios";
import * as types from "./mutations-type";
export const actions = {
/****************************************
*** 可包含任何异步请求
*** 多重命令mutation, 并非直接变更数据
****************************************/
async getListAndSet({ commit }, queryParams) {
const ret = await axios.get('api/test/test1', {
params: queryParams
}).then(res => res.data.data)
commit(types.SET_LIST, ret)
commit(types.SET_TEMP_LIST, ret)
localStorage.setItem('_list', ret)
}
}
getters.js 数据计算输出
export const list = state => state.list
export const tempList = state => state.tempList
export const whiteUser = state => state.list.filter(item => (/白/g).test(item.nickname))
使用 & 辅助函数
在 .vue 中使用 vuex 数据, 我们可以在计算属性(computed)中先定义
computed: {
list() {
return this.$store.getters.list;
},
tempList() {
return this.$store.getters.tempList;
},
whiteUser() {
return this.$store.getters.whiteUser;
}
}
再后来于组件中正常访问即可
<template>
<div class = "list">
<div class="item" v-for="(user, index) in list" :key="index"> {{ user.nickname }} </div>
</div>
</template>
组件中提交 mutations & 分发 actions
export default {
methods: {
setListData() {
const data = [
{ nickname: '小白1', age: 18 },
{ nickname: '小白2', age: 17 },
{ nickname: '小黑', age: 19 }
]
// 组件中 提交 mutations
this.$store.commit("SET_LIST", list);
},
getListAndSetData() {
// 组件中 分发 actions
this.$store.dispatch("getListAndSet", {
page: 1,
limit: 20
});
}
}
}
辅助函数 映射 vuex 数据/方法到局部组件中【喜欢就用: 推荐】
- mapMutations
- mapActions
- mapGetters
- ...
import { mapGetters, mapMutations, mapActions } from "vuex";
export default {
methods: {
setListData() {
const data = [
{ nickname: '小白1', age: 18 },
{ nickname: '小白2', age: 17 },
{ nickname: '小黑', age: 19 }
]
this.SET_LIST(list);
},
getListAndSetData() {
this.getListAndSet({
page: 1,
limit: 20
});
},
// mapMutations & mapActions 都在 methods 中进行映射
...mapMutations(["SET_LIST"]),
...mapActions(["getListAndSet"])
},
computed: {
// mapState & mapGetters 都在 computed 中进行映射
...mapGetters(["list", "tempList", "whiteUser"])
}
}
辅助函数参数还可以是对象
export default {
methods: {
setListData() {
const data = [
{ name: '小白1', age: 18 },
{ name: '小白2', age: 17 },
{ name: '小黑', age: 19 }
]
this.setList(data) // 提交 mutations 设置列表数据
},
// 辅助函数接收对象形式,其它函数形式也是如此
...mapMutations({
setList : 'SET_LIST',
})
}
}
如果项目够大/复杂 vuex 的 Module 就可以发挥巨大作用
模块化(全局命名空间)
# 基本目录结构
|-- store
|-- modules
|-- global.js
|-- test.js
|-- index.js
|-- types.js
# 当然, 我们可以细分每个模块
store 入口文件
import Vue from 'vue'
import Vuex from 'vuex'
// 管理模块
import test from './modules/test'
import global from './modules/global'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
test,
global
},
})
export default store;
types.js
export const SET_LIST = 'SET_LIST';
export const SET_TEMP_LIST = 'SET_TEMP_LIST';
// global
export const SET_TOKEN = 'SET_TOKEN'
modules/test.js
// test module
import * as types from '../types';
import axios from "axios"
const state = {
list: [],
tempList: []
}
const mutations = {
[types.SET_LIST](state, list) {
state.list = list
},
[types.SET_TEMP_LIST](state, list) {
state.tempList = list
}
}
const actions = {
async getListAndSet({ commit }, queryParams) {
const ret = await axios.get('api/test/test1', {
params: queryParams
}).then(res => res.data.data)
commit(types.SET_LIST, ret)
commit(types.SET_TEMP_LIST, ret)
localStorage.setItem('_list', ret)
}
}
const getters = {
list: state => state.list,
tempList: state => state.tempList,
whiteUser: state => state.list.filter(item => (/白/g).test(item.nickname))
}
export default {
state,
actions,
getters,
mutations
}
全局命名空间 的模块化,我们可以按照以往方式正常获得属性或方法, 因为它们都默认被注册于全上.
考虑模块理应具有封装/复用性, 不喜欢命名上有所冲突, 所以
模块化 & namespace
为 vuex 模块添加命名空间时,我们需要探讨的几个问题
- 如何给 vuex 模块添加命名空间
- 在带命名空间的模块中访问全局命名空间内容
- 添加了命名空间的模块在组件中访问方式
给vuex模块添加命名空间&访问全局命名空间内容
/**
* 添加命名空间的vuex模块的actions&getters的参数对象选项中会自动添加 rootState/rootGetters 方便我们访问全局属性
* 添加命名空间的vuex模块的actions中想要访问全局下的 dispatch 或 commit, 需要赋予第三个参数 { root: true } 表示授权
*/
import * as types from '../types';
import axios from "axios"
const state = {
listNameSpace: []
}
const mutations = {
["SET_LIST"](state, list) {
state.listNameSpace = list
}
}
const actions = {
// 带命名空间的 module 中 dispatch 和 commit 都被局部化,可以通过第三个参数对象 {root: true} 访问
// 参数对象中会自动添加参数 rootState rootGtters, 分别表示全局下的数据
async getListAndSetNamespace({
dispatch,
commit,
rootState,
rootGetters
}, queryParams) {
const ret = await axios.get('api/test/test1', {
params: queryParams
}).then(res => res.data.data)
commit('SET_LIST', ret) // 访问局部的 test_namespace/SET_LIST
commit("SET_LIST", ret, { root: true }) // 访问全局下的 SET_LIST
dispatch("getListAndSet", ret, { root: true }) // 访问全局下的 getListAndSet
console.log('rootState: ', rootState)
console.log('rootGetters: ', rootGetters)
}
}
const getters = {
// 带命名空间的 module 中 state 和 getters 都被局部化, 会自动添加 第三个参数(rootState)第四个参数(rootGetters)可以通过它们访问全局属性
ListNameSpaceGetters(state, getters, rootState, rootGetters) {
return rootGetters.tempList
}
}
export default {
namespaced: true,
state,
actions,
getters,
mutations
}
在组件中访问带命名空间的vuex模块
<template>
<div>
ListNameSpaceGetters: {{ ListNameSpaceGetters }}
<van-button @click="namespaceGetDataAndSetData">局部组件的actions调用</van-button>
</div>
</template>
import { mapGetters, mapActions } from "vuex";
export default {
name: "test",
data() {
return {};
},
methods: {
namespaceGetDataAndSetData() {
this.getListAndSetNamespace()
},
...mapActions({
getListAndSetNamespace: 'test_namespace/getListAndSetNamespace'
})
},
computed: {
...mapGetters({
listNameSpaceGetters: "test_namespace/ListNameSpaceGetters"
})
}
};
vuex 日志使得我们可以在 console 愉快地查看对 vuex 的操作
vuex 日志
// store 入口文件中添加 4 行代码
import Vue from 'vue'
import Vuex from 'vuex'
// 管理模块
import test from './modules/test'
import global from './modules/global'
import createLogger from 'vuex/dist/logger' // 1
Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production' // 2
const store = new Vuex.Store({
modules: {
test,
global
},
// vuex工具
strict: debug, // 3
plugins: debug ? [createLogger()] : [] // 4
})
export default store;
结语
笔记仅供参考, 如有错误还请朋友们不吝指出.