安装:
npm install vuex --save
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// 模块化工程中,Vue.use() 是必须的
Vue.use(Vuex);
// 抛出模块,用于跟组件注册
const store = new Vue.store({
// ...
});
export default store
// main.js 需要引入 store
import store from './store/index.js';
// vue 根组件注册 store
new Vue({
store: store
});
注意:Vuex 依赖 Promise。若浏览器没实现Promise,请安装包 es6-promise 。
<!-- 单文件项目,可使用全局的script标签,省略前三步 -->
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
概念:
使用:
vuex实例对象的5个属性。创建store:
new Vuex.store({
state: {
list: [
{ id: 1, text: '...1...', done: true },
{ id: 2, text: '...2...', done: false }
]
},
// 用于提取"特征数据",类似组件的"computed"属性
getters: {
findIdIsTwo(state, id) {
return state.list.find((e) => {
return e.id === id;
})
}
},
// 作为修改"state"数据的唯一途径,但内部只能定义"同步函数"
mutation: {
addList(state, item) {
state.list.push(item);
}
},
// 类似于"mutation",但"action"提交的是"mutation",而不是直接变更数据状态,一般定义"异步函数"
actions: {
asyncAddList({ commit }) {
setTimeout(() => {
// 调用"commit"回调函数
commit('addList');
}, 2000);
},
// 组合 Action 利用Promis或async/await
// 假设 getData() 和 getOtherData() 返回的是 Promise
async actionA({ commit }) {
commit('gotData', await getData())
},
async actionB({ dispatch, commit }) {
await dispatch('actionA') // 等待 actionA 完成
commit('gotOtherData', await getOtherData())
}
},
// 当本组件太臃肿,需要拆分,则要用"model",较好的情况的是只有"model",其他属性均以组件引入
// 一般使用"import"引入模块 import moduleA from './module/moduleA'
module: {
moduleA
}
});
// 关于局部模块的注意事项
const moduleA = {
state: { count: 0 },
// 对于模块内部的 mutation 和 getter,接收的第一个参数(state)是模块的局部状态对象。
mutations: { increment(state) { } },
// 对于模块内部的 getter,根节点状态会作为第三个参数(rootState)暴露出来
getters: { sumWithRootCount(state, getters, rootState) { } },
// 对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState
actions: { incrementIfOddOnRootSum({ state, commit, rootState }) { } }
}
/* action 内能使用 "dispatch" */
使用/修改:
// 引入"辅助函数"
import { mapState, mapGetters } from "vuex";
// 获取数据的方式(以"mounted"为例)
new Vue({
computed: {
// State
// 访问数据不在模块的情况
count1() { return this.$store.state.count1 },
// 如果是模块内的,如 moduleA
count2() { return this.$store.state.moduleA.count2 },
// 使用 mapState 辅助函数 和 对象展开运算符
...mapState({
count3: state => state.moduleA.count3,
// ...
}),
// Getter
// 与 State 类似的方式引入
itemIsTwo(){ return this.$store.getters.moduleA.findId(2);},
// 使用 mapGetters 辅助函数 和 对象展开运算符
...mapGetters([
'doneTodosCount',
// ...
])
},
methods: {
handleClick() {
// 使用 Mutation ,第一个参数为 Mutation 内的方法名,第二个参数为传参(可省略)
this.$store.commit('addList', { id: 5, text: '5', done: false });
// 使用 Action ,与 Mutation 类似
this.$store.dispatch('asyncAddList', { id: 6, text: '6', done: false })
}
}
});
表单处理:
由于 "store" 的数据不能直接修改,表单使用 "v-model" 的双向绑定会报错:
<!-- 错误做法(假设"message"来源于"store") -->
<input v-model="message">
正确做法1:( "v-on" 事件发起 "commit")
<input :value="message" @input="updateMessage">
// ...
computed: {
...mapState({
message: state => state.message
})
},
methods: {
updateMessage (e) {
this.$store.commit('updateMessage', e.target.value)
}
}
正确做法2:(创建 "get" 和 "set" 方法)
<input v-model="message">
// ...
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}