文章目录
1.getter
store中的计算属性
比如:初始的状态值为0
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count:0}
})
通过计算属性改变count的值,如果不用vuex的话
<div id='ex1'>
<p>Computed count:"{{addCount}}"</p>
</div>
var vm = new Vue({
el:"#ex1",
data:{count:0},
computed:{
addCount:funtion(){
return this.count + 3
}
})
结果:
Computed count:3
现在,使用vuex,就要在store里的getters来改变count
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count:0},
getters:{
addCount:state => {
return state.count + 3;}
}
})
原本写在计算属性里面的addCount方法,写在了getters里面,然后computed属性里面直接返回store.getters对象的addCount
const Counter={
template:"<div id='ex1'>
<p>Computed count:{{addCount}}</p>
</div>",
computed:{
addCount(){
return this.$store.getters.addCount}
}
1.1 mapGetters辅助函数
已知有getter方法addCount
export default new Vuex.Store({
state: {
count: 0,
name: "xixi"
},
getters: {
addCount: state => {
return state.count + 3;
}
},
//.......
不使用mapGetters时
computed: {
addCount() {
return this.$store.getters.addCount;
}
},
使用mapGetters时
首先在组件中导入mapGetters
import {mapGetters} from 'vuex';
然后在mapGetters里面建立addCount方法的映射,这里取名为myAddCount
computed: { ...mapGetters({ myAddCount: "addCount" }) },
那么相应的,在模板里
<div class="c">{{ myAddCount }}</div>
1.2mapState辅助函数
已知state里面有count为1
export default new Vuex.Store({
state: {
count: 1,
name: "xixi"
},
不使用mapState的情况下
computed: {
count() {
return this.$store.state.count;
}
},
同时模板中
<div class="d">{{ count }}</div>
使用mapState的情况下
在组件中引入mapState
import { mapState } from "vuex";
然后用展开运算符讲mapState里面的对象混入到computed属性里面
computed: {
...mapGetters({ myAddCount: "addCount" }),
...mapState({
count: state => state.count
})
},
2.mutation
1.mutation翻译过来有改变,转变的意思,即用来改变状态。
2.更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
3.类似store中的事件
4.mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler),并且它会接受 state 作为第一个参数
5.Mutation 必须是同步函数
比如:初始值状态为1
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count:1}
})
如果不使用vuex来改变
<div id="ex2">
<p>subtractCount count:{{count}}</p>
<button @click="subtractCount">subtractCount</button>
</div>
var vm2 = new Vue({
el:'#ex2',
data:{count:1},
methods:{
subtractCount:function(){
return this.count-3}
}
})
使用vuex,把methods的回调写到mutations里面,相当于事件注册
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count:1},
mutations:{
subtractCount(state){
state.count-=3}
}
})
然后用commit方法提交mutation(这里是同步触发的)
const count2 = {
template:'<div>
<p>subtractCount count:{{count}}</p>
<button @click="$store.commit('subtractCount')">subtractCount</button>
</div>'
}
提交载荷
可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload)
//...
mutations:{
subtractCount(state,n){
state.count-=n}
}
store.commit('subtractCount',3)
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读
// ...
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
store.commit('increment', {
amount: 10
})
3.action
1.action类似于mutation
2.action提交的是mutation,而不是直接变更状态
3.action可以包含任意异步操作
如果想异步的触发mutations里面的事件,那么就要在action里面写一个异步函数来提交mutations里面的事件
比如:初始状态为2
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count:2},
mutations:{
subtractCount(state){
state.count-=3}
},
actions:{
subtractCountAsync(context){
//Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,
//因此你可以调用 context.commit 提交一个 mutation
//或者通过 context.state 和 context.getters 来获取 state 和 getters。
setTimeout(()=>{context.commit("subtractCount")},1000)
}
}
})
实践中,我们会经常用到 ES2015 的 参数解构 来简化代码
actions: {
increment ({ commit }) {
setTimeout(()=>{commit("subtractCount")},1000)
}
}
然后Action 通过 store.dispatch 方法触发
const count2 = {
template:'<div>
<p>subtractCount count:{{count}}</p>
<button @click="$store.dispatch('subtractCountAsync')">subtractCountAsync</button>
</div>'
}
载荷形式
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state:{
count:2},
mutations:{
subtractCount(state,n){
state.count-=n}
},
actions:{
subtractCountAsync({commit},n){
setTimeout(()=>{commit("subtractCount",n)},1000)
}
}
})
同样以载荷形式分发
store.dispatch('incrementAsync', 3)
异步操作如何得到结果
store.dispatch可以处理action里面的函数所返回的Promise,并且store.dispatch 仍旧返回 Promise
假如state里面有个name属性,点击按钮会在一段时间后弹出欢迎弹窗,
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
name: "xixi"
},
mutations:{
greet(state) {
alert("Hello" + state.name);
}
},
actions:{
greetAsync({ commit }) {
return new Promise(resolve => {
setTimeout(() => {
commit("greet");
resolve();//将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved)
//在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
}, 10000);
});
}
})
然后用then方法处理成功后的回调函数
const showname = {
template:'<div><button @click="$store.dispatch('greetAsync')then(() => showName())"> 点击弹出欢迎</button></div>',
methods: {
showName: function() {
console.log(this.$store.state.name);
}
}
}
mapActions
已知actions里面有一个gerrtAsync方法
actions: {
greetAsync({ commit }) {
return new Promise((resolve, reject) => {
if (
setTimeout(() => {
commit("greet");
}, 10000)
) {
resolve();
} else {
reject(1);
}
});
}
},
如果不使用mapActions
</button>
<button @click="$store.dispatch('greetAsync').then(() => showName())">
如果使用mapActions
那么先引入mapActions
import { mapActions } from "vuex";
在methods里面吧$store.dispatch(‘greetAsync’)映射为"greetAsync"
methods: {
...mapActions(["greetAsync"])
}
};
然后再html里面用greetAsync()代替$store.dispatch(‘greetAsync’)
<button @click="greetAsync().then(() => showName())">
点击弹出欢迎
</button>
mapActions里面带参数的用法
已知actions里面有multiplyAsync方法他带有一个参数playload
actions: {
multiplyAsync({ commit }, playload) {
setTimeout(() => {
commit("multiplyCount", playload);
}, 1);
}}
不用mapactions的情况
<button @click="$store.dispatch('multiplyAsync', { amount: 3 })">
如果使用mapActions
首先引入mapActions
import { mapActions } from "vuex";
在方法里面把$store.dispatch(‘multiplyAsync’, { amount: 3 })映射为"multiplyAsync"
这里是分发多个actions
methods: {
showName: function() {
console.log(this.$store.state.name);
},
...mapActions(["greetAsync", "multiplyAsync"])
}
最后在html里面把$store.dispatch(‘multiplyAsync’, { amount: 3 })改为multiplyAsync({ amount: 3 })
<button @click="multiplyAsync({ amount: 3 })">
点击得到3的倍数
</button>
Module
module是模块的意思
为了解决单一状态数造成store变得复杂臃肿的问题,我们可以将store分割成模块。
每个模块都拥有自己的mutation、action、getter、甚至是嵌套子模块。
在工程中新建一个名为modules的文件夹
里面放入需要分割的模块文件,这里为Blog.js
我们来看Blog.js内部
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
// eslint-disable-next-line no-unused-vars
const Blog = {
state,
actions,
mutations,
getters
};
export default Blog;
const state = {
blogTitle: "雯雯Blog",
views: 10,
blogNumber: 100,
total: 0,
todos: [
{ id: 1, done: true, text: "我是lala" },
{ id: 2, done: false, text: "我是feifei" },
{ id: 3, done: true, text: "我是xixi" }
]
};
const mutations = {
addViews(state) {
state.views++;
},
blogAdd(state) {
state.blogNumber++;
},
clickTotal(state) {
state.total++;
}
};
const getters = {
getToDo(state) {
return state.todos.filter(item => item.done === true);
}
};
const actions = {
addViews({ commit }) {
commit("addViews");
},
clickTotal({ commit }) {
commit("clickTotal");
},
blogAdd({ commit }) {
commit("blogAdd");
}
};
能够看出他拥有自己的mutation、action、getter等,一定要记得导出
export default Blog;
模块写好之后在index.js里面的modules里面导入,前面的部分省略了
import Vue from "vue";
import Vuex from "vuex";
import Blog from "./modules/Blog";
Vue.use(Vuex);
export default new Vuex.Store({
//......
modules: {
Blog//这里使用了es6的新特性,未指定属性名,默认属性值和属性名同名,相当于Blog:Blog
}
});