说到 MV* 就不得不提到响应式网页设计(Responsive Web design),这是2011年提出的概念,且从2012年成为公认的网页设计主流方向,他是一种网页设计的技术做法,该设计可使网站在多种浏览器设备上获得类似的阅读与导航功能,同时减少用户缩放、平移与滚动等操作。这样就要求网站需要设计成SPA。而响应式网页设计的核心理念,不仅仅是交互样式上体现,还有对于跨平台兼容性,良好的分层解耦、响应速度,已经是应用架构的必要条件,现今主流的应用架构,是以BackbonsJS、AngularJS为代表的MVC/MVVM和Flux。
了解MVC
MVVM是由MVC演化来的,接下来了解一下MVC。MVC是一种架构设计模式,它关注数据、界面分离。M表示Model业务数据,V表示用户界面View,C表示Controller控制器管理逻辑和用户输入。(Smalltalk在20世纪80年代设计出来的)。如下图。
特别提一下:
一个View通常对应一个Model,并在Model更改时进行通知,使View本身能进行响应的更新,但是实际开发中还是有面临多个View对应多个Model的情况,这会在开发大型项目时造成混乱。
在前端的MVC框架中,Controller和传统MVC的概念还是不一样,比如Backbone包含Model和View,但是实际上没有真正的Controller,其View和路由的行为与Controller有些类似,但实际上都不是Controller。
MVVM的改进
MVVM出现于2005年,最大的变化是VM(ViewModel)代替了C(Controller),其关键“改进”是数据绑定(DataBinding),也就是说View的状态变化可以直接影响VM,VM对View也是。如下图。
MVC存在的问题
MVC的问题,在项目越来越大,业务逻辑越来越复杂时,这个问提尤其明显,那就是混乱的数据流动方式,如下图。
这种混乱的数据流动方向,以及对于model混乱的监听和触发方式,会造成业务逻辑的难以维护。
解决混乱的数据流动方向的办法
所以就方案就是,如果渲染还是只有一个,统一放在Controller中,每次更新重渲染页面,这样的话,任何数据的更新都只用调用重渲染就行,而且数据和当前页面的状态是唯一确定的。这样就要保证数据的流动清晰,不能出现交叉分路的情况。然而不得不说的是,重渲染会带来严重的性能和用户体验问题。所以对于MVC来说也并不是很好的解决方案。
Flux的解决方案
所以来看看Flux的解决方案,Flux的核心思想是数据和逻辑永远单向流动,如下图。
注意:对于一些复杂的前端应用(比如Firefox中的调试器),Flux已经证明了自己确实能够极大的降低复杂度。但是对于许多原本使用MVC方式架构都绰绰有余的项目来说,Flux看起来像是大材小用。
Flux基本概念
一个Flux应用由3大部分组成————dispatch、store和view,其中的dispatcher负责分发事件;store负责保存数据,同时响应事件并且更新数据;view负责订阅sotre中的数据,并且使用这些数据渲染响应的页面。
尽管MVVM看起来有点像MVC,但是MVVM中没有一个职责明确的controller。实际上,Flux中存在一个controller-view的角色,但是它的职责是将view与store绑定,并没有传统MVC中的controller需要承担的复杂的逻辑。
dispatcher与action
flux中的事件会由若干个中央处理器来分发,这就是dispatcher。
dispatcher是Flux中最核心的概念,实际上dispatcher的实现很简单,我们只需要关心.register(callback)和.disaptch(action)这两个API即可。
register用来注册一个监听器,而dispatch用来分发一个action。
action是一个普通的JavaScript对象,一般包含type、payload等字段,用于描述一个事件以及需要改变的相关数据。比如点击了页面上某个按钮,可能会触发如下action:
{ "type": "CLICK_BUTTON" }
开源社区中有一套关于Flux中action对象该如何定义的规范,称为(FSA)。该规范定义了一个Flux action必须拥有一个type字段,可以有error、payload、meta字段。除此之外不能有别的字段。
2 store
Flux中,store负责保存数据,并定义修改数据的逻辑,同时调用dispatcher的register方法将自己注册为一个监听器。这样每当使用dispatcher的dispatch方法分发一个action时,store注册的监听器就会被调用,同时得到这个action作为参数。
3 controller-view
一般来说,controller-view是整个应用层的最顶端的view,主要用来进行store与React组件的绑定,定义数据更新以及传递的方式。
controller-view会调用store暴露的getter获取存储器中的数据并且设置为自己的state,在render时以props的形式传给自己的子组件(this.props.children)。当store响应某个action并且更新数据后,会触发一个更新事件,这个更新事件就是在controller-view中进行监听的。当store更新时controller-view会重新获取store中的数据,然后调用setState方法触发界面重绘。
view
view的角色可以由React、Vue、Angular等来扮演。view除了显示界面,还有一条特殊规定:如果界面操作需要修改数据,则必须使用dispatcher分发一个action,除此之外没有别的办法在Flux中修改数据。
actionCreator
actionCreator 就是用来创造action的,因为我们在分发action的时候代码是冗余的,所以可以创建actionCreator来减少冗余代码方便逻辑重用。
文献来源:陈屹著《深入React技术栈》