💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 介绍 Vuex [Vuex](vuex.vuejs.org/zh) 是一个 Vue 官方的状态管理库,主要是解决组件之间的数据共享问题。 Vue 中组件的数据交流可以通过2种方式: - **props**:从父组件传递数据(状态)到子组件; - **events**, 子组件更改父组件状态,或者使用 event bus。 有时状态会比这些更复杂,在这种情况下,一个好的选择是将状态集中到单个存储中。这就是Vuex 所做的。 # 为什么要使用 Vuex 在 Vue 中 Vuex 不是唯一选择(使用 Redux 也可),但是它是官方的,而且和 Vue 紧密集成。 使用React时,你不得不从众多可用的库中选择一个,因为生态系统非常庞大,而且没有实际的标准。最近 Redux 是最受欢迎的选择,MobX 紧随其后。对于Vue,我想说的是,除了 Vuex,你不需要寻找其他任何东西,尤其是在开始的时候。 Vuex 从 React 生态系统借鉴了很多想法,因为这是 Redux 流行的 Flux 模式。如果你知道 Flux 或 Redux已经,Vuex将非常熟悉。如果你没有,没问题——我将从头到尾解释每一个概念。 Vue 应用程序中的组件可以有自己的状态。例如,输入框将在本地存储输入的数据。 这是完美的,组件可以有本地状态,即使使用 Vuex。当你开始做很多工作来传递一个状态时,你知道你需要像 Vuex 这样的东西。 Vuex为状态提供了一个中央存储库存储,您可以通过请求存储库来更改状态。 依赖于特定状态块的每个组件都将使用存储上的 getter 来访问它,以确保一旦该状态块发生更改,它就会被更新。 使用 Vuex 会给应用程序带来一些复杂性,因为事情需要以某种方式正确地进行设置,但是如果这有助于解决无组织的混乱的 props 传递和事件系统,那么这是一个不错的选择。 # 开始 推荐在 [CodeSandbox](https://codesandbox.io/s/vue) 。它上面有一个 Vue CLI 的示例,可以直接把玩 vue, ![](https://img.kancloud.cn/31/7a/317a9376bd677d173f00ea436f46d07d_1280x800.png) 可以 **Add dependency** 按钮,然后输入 `vuex`,进行安装。 本地安装的话: `npm install vuex` 或者 `yarn add vuex` # 创建 Vuex store 推荐 新建 `src/store/store.js`文件,然后 初始化 Vuex ,然后编写以下代码: ``` import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({}) ``` ![Vuex store](https://img.kancloud.cn/04/86/0486887cc00898fe6e221187732fe44f_1280x800.png) 通过 `Vuex.Store()` api 来创建一个 Vuex store 对象,并通过 `export` 导出; # 一个store 示例 现在我们做个示例,有两个兄弟组件,一个有输入框,一个显示输入的内容。 当输入框的数据发生变化,另一个组件的显示内容也变化。 首先删除默认的 HelloWorld 组件,然后添加一个Form 组件,和一个 Display 组件。 ``` <template> <div> <label for="flavor">Favorite ice cream flavor?</label> <input name="flavor"> </div> </template> ``` ``` <template> <div> <p>You chose ???</p> </div> </template> ``` # 添加组件到 app 我们添加它们到 App.vue 中,替换原来的 HelloWorld 组件: ``` <template> <div id="app"> <Form/> <Display/> </div> </template> <script> import Form from './components/Form' import Display from './components/Display' export default { name: 'App', components: { Form, Display } } </script> ``` # 添加状态到 store中 在 `store.js` 中 添加一个键名为 `state`的对象,该 `state` 对象 含一个值为空字符串的 `flavor` 属性。 ``` import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({ state: { flavor: '' } }) ``` 当用户一有输入,我们便更新该值! # 添加一个 mutation 除了使用 **mutations**,其他操作无法更改状态。我们需要在 Form 组件中设置一个 mutation,用来通知 store 更改状态。 ``` import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({ state: { flavor: '' }, mutations: { change(state, flavor) { state.flavor = flavor } } }) ``` # 添加一个 getter 来引用状态属性 以上操作之后,我们需要添加一种查看状态的方法。我们使用 **getter** 来实现。我们为 `flavor` 属性设置了一个 getter: ``` import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({ state: { flavor: '' }, mutations: { change(state, flavor) { state.flavor = flavor } }, getters: { flavor: state => state.flavor } }) ``` `getters` 是一个对象。这里的 `flavor` 是一个对象的属性,它接收了应用的状态作为参数,并且返回了状态的 `flavor`值。 # 添加 Vuex store 到 app 现在 整个 store 已经准备就绪,我们返回 `main.js` 文件中,我们需要导入该状态,并且使它在我们的app 中可用。 首先导入加: ``` import { store } from './store/store' ``` 并且添加到我们 Vue 应用中: ``` new Vue({ el: '#app', store, components: { App }, template: '<App/>' }) ``` 一旦我们添加这个,因为这是主要的Vue组件,每个Vue组件中的 `store` 变量将指向该 Vuex store。 # 通过 `commit` 在用户的操作中更新状态 当用户输入时,我们通过 `store.commit` api,来更新状态。 但是首先,我们需要一个方法,当用户输入时,用来被调用。我们使用 `@input` 而不是 `@change` 事件,因为后者只在焦点从输入框移开时触发,而 `@input` 则在每次按键时调用。 ``` <template> <div> <label for="flavor">Favorite ice cream flavor?</label> <input @input="changed" name="flavor"> </div> </template> <script> export default { methods: { changed: function(event) { alert(event.target.value) } } } </script> ``` 现在我们有了 `flavor` 的值,然后我们使用 Vuex API: ``` <script> export default { methods: { changed: function(event) { this.$store.commit('change', event.target.value) } } } </script> ``` 看到我们如何使用 `this.$store` 引用 store 了吗? 这是因为在主Vue组件初始化中包含了 store 对象。 `commit()` 方法接受一个突变(mutation)名(我们在Vuex store 中使用了 `change`)和一个有效负载(payload),它将作为回调函数的第二个参数传递给突变。 # 使用 getter 打印状态值 现在我们需要在显示模板中使用 `this.$store.getters.flavor` 引用这个值的getter。 `this` 可以被删除,因为我们在模板中,而 `this` 是隐式的。 ``` <template> <div> <p>You chose {{ $store.getters.flavor }}</p> </div> </template> ``` # 页面刷新state数据初始化 解决思路:将state中的数据放在浏览器的 sessionStorage 和 localStorage 中 在实际的Vue项目中,当我们的应用遇到多个组件之间的共享问题时,通常会用到Vuex(状态管理工具,可以解决不同组件之间的数据共享和数据持久化)解决组件之间同一状态的共享问题 解决方法: ① 存储在 `sessionStorage `中 单页面应用,操作都是在一个页面跳转路由,因此`sessionStorage`较为合适,原因如下: 1. sessionStorage 可以保证打开页面时 sessionStorage 的数据为空; 2. 每次打开页面 localStorage 存储着上一次打开页面的数据,因此需要清空之前的数据。 vuex 中 state 数据的修改必须通过 mutation 方法进行修改,因此 mutation 修改 state的同时需要修改 sessionstorage,问题倒是可以解决但是感觉很麻烦,state中有很多数据,很多 mutation 修改state就要很多次 sessionstorage 进行修改,既然如此直接用sessionstorage解决不就行了,为何还要用vuex多此一举呢? vuex 的数据在每次页面刷新时丢失,是否可以在页面刷新前再将数据存储到sessionstorage中呢,是可以的,[beforeunload](https://www.w3cschool.cn/fetch_api/fetch_api-9vhu2oq0.html) 事件可以在页面刷新前触发,但是在每个页面中监听beforeunload事件感觉也不太合适,那么最好的监听该事件的地方就在 `app.vue` 中。 1. 在 `app.vue` 的 `created `方法中读取`sessionstorage`中的数据存储在store中,此时用`vuex.store`的[replaceState](https://vuex.vuejs.org/zh/api/#replacestate)方法,替换 `store `的根状态 2. 在`beforeunload`方法中将 `store.state` 存储到 `sessionstorage `中。 示例: ``` export default { name: 'App', created () { // 在页面加载时读取sessionStorage里的状态信息 sessionStorage.getItem("store") && this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(sessionStorage.getItem("store")))) // 在页面刷新时将vuex里的信息保存到sessionStorage里 window.addEventListener("beforeunload",()=>{ sessionStorage.setItem("store",JSON.stringify(this.$store.state)) }) } } ``` ② 使用 [vuex-persistedstate](https://npm.io/package/vuex-persistedstate) 、[vuex-along](https://github.com/boenfu/vuex-along)、[vuex-persist](https://npm.io/package/vuex-persist) 插件 安装插件: ~~~ npm install vuex-persistedstate --save ~~~ 配置: 在 store 的 `index.js` 中,手动插入并配置 ``` import createPersistedState from "vuex-persistedstate" const store =new Vuex.Store({ plugins: [createPersistedState()] }) ``` 该插件默认持久化所有 state,当然也可以指定需要持久化的 state: ``` import createPersistedState from "vuex-persistedstate" const store =new Vuex.store({ plugins: [createPersistedState({ storage:window.sessionStorage, reducer(data) { return { // 设置只存储state中的myData myData:data.myData } } })] }) ``` # 总结 这是介绍 Vuex! 完整的工作源代码可以在 <https://codesandbox.io/s/zq7k7nkzkm> 找到。 在这个谜题中仍然有许多概念缺失: - actions - modules - helpers - plugins 但是你已经有了一些基础去阅读官方文档中的相关内容。 编码快乐!