文章目录
- 一、Vuex 是什么?
- 二、核心概念
- 三、Vuex 的工作流程
- 四、什么情况下我应该使用 Vuex?
- 五、Vuex 的使用
- 六、使用示例
- 七、状态持久化
- 1、手动利用HTML5的本地存储
- 2、利用vuex-persistedstate插件
- 2.1、安装
- 2.2、配置
一、Vuex 是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方生态系统中,并且在开发大型、复杂单页应用(SPA)时尤其有用。
二、核心概念
-
state:定义应用程序状态的数据。(数据,类似data)
-
mutations:用于修改状态的方法。(执行,类似methods)
-
actions:用于触发 mutations 的方法。(事件,类似controller)
-
getters:用于获取 state 中的数据。(数据加工,类似computed)
-
modules:使用单一状态树,致使应用的全部状态集中到一个很大的对象,所以把每个模块的局部状态分装使每一个模块拥有本身的 state、mutation、action、getters、甚至是嵌套子模块;
三、Vuex 的工作流程
-
通过dispatch去提交一个actions,
-
actions接收到这个事件之后,在actions中可以执行一些异步|同步操作,根据不同的情况去分发给不同的mutations,
-
actions通过commit去触发mutations,
-
mutations去更新state数据,
-
state更新之后,就会通知vue进行渲染
四、什么情况下我应该使用 Vuex?
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式 (opens new window)就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
五、Vuex 的使用
-
定义 state:定义应用程序的状态数据。
-
定义 mutations:定义修改 state 的方法。
-
定义 actions:定义触发 mutations 的方法,可以包含异步操作。
-
定义 getters:定义获取 state 中数据的方法。
-
创建 store:将 state、mutations、actions、getters 组合成一个 store 对象。
-
在应用程序中使用 store:在应用程序中使用 store 对象的 state、mutations、actions、getters。
Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:
-
应用层级的状态应该集中到单个 store 对象中。
-
提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
-
异步逻辑都应该封装到 action 里面。
只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。
六、使用示例
以购物车为例,介绍vuex的使用全过程。
// vuex的入口文件,封装了cart模块,直接引入使用
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import cart from './cart'
Vue.use(Vuex)
export default new Vuex.Store({modules: {cart}
})
// cart模块的首页,引入了getters,actions,mutations
// 以及state中模拟的数据
// store/cart/index.js
import getters from "./getters"
import actions from "./actions"
import mutations from "./mutations"export default {state:{goods: [{id:1,name:'小米手机',price: 2000,count: 0,},{id:2,name:'苹果手机',price: 3000,count: 0,},{id:3,name:'华为手机',price: 4000,count: 0,}],},getters,actions,mutations
}
// getters文件,计算购物车的总价及数量
// store/cart/getters.js
export default {totalPrice(state){return state.goods.reduce((total,item)=>{total += item.price * item.countreturn total},0).toFixed(2)},count(state){return state.goods.reduce((total,item)=>{total += item.countreturn total},0)}
}
// actions文件,用于提交商品数量的变化
// store/cart/actions.js
export default {add({commit},payload){commit('add',payload)},reduce({commit},payload){commit('reduce',payload)}
}
// mutations文件,用于改变state中商品的数量变化
// store/cart/mutations.js
export default {add(state,index){state.goods[index].count++},reduce(state,index){if(state.goods[index].count>=1){state.goods[index].count--}},
}
// 这里是使用vuex的页面,展示购物车页面
// app.vue
<template><div class="about"><div v-for="(item, index) in goods" :key="index"><div>{{ item.name }}</div><div>{{ item.price }}</div><div style="display: flex"><button @click="reduce(index)">-</button><div>{{ item.count }}</div><button @click="add(index)">+</button></div></div><div style="display: flex;"><div>总计:{{ count }}</div><div>结算:{{ totalPrice }}</div></div></div>
</template><script>
import { mapGetters,mapState } from 'vuex'
export default {computed: {...mapState({goods(state) {return state.cart.goods},}),...mapGetters(['count', 'totalPrice'])},methods: {add(index) {this.$store.dispatch('add', index)},reduce(index) {this.$store.dispatch('reduce', index)}}
}
</script>
七、状态持久化
vuex优势: 相比sessionStorage,存储数据更安全,sessionStorage可以在控制台被看到。
vuex劣势: 在F5刷新页面后,vuex会重新更新state,所以,存储的数据会丢失。(即刷新浏览器,vuex数据丢失)
1、手动利用HTML5的本地存储
vuex的state在localStorage或sessionStorage或其它存储方式中取值 在mutations定义的方法里对vuex的状态操作的同时对存储也做对应的操作。这样state就会和存储一起存在并且与vuex同步
2、利用vuex-persistedstate插件
2.1、安装
npm install vuex-persistedstate
2.2、配置
- vuex-persistedstate默认存储于localStorage
// 在store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate';Vue.use(Vuex);export default new Vuex.Store({// ...plugins: [createPersistedState()]// ...
});
- 存储sessionStorage的情况
plugins: [createPersistedState({storage: window.sessionStorage})]
- 存储cookie的情况
import Cookies from 'js-cookie'plugins: [persistedState({storage: {getItem: key => Cookies.get(key),setItem: (key, value) => Cookies.set(key, value, { expires: 7 }),removeItem: key => Cookies.remove(key)}})]
- 指定需要持久化的state
在vuex-persistedstate中,如果你想要指定需要持久化的state(即只持久化Vuex store中的部分状态,而不是全部),你可以通过paths配置选项来实现。paths是一个数组,其中的每个元素都是一个字符串,表示Vuex store中需要被持久化的状态的路径。
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import cart from './cart'
import user from './user'
Vue.use(Vuex)
export default new Vuex.Store({plugins: [createPersistedState({paths:['cart','userSettings','user.name'] // 持久化'cart'模块的全部状态// 持久化全局状态中的'userSettings'// 只持久化'user'模块中的'name' })],state: { // 你的全局状态 token: '', userSettings: { theme: 'dark', notifications: true } }, // 你的模块 modules: {cart,user}
})
- 过滤需要持久化的state
在vuex-persistedstate中,reducer是一个可选的配置项,它的作用是对即将被持久化到存储(如localStorage或sessionStorage)中的Vuex状态进行过滤或转换。通过使用reducer,你可以控制哪些数据被保存,以及如何保存这些数据,从而实现更细粒度的状态持久化控制。
reducer通常是一个函数,它接收当前的state(或特定部分的state,取决于你的配置)作为参数,并返回一个新的对象,该对象包含了应该被持久化的数据。
plugins: [createPersistedState({storage: window.sessionStorage,reducer(state) { // 只返回需要被持久化的部分state return { // 假设我们只想持久化user模块中的name和avatar字段 user: { name: state.user.name, avatar: state.user.avatar } }; }})]
如果path和reducer同时存在则使用reducer, 忽悠paths属性。
- API 配置
createPersistedState([options])使用给定的选项创建插件的新实例。可以提供以下选项来配置您的特定需求的插件:
API | 参数类型 | 说明 | 默认值 |
---|---|---|---|
key | String | 用于存储持久状态的键。 | vuex |
paths | Array | 部分保持状态的任何路径的数组。如果没有给定路径,则完整状态将持久化。如果给定一个空数组,则不会持久化任何状态。如果使用模块,请包括模块名称。 | [] |
reducer | Function | 一个将被调用的函数,对即将被持久化到存储中的Vuex状态进行过滤或转换。 | 都包含这些值 |
subscriber | Function | 被调用以设置突变订阅的函数。 | store => handler => store.subscribe(handler) |
storage | String | 指定存储数据的方式。 | localStorage |
getState | Function | 用来重新补充先前持久状态的功能。 | storage |
setState | Function | 用以保持给定状态的函数。 | storage |
filter | Function | 一个将被调用以过滤setState最终将在存储中筛选过滤的函数。 | () => true |
注意,getState 和 setState 是高级选项,它们允许你完全控制状态的存储和恢复过程。然而,在大多数情况下,简单地使用 paths 或默认行为可能就足够了。