🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 一、MVC **MVC**中的**M**就是单纯的从网络获取回来的数据模型,**V**指的我们的视图界面,而**C**就是我们的ViewController; 在其中,ViewController负责View和Model之间调度,View发生交互事件会通过target-action或者delegate方式回调给ViewController,与此同时ViewController还要承担把Model通过KVO、Notification方式传来的数据传输给View用于展示的责任。 随着业务越来越复杂,视图交互越复杂,导致Controller越来越臃肿,负重前行。脏活累活都它干了,到头来还一点不讨好。福报修多了的结果就是,不行了就重构你,重构不了就换掉你; 经典的MVC模式图: ![](https://img.kancloud.cn/2d/16/2d16afab6bd419df62354d7bed8db1d0_1200x653.png) ## 二、MVVM 为了解决MVC的问题,MVVM就闪亮登场了。它把View和Contrller都放在了View层(相当于把Controller一部分逻辑抽离了出来),Model层依然是服务端返回的数据模型; ![](https://img.kancloud.cn/6b/62/6b628a17da0630a736ac45678962b1c0_503x162.png) * **View层**:视图展示。包含UIView以及UIViewController,View层是可以持有ViewModel的; * **ViewModel层**:视图适配器。暴露属性与View元素显示内容或者元素状态一一对应。一般情况下ViewModel暴露的属性建议是readOnly的,至于为什么,我们在实战中会去解释。还有一点,ViewModel层是可以持有Model的; * **Model层**:数据模型与持久化抽象模型。数据模型很好理解,就是从服务器拉回来的JSON数据。而持久化抽象模型暂时放在Model层,是因为MVVM诞生之初就没有对这块进行很细致的描述。按照经验,我们通常把数据库、文件操作封装成Model,并对外提供操作接口。(有些公司把数据存取操作单拎出来一层,称之为**DataAdapter层**,所以在业内会有很多MVVM的变种,但其本质上都是MVVM); **Binder**:MVVM的灵魂。可惜在MVVM这几个英文单词中并没有它的一席之地,它的最主要作用是在View和ViewModel之间做了双向数据绑定。如果MVVM没有Binder,那么它与MVC的差异不是很大; >[danger] 把Model用纯JavaScript对象表示,View负责显示,把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model; ## 三、MVVM和Jquery操作DOM的区别 这个问题,是深刻理解MVVM框架的一个关键; 先看用jQuery实现的修改两个DOM节点的例子: ~~~ <p>Hello, <span id="name">Bart</span>!</p> <p>You are <span id="age">12</span>.</p> ~~~ ### **用jQuery修改name和age节点的内容:** ``` var name = 'Homer'; var age = 51; $('#name').text(name); $('#age').text(age); ``` ### **用MVVM框架来实现同样的功能** 使用MVVM框架来实现同样的功能,我们首先并不关心DOM的结构,而是关心数据如何存储。最简单的数据存储方式是使用JavaScript对象: ~~~ var person = { name: 'Bart', age: 12 }; ~~~ 我们把变量`person`看作Model,把HTML某些DOM节点看作View,并假定它们之间被关联起来了; 借助MVVM框架并不需要并不操作DOM,而是直接修改JavaScript对象: ``` person.name = 'Homer'; person.age = 51; ``` 这让我们的关注点从如何操作DOM变成了如何更新JavaScript对象的状态,而操作JavaScript对象比DOM简单多了; >[danger] 这就是MVVM的设计思想:关注Model的变化,让MVVM框架去自动更新DOM的状态,从而把开发者从操作DOM的繁琐步骤中解脱出来!