1.1、Vuex定义与注意事项
Vuex是为vue.js框架更好的管理状态而设计一个插件。Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
使用Vue开发中需要将应用拆分成多个组件,但是组件与组件之间数据共享成了一个问题,父子组件实现起来相对简单,有很多兄弟组件和跨多级组件,实现起来过程繁琐,在多人协同开发上,不利于统一管理,Vuex可以解决这些问题。
1.1.1、状态管理模式
没有使用Vuex时,让我们看一个简单的 Vue 计数应用:
new Vue({ // state data () { return { count: 0 } }, // view template:'<div>{{ count }}</div>', // actions methods: { increment () { this.count++ } } })
这个状态自管理应用包含以下几个部分:
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化。
以下是一个表示“单向数据流”理念的极简示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此使用Vuex,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
另外,通过定义和隔离状态管理中的各种概念并强制遵守一定的规则,我们的代码将会变得更结构化且易维护。
这就是 Vuex 背后的基本思想,借鉴了 Flux、 Redux、和 The Elm Architecture。与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
1.1.2、使用 Vuex
虽然 Vuex 可以帮助我们管理共享状态,但也附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。引用 Redux 的作者 Dan Abramov 的话说就是:"Flux 架构就像眼镜:您自会知道什么时候需要它。"
1.1.3、注意事项
Vuex会有一定的门槛和复杂性,它的主要使用场景是大型单页面应用,如果你的项目不是很复杂,用一个bus也可以实现数据的共享(在前面讲组件的内容中已经讲到过bus作为总线进行通信的示例),但是它在数据管理,维护,还只是一个简单的组件,而Vuex可以更优雅高效地完成状态管理,所以,是否使用Vuex取决于你的团队和技术储备。
使用bus作为总线通信的示例:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Vue2 Demo</title> </head> <body> <div id="app01"> <my-comp1></my-comp1> <my-comp2></my-comp2> </div> <script src="../../js/vue/vue.js"></script> <script> //事件总线 var bus = new Vue(); Vue.component("my-comp1", { template: "<button @click='incrN'>{{n}}</button>", data() { return {n: 0} }, methods: { incrN: function () { this.n++; //发布事件 bus.$emit("inc",this.n); } } }); Vue.component("my-comp2", { template: "<button @click='incrN'>{{n}}</button>", data() { return {n: 999} }, methods: { incrN: function () { this.n--; } }, //勾子,挂载完成时执行事件 mounted:function () { var _this=this; //监听事件,订阅事件 bus.$on("inc",function (val) { _this.n+=val; }) } }); var vm = new Vue({ el: "#app01", data: {} }); </script> </body> </html>