引入vuex
安装依赖:npm install vuex --save
src目录下的store文件夹创建index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(vuex);
//不是生产环境debug为true
const debug = process.env.NODE_ENV !== 'production';
//创建vuex实例对象
const store = new Vuex.Store({
strict: debug,//在不是生产环境下开启严格模式
state:{
},
getters:{
},
mutations:{
},
actions:{
}
})
export default store;
再在main.js中引入Vuex
import Vue from 'vue';
import App from './App.vue';
import store from './store';
const vm = new Vue({
store: store,
render: h => h(App)
}).$mount('#app')
Vuex的核心属性
state, getters, mutations. actions, modules
State
Vuex中状态都存储state中,改变状态的唯一路径是提交mutation(e.g: this.$store.commit('SET_NUMBER', 10)
)。
当Vuex中存储的状态是对象数据类型时,需要先使用 JSON.stringify(objName)将对象转换为字符串形式,再进行存储(e.g:
this.$store.commit('createUser', JSON.stringify(user)
), 在获取到对象数据类型时,再通过JSON.parse()
进行转换。
批量使用Vuex的state状态 -> 使用mapState辅助函数
import {mapState} from 'vuex'
export default{
computed:{
...mapState(['price','number'])
}
}
Getters
主要用于提供给多个组件state的派生状态,getter接收两个参数,一个是state(局部的state),第二个是getter(可以用来访问其他的getter),如果想要访问全局的getter和state,可以使用getter的第三个参数rootState以及第四个参数rootGetters
使用方法如下:
const store = new Vuex.Store({
state: {
price: 10,
number: 10,
discount: 0.7,
todos: [
{id: 1, text: '...', done: true},
{id: 1, text: '...', done: true},
]
},
getters: {
total: state => {
return state.total * state.number;
},
discountTotal: (state,getters) => {
return state.discount * getters.total;
},
// 可以通过给getter传值的方式获取特定的state
getTodoById: (state) => (id) => {
return state.todos.find(todo=>todo.id === id)
}
}
})
可以在组件中通过计算属性computed通过this.$store.getters.total这样来访问这些getters派生的state。
computed: {
total(){
return this.$store.getters.total;
},
discountTotal(){
return this.$store.getters.discountTotal;
},
//使用和普通getters相同的方法进行引用
getTodoById(){
return this.$store.getters.getTodoById;
}
}
mounted(){
// 输出state中todos一个index的done属性
console.log(this.getTodoById(1).done)//false
}
批量使用Vuex的getters -> 使用mapGetters辅助函数
import {mapGetters} from 'vuex'
export default{
computeds: {
...mapGetters(['total','discountTotal'])
// 如果需要给getters属性取别名
//...mapGetters({
// myTotal: 'total',
// myDiscountTotal: 'discount
//})
}
}
Mutations
用于改变state中的某个状态,必须是同步函数,只有mutation中的函数能够直接变更某个状态,mutation函数的第一个值是state(局部的state,及模块的state),第二个值是data。
const store = new Vuex.Store({
state: {
number: 30,
},
mutations: {
SET_NUMBER(state,data){
state.number = data;
}
}
})
在组件中使用this.$store.commit
提交mutation,改变state中的number属性。
this.$store.commit('SET_NUMBER',10)
// 如果在组件中我们会多次提交同一个,可以借助mapMutation辅助函数
import { mapMutations } from 'vuex'
methods: {
...mapMutations({
setNumber: 'SET_NUMBER'
})
}
//然后调用方法也变得更加简洁
this.setNumber(10)
Actions
action与mutation的不同之处:
①action是提交mutation,只能间接地修改state中的属性,而mutation可以直接变更state;
②action可以是异步的(通常是异步的),而mutation只能是同步的;
③action通过this.$store.dispatch(‘ACTION_NAME’,data)进行提交,而mutation通过this.$store.commit(‘MUTATION_NAME’,data)进行提交;
④action第一个参数是context而mutation是state。
action与mutation的相同之处:
dispatch和commit的第二个参数都可以接受外部提交时传递的参数。
actions: {
SET_NUMBER_A({commit},data){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
commit('SET_NUMBER',10);
resolve();
},2000)
})
},
//如果一个异步操作的action需在另一个action结束处理后再操作,试下方法如下
async actionA({commit}){
//...
},
async actionB({dispatch}){
await dispatch('actionA')//等待actionA完成
}
}
//在组件中通过dispatch调用
this.$store.dispatch('SET_NUMBER_A').then(()=>{
//...
})
//也可以借助mapActions辅助函数
methods:{
...mapActions({
setNumberA: 'SET_NUMBER_A',
})
}
//可以直接使用setNumber进行调用
this.setNumberA().then(()=>{
//...
})
Modules
如果所有状态集成在一个对象,当状态属性过多时,store对象就会变得非常臃肿,所以将store分割成模块(module)。每个模块拥有独立的state、mutations、actions、getters。
const state = {
//...
}
const getters = {
//...
}
const mutations ={
//...
}
const actions = {
//...
}
export default{
state,
getters,
mutations,
actions
}
再在index.js引入模块
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
import moduleA from './module/moduleA';
import moduleB from './module/moduleB';
const store = new Vuex.Store({
modules:{
moduleA,
moduleB,
}
});
export default store
命名空间
默认情况下,模块内部的action、mutation和getter是注册在全局命名空间,如果多个模块中action、mutation的命名是一样的,那么提交mutation、action时,将会触发所有模块中命名相同的mutation、action。为避免这种情况,在导出模块时,添加namespaced: true
属性使其成为带有命名空间的模块。
export default{
namespaced: true,
state,
getters,
mutations,
actions
}
如果需要提交在带有命名空间的模块中的mutation或者action,用如下方法:
this.$store.commit('moduleA/mutationA',data)
//将mapState,mapGetters,mapActions和mapMutations绑定到命名空间的模块
//引入createNamespaceHelpers
import { createNamespacedHelpers } from 'vuex';
const { mapState, mapActions } = createNamespacedHelpers('moduleA');
export default {
computed: {
// 在 `module/moduleA` 中查找
...mapState({
a: state => state.a,
b: state => state.b
})
},
methods: {
// 在 `module/moduleA` 中查找
...mapActions([
'actionA',
'actionB'
])
}
}