Vuex
- 一个大型的单页面应用,当很多组件都同时依赖一个状态时,一个组件将这个状态改变,那么它要通知所有依赖它的组件,告诉他们修改值。这样互相一层一层的传值很麻烦。此时可以使用vuex集中管理状态。
- 将这个状态保存在vuex中,所有需要这个数据的组件就去这里面拿值,修改数据时,直接修改这里面的值,那么所有的组件也就都能拿到最新的值。
- 非必要情况下小项目不要使用Vuex。
快速上手
-
首先安装vuex
npm i vuex -D
-
在src下面单独创建个store文件夹,用于专门存储共享数据。在index.js中创建store仓库
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ //state里是自己要存的数据 state: { count: 0 //假如这里有的count }, //getters里面相当于vue的computed,将state中的数据处理一下return回去。不能用于修改数据 getters: { doubleCount(state) { //获取两倍的count return state.count * 2 } }, //方法区。用于修改共享数据。只能调用这里面的方法修改数据 mutations: { increment(state, paload) {//修改count,paload是调用时传梯的参数 state.count += paload } }, //异步函数。当调用的函数是异步时,就将函数写在这里,带异步函数执行完,再调用mutations里的方法修改数据。 actions: { //(执行函数上下文, 传过来的参数) incrementAsync (context, payload) { setTimeout(() => { //异步完之后调用mutations里面的方法修改数据 context.commit('increment', payload) }, 2000); } }, //当数据特别多时,store会变得特别臃肿,所以vuex有推出模块。一个大的store可以拥有很多子模块 modules: { } })
-
在入口文件中,引入刚才创建的store类
import Vue from 'vue' import App from './App.vue' import store from './store' Vue.config.productionTip = false new Vue({ store, render: h => h(App) }).$mount('#app')
-
然后就可以在组件中直接使用store中的值了
//直接和获取数据 <h1>count: {{ $store.state.count }}</h1> //进入mutations里面修改数据,调用方法必须用commit <button @click="$store.commit('increment', 3)">Mutation</button> //必须通过dispatch触发这个异步函数 <button @click="$store.dispatch('incrementAsync', 3)">AsyncMutation</button>
优化
上面那种,每次都是以store.xxx很麻烦,可以直接使用vuex中的工具简化代码
-
获取state值优化
import { mapState } from 'vuex' //vuex提供,不要格外安装模块 export default { name: 'App', computed: { //这个东西会返回一个对象,相当于 count: state => state.count ...mapState(['count', 'msg'])//count,msg是state中的共享数据,想获取几个就写进数组几个 } } //在页面中可以直接获取值 <h1>count: {{ count }}</h1> <h1>msg: {{ msg }}</h1>
-
同理,getter也可以直接用这东西改
import { mapState, mapGetters } from 'vuex' //vuex提供,不要格外安装模块 export default { name: 'App', computed: { ...mapState(['count', 'msg']), ...mapGetters(['reverseMsg']) } } //在页面中可以直接获取值 <h1>count: {{ count }}</h1> <h1>reverseMsg: {{ reverseMsg }}</h1>
-
mutation和actions是个方法,所以不能写在computed里面,要修在methods里面
//引入 import { mapGetters, mapState, mapMutations, mapActions } from "vuex"; //写在组建的methods里面 methods: { ...mapMutations(["increment"]), ...mapActions(['incrementAsync']) }, //使用时简化的直接写方法 <button @click="increment(3)">Mutation</button> <button @click="incrementAsync(8)">AsyncMutation</button>
-
如果store中的数据和自己组件中的东西重名了,可以使用这个mapxxx工具直接改名字。比如mapState
//可以不往里面传数组,直接是个对象,对象的属性就是自己给它的新名字。别的mapGetter等也可以这样 ...mapState({ mycount: 'count', mymsg: 'msg' })
-
关于module模块
当一个项目中共享的 数据比较多时,store里面的代码就会变得臃肿,所以vuex引入子模块。每个子模块可以实现自己独立的功能。并且有自己的命名空间。
vuex分发状态时,直接调用store里面的函数,可以改变store里面的公共数据。
在每个子模块中分发状态时,调用函数时指定了某个命名空间,那么这个命名空间里的值会改变。
具体看后面的购物车案例
Vuex启动严格模式
虽然state中数据必须通过mutations改变,但是直接在代码里通过state修改也可以直接修改,虽然者不符合约定,但却是可以改,这样改完出现错误,就很难定位到错误的地方。
开启严格模式后,一旦不通过mutations修改state,就会报错
export default new Vuex.Store({
strict: true,
state: {
count: 0,
msg: 'hello vuex'
},
mutations: {
},
actions: {
},
modules: {
}
})
生产模式不要开启严格模式,会影响性能。只能在开发模式下开启严格模式。如果使用的Webpack进行打包,可以通过判断webpack的模式,来动态添加这个严格模式。
strict: process.env.NODE_ENV !== 'production',