Vuex是Vue.js应用程序开发的状态管理模式,组件间共享的数据可以存放到这里(换句话说就是存在vuex里的数据任何组件都可以用)。它是响应式的,一个地方修改其他地方也跟着改变;注意我们在改变数据状态的时候最好不要直接修改,而是要通过this.$store.commit()
方法提交到mutation在mutation里修改,这样修改的数据才能配合devtools跟踪到数据变化;
vuex
/*安装vuex:npm install vuex --save
;创建store
文件夹,分别创建index.js
(配置vuex
)和actions.js,mutations.js,getters.js,modules.js
(分别用来处理不同状态)*/import Vuex from 'vuex'
(引入处理状态import mutations from './mutations.js'
)vuex
:Vue.use(Vuex)
const store = new Vuex.Store({state:{},mutations:{},actions:{},getters:{},modules:{}})
;建议一个项目只创建一个store
这样方便后期维护export default store
main.js
中为vue
添加store
全局属性*/ main.js
中引入index.js
的store
模块:import store from './store/index.js'
store
添加到vue
全局属性里:new Vue({store,render: h =>h(App)}).$mount('#app')
。(为什么要添加到这里。个人认为,store里的数据需要在挂载的时候用到,所以要添加到挂在前;还有一种原因可能是store相当于是一个没有DOM(没有el属性)的实例,需要使用vm.$mount()方法手动挂载)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//index.js import Vuex from 'vuex' import mutations from './mutations.js' //1.安装vuex插件 Vue.use(Vuex) //2.创建Store对象 let state = { data:[] } const store = new Vuex.Store({ state, mutations }); //3.挂载在vue实例上 export default store //main.js //1.引入store实例 import store from './store' //2.在全局挂载store,然后在任何地方都可以用$store调用这个vuex实例 new Vue({ store, render: h => h(App) }).$mount('#app') |
vuex的核心就是一个store(仓库),它相当于是一个容器,里面包含有五大核心:state,action,mutation,getter,modules。
state属性就是用来存放状态的;vuex建议只有一个状态源,这样有利于管理和维护;一开始就定义在state里的属性都会被添加到vue的响应式里,都可以做到响应式
1 2 3 4 5 6 7 8 |
//定义 state:{ name:'lele', arry:[3,4,6], obj:{name:'乐乐',age:26} } //使用 <span>{{$store.state.name}}</span>或者this.$store.state.name |
state辅助函数mapState(): 当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState
辅助函数帮助我们生成计算属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//在index.js中定义state state: { name:'lele', age: 99 } //1.引入mapstate import { mapState } from 'vuex' //2.在computed计算属性里获取需要的state状态 computed:{ ...mapState(["name",'age'])//通过展开运算符将mapState里的状态展开放在computed里,然后就可以直接使用了 } //3.在需要的地方展示 <span>{{name}}</span>或者this.name |
Getter 就是处理属性,在数据需要处理的时候,在这里处理好再丢出去;可以看作是store的一个计算属性(相当于vue的computed属性)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//定义 getters:{ supernumber(state){//第一个参数是state return state.vuenumber*state.vuenumber } ,supernumber2(state,getters){//第二个参数是getters本身 return getters.supernumber*0 } ,supernumber3(state){//如果想传参可以通过闭包的方式 return function(arg){ return state.vuenumber*arg } } } //使用 <p>{{$store.getter.supernumber}}</p>或者this.$store.getter.supernumber |
getter辅助函数mapGetters():只是将 store 中的 getter 里的属性映射到局部计算属性中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//在getter.j中定义getters getters: { filterNum(state){ return state.list.filter(item=>item.number < 10).length; }, addNumber(state){ return state.list.push(222) } } //1.引入mapGetters import {mapGetters} from 'vuex' //2.在组件的computed里展开getters属性 computed:{ ...mapGetters(["filterNum",'addNumber']) } //3.在需要的地方展示 <span>{{filterNum}}</span>或者this.filterNum |
vuex改变状态都要通过commit触发mutations来改变,这样devtools才能跟踪到每次修改的状态,以便后期维护;mutation类似于事件,写法:typeName:回调函数;只能是同步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
3.1:普通提交 带参数提交 对象式提交风格 //定义 mutations:{ vuexadd(state){//ES64h函数的增强写法;第一个参数state就是store的state state.vuenumber++ //直接返回需要的操作 }, vuexarg(state,arg){//第二个参数可以接收传过来的参数,1.传过来的参数只是一个参数 state.vuenumber = state.vuenumber * arg }, vuexarg2(state,payload){//2.传过来的参数是一个对象 state.vuenumber = state.vuenumber - payload.arg } } //使用 methods:{ vuexadd(){ this.$store.commit('vuexadd')//使用vuex里的方法,必须通过commit提交才能拿到,第一个参数是需要提交的事件名称 }, vuexarg(arg){//第二个参数可以传参,1.直接传一个参数参数 this.$store.commit('vuexarg',arg); }, vuexarg2(arg){//2.传一个对象 this.$store.commit({ type:'vuexarg2', arg }) } } 3.2:mutations里修改状态遵循vue的响应规则(最好一开始就在state里初始化好所有的属性);添加新的响应属性用vue.set(),删除属性并响应vue.delete() //mutations里定义 vuexsetobj(sate,arg){//属性的增删改 sate.obj.name = '我能改变已有的属性,并且是响应式的';//改 Vue.set(sate.obj,'height',arg+'cm');//增 Vue.delete(sate.obj,'sex')//删 } //需要的组件里使用 vuexsetobj(arg){ this.$store.commit('vuexsetobj',arg) } 3.3:用常量代替事件类型 在大型应用程序中使用常量代替事件类型可以让每个人都能清楚的看到mutation里都有什么操作 官方推荐使用 3.3.1:在store里创建一个单独的mutation-types.js存放常量 export const IAMCONST = 'IAMCONST' 3.3.2:在mutations.js中定义mutation import * as types from './mutation-types' mutations:{ [types.IAMCONST](state){ state.consttest = '==>!!!'+state.consttest+'!!!'; } } 3.3.3:在app.vue里使用 import {IAMCONST} from './store/mutation-types' //也可以使用import * as types from './mutation-types' methods:{ consttest(){ this.$store.commit(types.IAMCONST) } } |
mutation辅助函数mapMutations(): 当组件中有多个提交mutation触发state改变时,代码会显得重复冗余,mapMutations()就可以很好的解决这个问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//在mutations.js中定义mutations mutations: { add(state, n) { state.stus.push(n) } } //1.引入mapMutations import {mapMutations} from "vuex" //2.在methods中展开需要提交的mutation methods:{ ...mapMutations(["add"])//不用一个一个提交了 } //3.在需要的地方触发该方法 <div @click='add('增加')'></div> |
有异步操作时,需要先dispath提交到actions里,然后再commit到mutations中触发数据更新,以便跟踪状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
//定义 actions:{//异步的时候跟踪修改的状态 actiontest(context,payload){//context是上下文 这里就是store对象 setTimeout(function(){ context.commit('changeTimer');//提交给mutations的方法 console.log(payload) },1000) } } mutations(){//异步处理也是要经过mutations的 changeTimer(state){ state.timer = state.timer*666; } } //使用 actiontest(){ this.$store.dispatch('actiontest','我是payload') } //当你想要在异步操作修改数据完成的时候告诉你一声,或者完成的时候传一些数据;可以通过返回一个promise的方式来实现 //定义 mutations(){//异步处理也是要经过mutations的 changeTimer(state){ state.timer = state.timer*666; } } actions:{ actionpro(context,payload){ return new Promise((res,rej)=>{ setTimeout(function(){ context.commit('changeTimer'); },500); res('我是成功时传递出来的数据'); }) } } //使用 actionpro(){ this.$store.dispatch('actionpro').then(res=>console.log(res)) } |
action辅助函数mapActions():跟mapState、mapGetters...一样,减少代码重复和冗余
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//actions.js中设置actions actions:{ actiontest(context){ setTimeout(function(){ context.commit('changeTimer'); },1000) } } //mutations.js设置mutations mutations(){ changeTimer(state){ state.timer = state.timer*666; } } //1.引入mapActions import {mapActions} from "vuex" //2.在methods里展开action的事件 methods:{ ...mapActions(["actiontest"])//不用再一个一个dispath } //3.再需要异步操作修改数据的地方使用 <button @click="actiontest">点击修改数据</button> |
当state有太多的时候可以抽离成不同的模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
const moduleA={ state:{ name:'我是a模块的state的name值' } ,getters:{//可以传递三个参数rootstate就是根部的state fullname(state){ return state.name+'111' }, fullname2(state,getters){ return getters.fullname+'222' }, fullname3(state,getters,rootstate){ return getters.fullname2+rootstate.vuenumber } } ,mutations:{} ,actions:{ lastone(context){//这里的context上下文是moudleA有rootGetters和rootState属性 console.log(context); setTimeout(function(){ context.commit('lastchange') },2000) } } } modules:{ a:moduleA } 1.a模块state数据调用:<span>{{$store.state.a.name}}</span> 2.getters 使用和原来一样 3.mutation的使用和原来一样 4.actions的使用和原来一样 |
dispath
触发actions
来提交异步修改数据的操作actions
中通过commit
触发mutations
来修改数据mutations
接收到commit
的提交,就会通过mutate
修改state
状态 (如果操作不是异步可以直接通过commit
将改变数据的操作提交给mutations
) store
触发每一个调用它的组件