前言
了解前端的演化之路需要知道的两件事
- 架构不是一天实现而是演化出来的 </br>
- 架构的出现是为了解决一个或者一类问题的
</br>
UI包含什么?
在讨论UI框架之前,我们先来了解一个页面可能有的内容,一个UI页面正常包含的内容有
- 绑定事件,即响应用户的操作,常见的事件有点击,长按,滚动
- 向业务获得业务模型
- 展现模型,包括设置呈现内容,调整显示图层等
- 动画
- 显示
正常他们的流程关系�如下图:
正常来说,一个页面的大部分内容都应该是源自业务的,只有少数部分是用户操作引起的页面内容改动与业务无关(如滚动)
</br>
蛮荒时代
在互联网刚出现的时代,web端的html,js是全部写在一起的,同一个html既处理UI又处理业务,这种做法在那个刚起步的时代并没有什么问题,但随着业务的发展,逻辑日趋复杂,这种做法的弊端开始出现,整个业务逻辑变得复杂而难以维护
</br>
MVC时代 (web端主流框架,大部分移动端系统的默认架构)
MVC的到来,就是为了解决逻辑混杂的问题,从而将页面简单的进行功能划分,M负责处理业务,V负责显示,C负责设置V显示内容,响应V事件并调用M处理,MVC最明显的优点是,M的开发完全独立,不再需要考虑页面如何显示,而是直接的面相业务逻辑,V的开发也不需要考虑业务需要显示什么模型,而是直接面对显示结果 </br>
这是一个基础的MVC结构显示
MVC只是对原有页面的简单拆分,所以,还是存在部分问题的
在这个简单的MVC例子,短短的40多行代码中,混合了事件绑定,业务,UI显示操作,动画,一旦页面逻辑稍微复杂,C就会严重膨胀,影响编写与阅读
</br>
MVP时代
为了解决MVC遇到的问题,MVP(Model - View - Presenter)随之出现,MVP中的V是大V,顺序不是MVP,严格来说,MVP应该叫(Model - Presenter - Controller - View),他将页面的业务逻辑从C中拆分出来,放入P中,从而达到独立页面逻辑,最终达到页面显示/页面逻辑都可以单独测试的效果
经过拆分后,P在编写的时候已不需要考虑V具体怎么实现,只需要关心响应什么事件,向V提供什么模型
而VC也只需要关心模型怎么展现,在什么位置响应用户的操作
还是同样的例子,但是把业务拆分到Presenter
但MVP也不是没有缺点的,试想一下这种情况,我们现在需要显示一个列表,我们使用一个为Activity增加了一个Adapter显示这个列表
这时候,产品说我们需要增加一个昵称,这个昵称从另一个服务获得,我们来看看这时候我们需要改动什么,我们需要在顶层View(也就是Activity)上增加一个回调,
接着,我们需要在Adapter上增加一个方法,刷新全部
这时候我们思考下,
- 我们只是要在列表的单项里面增加一个显示内容,但我们却需要在他的父层级改动
2.我们改动的是item,却不得不刷新整个列表
对MVP的Presenter来说,View是单一的,意味着模型只能够传递到最顶层的View,再由顶层View逐级下发,一旦传递的模型增加,传递的层级加深,这部分就内容就非常容易膨胀,那如果底层的View能直接从P那边得到数据呢?MVVM的出现就是为了解决这么一个问题
</br>
MVVM时代
MVVM是一个基于模型绑定的框架。通过在V上增加对VM的监听,使P对VM的修改直接反应到V上,从而避免P的每一次修改都需要从主View逐级传递到子View上。
MVVM的V跟MVP一样也是大V,包含Controller和View,网上有些Demo把业务也集合进VM,但这里为了逻辑清晰,并且方便测试,我们将VM也业务独立出来,也就是把P独立出来,所以,整个框架应该是 M(P)VM(C)V
我们在Activity初始化的时候构造一个ViewModel,Present则由ViewModel来构造(为了使View对业务透明),ViewModel向View提供显示需要的业务模型。而对于底层的View来说,只需要传入一个ViewModel,接下来他的所有显示就与上层View无关了。ViewModel的任何改动,不再需要顶层View介入,就能传递到底层了
经过MVVM改造后,顶层View只有在构造的时候需要传入ViewModel,其他任何时候,底层View都能直接通过ViewModel获得自己要显示的内容,每一个底层View都是最小单元的MVC,具体底层View怎么显示已经与他的上层没有任何关系,ViewModel增加Field也不再需要通过顶层View传递进来,下层View能直接通过ViewModel获得