var myapp = {}; // 创建这个应用对象
myapp.Model = function() {
var val = 0; // 需要操作的数据
/* 操作数据的方法 */
this.add = function(v) {
if (val < 100) val += v;
};
this.sub = function(v) {
if (val
- val -= v;
};
this.getVal = function() {
return val;
};
};复制代码
View作为视图层,主要负责数据的展示。
myapp.View = function() {
/* 视图元素 */
var $num = $(’#num’),
$incBtn = $(’#increase’),
$decBtn = $(’#decrease’);
/* 渲染数据 */
this.render = function(model) {
$num.text(model.getVal() + ‘rmb’);
};
};复制代码
现在通过Model&View完成了数据从模型层到视图层的逻辑。但对于一个应用程序,这远远是不够的,我们还需要响应用户的操作、同步更新View和Model。于是,在MVC中引入了控制器controller,让它来定义用户界面对用户输入的响应方式,它连接模型和视图,用于控制应用程序的流程,处理用户的行为和数据上的改变。
那时计算机世界天地混沌,浑然一体,然后出现了一个创世者,将现实世界抽象出模型形成model,将人机交互从应用逻辑中分离形成view,然后就有了空气、水、鸡啊、蛋什么的。
——《前端MVC变形记》
上个世纪70年代,美国施乐帕克研究中心,就是那个发明图形用户界面(GUI)的公司,开发了Smalltalk编程语言,并开始用它编写图形界面的应用程序。
到了Smalltalk-80这个版本的时候,一位叫Trygve Reenskaug的工程师为Smalltalk设计了MVC(Model-View-Controller)这种架构模式,极大地降低了GUI应用程序的管理难度,而后被大量用于构建桌面和服务器端应用程序。
如图,实线代表方法调用,虚线代表事件通知。
MVC允许在不改变视图的情况下改变视图对用户输入的响应方式,用户对View的操作交给了Controller处理,在Controller中响应View的事件调用Model的接口对数据进行操作,一旦Model发生变化便通知相关视图进行更新。
Model层用来存储业务的数据,一旦数据发生变化,模型将通知有关的视图。
myapp.Model = function() {
var val = 0;
this.add = function(v) {
if (val < 100) val += v;
};
this.sub = function(v) {
if (val > 0) val -= v;
};
this.getVal = function() {
return val;
};
/* 观察者模式 */
var self = this,
views = [];
this.register = function(view) {
views.push(view);
};
this.notify = function() {
for(var i = 0; i < views.length; i++) {
views[i].render(self);
}
};
};复制代码
Model和View之间使用了观察者模式,View事先在此Model上注册,进而观察Model,以便更新在Model上发生改变的数据。
view和controller之间使用了策略模式,这里View引入了Controller的实例来实现特定的响应策略,比如这个栗子中按钮的 click
事件:
myapp.View = function(controller) {
var $num = $(’#num’),
$incBtn = $(’#increase’),
$decBtn = $(’#decrease’);
this.render = function(model) {
$num.text(model.getVal() + ‘rmb’);
};
/* 绑定事件 */
$incBtn.click(controller.increase);
$decBtn.click(controller.decrease);
};复制代码
如果要实现不同的响应的策略只要用不同的Controller实例替换即可。
控制器是模型和视图之间的纽带,MVC将响应机制封装在controller对象中,当用户和你的应用产生交互时,控制器中的事件触发器就开始工作了。
myapp.Controller = function() {
var model = null,
view = null;
this.init = function() {
/* 初始化Model和View */
model = new myapp.Model();
view = new myapp.View(this);
/* View向Model注册,当Model更新就会去通知View啦 */
model.register(view);
model.notify();
};
/* 让Model更新数值并通知View更新视图 */
this.increase = function() {
model.add(1);
model.notify();
};
this.decrease = function() {
model.sub(1);
model.notify();
};
};复制代码
这里我们实例化View并向对应的Model实例注册,当Model发生变化时就去通知View做更新,这里用到了观察者模式。
当我们执行应用的时候,使用Controller做初始化:
(function() {
var controller = new myapp.Controller();
controller.init();
})();复制代码
可以明显感觉到,MVC模式的业务逻辑主要集中在Controller,而前端的View其实已经具备了独立处理用户事件的能力,当每个事件都流经Controller时,这层会变得十分臃肿。而且MVC中View和Controller一般是一一对应的,捆绑起来表示一个组件,视图与控制器间的过于紧密的连接让Controller的复用性成了问题,如果想多个View共用一个Controller该怎么办呢?这里有一个解决方案:
来把王者荣耀压压惊~其实我想说的是MVP模式…
MVP(Model-View-Presenter)是MVC模式的改良,由IBM的子公司Taligent提出。和MVC的相同之处在于:Controller/Presenter负责业务逻辑,Model管理数据,View负责显示。
虽然在MVC里,View是可以直接访问Model的,但MVP中的View并不能直接使用Model,而是通过为Presenter提供接口,让Presenter去更新Model,再通过观察者模式更新View。
与MVC相比,MVP模式通过解耦View和Model,完全分离视图和模型使职责划分更加清晰;由于View不依赖Model,可以将View抽离出来做成组件,它只需要提供一系列接口提供给上层操作。
myapp.Model = function() {
var val = 0;
this.add = function(v) {
if (val < 100) val += v;
};
this.sub = function(v) {
if (val > 0) val -= v;
};
this.getVal = function() {
return val;
};
};复制代码
Model层依然是主要与业务相关的数据和对应处理数据的方法。
myapp.View = function() {
var $num = $(’#num’),
$incBtn = $(’#increase’),
$decBtn = $(’#decrease’);
this.render = function(model) {
$num.text(model.getVal() + ‘rmb’);
};
this.init = function() {
var presenter = new myapp.Presenter(this);
$incBtn.click(presenter.increase);
$decBtn.click(presenter.decrease);
};
};复制代码
MVP定义了Presenter和View之间的接口,用户对View的操作都转移到了Presenter。比如这里可以让View暴露setter接口以便Presenter调用,待Presenter通知Model更新后,Presenter调用View提供的接口更新视图。
myapp.Presenter = function(view) {
var _model = new myapp.Model();
var _view = view;
_view.render(_model);
this.increase = function() {
_model.add(1);
_view.render(_model);
};
this.decrease = function() {
_model.sub(1);
_view.render(_model);
};
};复制代码
Presenter作为View和Model之间的“中间人”,除了基本的业务逻辑外,还有大量代码需要对从View到Model和从Model到View的数据进行“手动同步”,这样Presenter显得很重,维护起来会比较困难。而且由于没有数据绑定,如果Presenter对视图渲染的需求增多,它不得不过多关注特定的视图,一旦视图需求发生改变,Presenter也需要改动。
运行程序时,以View为入口:
(function() {
var view = new myapp.View();
view.init();
})();复制代码
MVVM(Model-View-ViewModel)最早由微软提出。ViewModel指 “Model of View”——视图的模型。这个概念曾在一段时间内被前端圈热炒,以至于很多初学者拿jQuery和Vue做对比…
指 “Model of View”——视图的模型。这个概念曾在一段时间内被前端圈热炒,以至于很多初学者拿jQuery和Vue做对比…
[外链图片转存中…(img-EWq1nQaK-1642936912311)]