看到这里是不是有些开心,终于要结束了,看到vuex说明对Vue已经有了一些了解。vuex是Vue官方的一款状态管理工具。采用集中式存储管理应用的所有组件的状态,很是强大。
文章结构:
- 1.Vuex使用场景
- 2.Vuex状态管理模式
- 3.vuex一站式应用(state,getters,muattions,actions)
- 4.Module
- 5.严格模式
- 6.项目结构
1.Vuex使用场景
为什么要使用vuex呢,可以考虑一下,一个整站有很多的网页,很多的数据,也是由很多的组件拼成的。每个组件之间会共享一些状态。比如说用户的登录状态或者购物车。这个购物车在头部会用到,在页面会用到,在页面其他部分也会用到。
如果在头部对购物车部分进行增删改查,页面也要进行同步更新,直接的做法就是通过事件,当购物车组件的列表更新时,不论是侦听属性watch还是计算属性computed触发了更新,就可以通过事件或者eventbus传到另外一个组件。
这样做的缺点就是当组件很长复杂时,调用组件非常多,要挨个依次去通知所有的组件去更新,这样就很复杂耗时。
状态管理的模型就是有一个统一的数据管理中心,就是数据仓库store,store用于维护状态数据,它包含着应用中大部分的状态 (state)。流程图如下:
如上面模式图,每个组件进行更新的时候就会通知数据中心store,数据中心再将共享状态给每一个调用它的组件进行更新。
2.状态管理模式
上面这个模式对于足够复杂的大型应用十分高效,如果你的项目不是大型的单页面应用,是比较简单的应用,建议最好不要使用 Vuex。一个简单的 store 模式就可以了。
如果构建的是一个中大型单页应用,可能要考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
对于Vuex 背后的基本思想官方文档中介绍如下:
3.vuex一站式实例
-
安装
与vue-router相同,可以直接使用npm install vuex --save保存依赖,或者使用淘宝镜像。如下图: -
引入与注册
安装完vuex以后就可以跟vue-router一样引入和注册vuex。方法如下:<main.js文件>
//引入 import Vuex from 'vuex' //注册 Vue.use(Vuex) -
实例化——>全局使用
一个最简单的方式就是实例化store。store是通过vuex的store方法Vuex.store()实例化的,需要提供一个初始 state 对象和一些 mutation。实例化代码如下:
<main.js文件>let store = new Vuex.Store({ //Vuex使用单一状态树state,用一个对象就包含了全部的应用层级状态. //单一状态树让我们能够直接地定位任一特定的状态片段. //在调试的过程中也能轻易地取得整个当前应用状态的快照。 state: { totalPrice: 0 }, //getter 的返回值会根据它的依赖被缓存起来, //且只有当它的依赖值发生了改变才会被重新计算 //有了getter就不必每次从数据集中拿原始数据 getters: { getTotal(state){ return state.totalPrice } }, //动作参数 mutations: { //通过state参数改变price increment (state, price){ state.totalPrice += price }, decrement (state, price){ state.totalPrice -= price } }, //Action 类似于 mutation,不同在于: //Action 提交的是 mutation,而不是直接变更状态。 //Action 可以包含任意异步操作。 actions: { increase (context, price){ context.commit('increment',price) } } })实例化store之后,就要在全局使用store ,
/* eslint-disable no-new */ new Vue({ el: '#app', //router: router router, //全局使用store store, components: { App }, template: '<App/>' })到这里主页面使用结束,下面看看各个子组件怎么变化的。
-
子组件状态管理实现
-
App.vue组件
首先导入两个子组件animal和fruit,
通过 store.state 来获取状态对象,
由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。触发变化也仅仅是在组件的 methods 中提交 mutation。
代码如下:<template> <div id="app"> <img src="./assets/logo.png"> {{ totalPrice }} <!-- //使用组件 --> <Animal></Animal> <Fruit></Fruit> </div> </template> <script> import Animal from './components/animal' import Fruit from './components/fruit' export default { // name: 'App', components: {Animal,Fruit}, //由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可 computed: { totalPrice(){ //通过 store.state 来获取状态对象 //return this.$store.state.totalPrice return this.$store.getters.getTotal } } } </script> <style> #app { text-align: center; } </style> -
animal.vue组件
子组件animal有两个加一和减一的按钮。
使用commit方法调用一个mutation。
触发变化是在组件的 methods 中提交 mutation。
通过 store.commit 方法触发状态变更。
通过提交 mutation 的方式,而不是直接改变 store.state.price,是因为我们想要更明确地追踪到状态的变化。
代码如下:<template lang="html"> <div class="animal"> <h1>{{msg}}</h1> <button v-on:click="addOne">add one</button> <button @click="minusOne">minus one</button> </div> </template> <script> export default { data() { return { msg: 'i like the animal!', //当前价格设置 price: 5 } }, //触发变化也仅仅是在组件的 methods 中提交 mutation。 methods: { //通过提交 mutation 的方式,而不是直接改变 store.state.price,是因为我们想要更明确地追踪到状态的变化 //使用commit方法调用一个mutation addOne(){ //通过 store.commit 方法触发状态变更 this.$store.commit('increment',this.price) /*this.$store.dispatch('increase',this.price)*/ }, minusOne(){ this.$store.commit('decrement',this.price) } } } </script> -
fruit.vue组件
fruit.vue组件同animal.vue组件,代码如下:<template lang="html"> <div class="fruit"> <h1>{{msg}}</h1> <button v-on:click="addOne">add one</button> <button @click="minusOne">minus one</button> <!-- <button v-on:click="getParam">get route Param</button> --> </div> </template> <script> export default { data() { return { msg: 'i like the fruit!', price: 15 } }, methods: { //使用commit方法调用一个mutation addOne(){ console.log(this.$store) this.$store.commit('increment',this.price) }, minusOne(){ this.$store.commit('decrement',this.price) } } } </script>
综上几部分,发现不需要发送其他杂乱的东西,只需要调用对应的mutation就可以实现组件间共享状态的功能。
实现的效果如下:
store的值及其常用方法贴出来帮助理解。 -
4.Module
-
由于使用单一状态树state,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
-
为了解决以上问题,Vuex 允许将 store 分割成模块(module)。每个模块拥有并维护一套自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割,最后每个状态集即模块(module)都会合成到一个总的store对外接口上。
如下示例:
5.严格模式
- ES6的严格模式与vuex的严格模式
-
JavaScript 严格模式(strict mode)即在严格的条件下运行。ES6的严格模式通过在脚本或函数的头部添加 “use strict”; 表达式来声明。
-
vuex开启严格模式,仅需在创建 store 的时候传入 strict: true。如下:
const store = new Vuex.Store({ // 在创建vuex的store实例时开启严格模式 strict: true })
- vuex在严格模式下,不管什么时候发生了状态变更,而且变更不是由 mutation 函数引起的,都将会抛出错误。这样做能保证所有的状态变更都能被调试工具跟踪到。
- 一定不能在发布环境下启用严格模式!!一定要在发布环境下关闭严格模式,以避免性能损失。因为严格模式会深度监测状态树来检测不合规的状态变更。
6.项目结构
此部分来自vuex官方文档。
- Vuex 不限制你的代码结构。但是,它规定了一些需要遵守的规则:
- 应用层级的状态应该集中到单个 store 对象中。
- 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
- 异步逻辑都应该封装到 action 里面。
- 只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
每天进步一点点、充实一点点、快乐一点点、一起加油!