# vuex ## 介绍 专为 Vue.js 应用程序开发的**状态管理模式**, 采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. https://vuex.vuejs.org/zh/ ![image-20210127204118836|788x443](https://img.081024.xyz/image-20210127204118836.png) 1. 修改state状态必须通过 **`mutations`** 2. **`mutations`** 只能执行**同步**代码,类似 ajax、定时器之类的代码不能在mutations中执行 3. 执行**异步**代码,要通过 **`actions`** ,然后将数据提交给 `mutations` 才可以完成 4. state 的状态即共享数据可以在组件中引用 5. 组件中可以调用 action / mutations ## 使用场景 不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。如果您的应用够简单,您最好不要使用 Vuex ## 下载 安装 ```bash npm install vuex --save ``` ```js import Vue from 'vue' import Vuex from 'vuex' Vue.use(vuex) const store = new Vuex.Store({}) new Vue({ el: '#app', store }) ``` ==Vuex有五个最重要的构造器: state, mutations, actions, getters, modules== ## state > state是放置所有公共状态的属性,如果你有一个公共状态数据 , 你只需要定义在 state对象中 ​几种使用方法: ### 原始调用 组件中可以使用 **this.$store** 获取到vuex中的store对象实例 ```html
state的数据:{{ $store.state.count }}
``` ### 结合计算属性 将state属性定义在计算属性中 ```js computed: { count () { return this.$store.state.count } } ``` ### 辅助函数 mapState > 方便获取多个状态, 像前面在 computed 里多次定义太啰嗦 ```js // 第一步:导入mapState import { mapState } from 'vuex' // 第二步:采用数组形式引入state属性 // 第三步:mapState函数返回的是对象, 利用展开运算符合并到计算属性里 computed: { ...mapState([ 'count', 'count2', //... ]) } // 如果计算属性的名称和state的子节点名称不同 computed: { ...mapState({coutAlias: state => state.cout}), } // 使用
state的数据:{{ count }}
``` ## getters > 除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到 getters > 可以认为是 store 的计算属性 例如,state中定义了list,为1-10的数组,组件中,需要显示所有大于5的数据 ```js state: { list: [1,2,3,4,5,6,7,8,9,10] }, getters: { // getters函数的第一个参数是 state // 必须要有返回值 filterList: state => state.list.filter(item => item > 5) } ``` ===通过属性访问时会进行缓存=== getter 可以返回一个函数, 实现向 getter 传参 ```js state: { list: [1,2,3,4,5,6,7,8,9,10] }, getters: { // getters函数的第一个参数是 state // 必须要有返回值 filterList: state => (n)=>state.list.filter(item => item > n) } ``` ===通过函数每次都进行调用不会缓存=== ### 原始调用 ```vue
{{ $store.getters.filterList }}
``` ```vue
{{ $store.getters.filterList(5) }}
``` ### 结合 computed ```js computed: { filterList () { return this.$store.getters.filterList } } ``` ### 辅助函数 mapGetters ```js computed: { ...mapGetters(['filterList']) } // 重命名 computed: { ...mapGetters({filterListAlias:'filterList'}) } // ...
{{ filterList }}
``` ## mutations > state数据的修改只能通过mutations,并且mutations必须是同步更新, 不能写异步代码 (比如axios) mutations是一个对象,对象中存放修改state的方法 ```js mutations: { // 方法里参数 第一个参数是当前store的state属性 // 第二个可选参数payload, 载荷 运输参数, 外部调用mutaiions的时候可以传递参数 addCount (state, data) { state.count += data } }, ``` ### this.$store.commit ```js // 调用方法 //... //... methods: { addCount(num){ this.$store.commit('addCount', num) // commit 提交 } } ``` ### mapMutations > mapMutations和mapState很像,它把位于mutations中的方法提取了出来,我们可以将它导入 ```js import { mapMutations } from 'vuex' methods: { ...mapMutations(['addCount']), } // 对像写法, 重命名 methods: { ...mapMutations({changeAllDistrictAlias:'changeAllDistrict'}) } ``` ## actions > state是存放数据的,mutations是同步更新数据,actions则负责进行异步操作(比如请求, 定时器) ```js // 定义actions actions: { // 第一个参数context表示当前的store的实例,可以通过 context.state 获取状态,也可以通过context.commit 来提交mutations,也可以 context.dispatch调用其他的action // 第二个参数data 可选 getAsyncCount (context) { // 这里可以用解构 getAsyncCount({ commit }) setTimeout(function(){ context.commit('addCount', 123) // 对应的可以简写 commit('addCount', 123) }, 1000) }, // 写法2 getAsyncCount ({commit}) { setTimeout(function(){ commit('addCount', 123) }, 1000) }, } ``` ### 原始调用 ```js addAsyncCount () { this.$store.dispatch('getAsyncCount') // dispatch 委派 } ``` ```js // 传参 addAsyncCount () { this.$store.dispatch('getAsyncCount', 123) } ``` ### mapActions > actions也有辅助函数,可以将action导入到组件中 ```js import { mapActions } from 'vuex' methods: { ...mapActions(['getAsyncCount']) } // 重命名 methods: { ...mapActions({ initialDistrictAlias: 'initialDistrict' }) } ``` 直接通过 this.方法就可以调用 ```vue ``` ## Module > 每个子模块都是一个对象, 可以自己拥有state, mutations, actions, getters ```js const store = new Vuex.Store({ modules: { user: { state: { token: '12345' } }, setting: { state: { name: 'Vuex实例' } } }) ``` ### 原始调用 ```vue // store.state.模块名.字段名 ``` ### 配合 getters + mapGetters ```js // 配合getters简写 getters: { token: state => state.user.token, name: state => state.setting.name } // 再配合mapGetters computed: { ...mapGetters(['token', 'name']) } ``` ### 命名空间 ==注意: 默认情况下,模块内部的 action、mutation 和 getter 是注册在**全局命名空间**的==(简单的说不加模块名直接带上字段名就可以调用 state.token) , 为了保证内部模块的高封闭性,采用namespaced来进行设置 ```js user: { namespaced: true, // 命名空间 state: { token: '12345' }, mutations: { // 这里的state表示的是user的state updateToken (state) { state.token = 678910 } } }, ``` 方案1:**带上模块的属性名路径** ```js // 对于有命名空间的action和mutation, 要带上 '命名空间/模块名' methods: { ...mapMutations(['user/updateToken']), test () { this['user/updateToken']() } } ``` ```js // 调用模块里的mutatios/actions this.$store.dispatch('user/getUserInfo') this.$store.commit('user/getUserInfo') ``` ```js computed: { // 把模块名字符串当成第一个参数传进去 ...mapState('some/nested/module', { a: state => state.a, b: state => state.b }) }, methods: { ...mapActions('some/nested/module', [ 'foo', 'bar' ]) } ``` 方案2: **createNamespacedHelpers** 创建基于某个命名空间辅助函数 ```js import { mapGetters, createNamespacedHelpers } from 'vuex' // ... const { mapMutations: mapMutationsUser } = createNamespacedHelpers('user') //创建出属于当前模块的辅助函数, 是一个对象, 里面包括mapGetters, mapState, mapMutations // 解构并重命名 export default { computed: { ...mapGetters(['token', 'appName']) // 这里就是子模块里的 }, methods: { ...mapMutationsUser(['setUserInfo']) } } ``` ## 持久化 `VuexPersistence` https://www.npmjs.com/package/vuex-persist https://www.cnblogs.com/lemoncool/p/9645587.html ### Steps Import it ``` import VuexPersistence from 'vuex-persist' ``` > NOTE: In browsers, you can directly use `window.VuexPersistence` Create an object ```js const vuexLocal = new VuexPersistence({ storage: window.localStorage }) ``` Use it as Vue plugin. ```js const store = { state: { ... }, mutations: { ... }, actions: { ... }, plugins: [vuexLocal.plugin] } ``` vuex-persist 的详细属性: | 属性 | 类型 | 描述 | | ------------ | ---------------------------------- | ------------------------------------------------------------ | | key | string | 将状态存储在存储中的键。默认: 'vuex' | | storage | Storage (Web API) | 可传localStorage, sessionStorage, localforage 或者你自定义的存储对象. 接口必须要有get和set. **默认是: window.localStorage** | | saveState | function (key, state[, storage]) | 如果不使用存储,这个自定义函数将保存状态保存为持久性。 | | restoreState | function (key[, storage]) => state | 如果不使用存储,这个自定义函数处理从存储中检索状态 | | reducer | function (state) => object | 将状态减少到只需要保存的值。默认情况下,保存整个状态。 | | filter | function (mutation) => boolean | 突变筛选。看mutation.type并返回true,只有那些你想坚持写被触发。所有突变的默认返回值为true。 | | modules | string[] | 要持久化的模块列表。 | ## 总结 * state 仓库状态对象 * mutations 改变数据的函数, 同步 * action 异步函数 * getters 类似计算属性的数据获取 * modules 子模块