MVC/MVP/MVVM的区别
1. MVC
传统的MVC主要分为三部分
✦ View 传送指令到 Controller
✦ Controller 完成业务逻辑后,要求 Model 改变状态
✦ Model 将新的数据发送到 View,用户得到反馈
实际项目往往会更灵活,比如Backbone 索性取消了 Controller,只保留一个 Router(路由器) 。
2. MVP
MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。
✦ 各部分之间的通信,都是双向的。
✦ View 与 Model 不发生联系,都通过 Presenter 传递。
✦ View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
3. MVVM
唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然
MVVM架构图实现model
01 初步
// Model 核心代码
function Model(value) {
this._value = typeof value === 'undefined' ? '' : value;
this._listeners = [];
}
Model.prototype.set = function(value) {
var self = this;
self._value = value;
// model中的值改变时,应通知注册过的回调函数
// 按照Javascript事件处理的一般机制,我们异步地调用回调函数
// 如果觉得setTimeout影响性能,也可以采用requestAnimationFrame
setTimeout(function() {
self._listeners.forEach(function(listener) {
listener.call(self, value);
});
});
};
Model.prototype.watch = function(listener) {
// 注册监听的回调函数
this._listeners.push(listener);
};
// html 代码:
<div id="div1"></div>
// 逻辑代码:
(function() {
var model = new Model();
var div1 = document.getElementById('div1');
model.watch(function(value) {
div1.innerHTML = value;
});
model.set('hello, this is a div');
})();
02 抽离中间方法,进一步简化
// 抽离中间方法
Model.prototype.bind = function(node) {
// 将watch的逻辑和通用的回调函数放到这里
this.watch(function(value) {
node.innerHTML = value;
});
};
// html代码:
<div id="div1"></div>
<div id="div2"></div>
// 逻辑代码:
(function() {
var model = new Model();
model.bind(document.getElementById('div1'));
model.bind(document.getElementById('div2'));
model.set('this is a div');
})();
实现controller
function Controller(callback) {
var models = {};
// 找到所有有bind属性的元素
var views = document.querySelectorAll('[data-bind]');
// 将views处理为普通数组
views = Array.prototype.slice.call(views, 0);
views.forEach(function(view) {
var modelName = view.getAttribute('data-bind');
// 取出或新建该元素所绑定的model
models[modelName] = models[modelName] || new Model();
// 完成该元素和指定model的绑定
models[modelName].bind(view);
});
// 调用controller的具体逻辑,将models传入,方便业务处理
callback.call(this, models);
}
// html:
<div id="div1" data-bind="model1"></div>
<div id="div2" data-bind="model1"></div>
// 逻辑代码:
new Controller(function (models) {
var model1 = models.model1;
model1.set('this is a div');
});
MVC完整版
function Model(value) {
this._value = typeof value === 'undefined' ? '' : value;
this._listeners = [];
}
Model.prototype.set = function(value) {
var self = this;
self._value = value;
setTimeout(function() {
self._listeners.forEach(function(listener) {
listener.call(self, value);
});
});
};
Model.prototype.watch = function(listener) {
this._listeners.push(listener);
};
Model.prototype.bind = function(node) {
this.watch(function(value) {
node.innerHTML = value;
});
};
function Controller(callback) {
var models = {};
var views = Array.prototype.slice.call(document.querySelectorAll('[data-bind]'), 0);
views.forEach(function(view) {
var modelName = view.getAttribute('data-bind');
(models[modelName] = models[modelName] || new Model()).bind(view);
});
callback.call(this, models);
}
// html:
<span data-bind="hour"></span> : <span data-bind="minute"></span> : <span bind="second"></span>
// controller:
new Controller(function (models) {
function setTime() {
var date = new Date();
models.hour.set(date.getHours());
models.minute.set(date.getMinutes());
models.second.set(date.getSeconds());
}
setTime();
setInterval(setTime, 1000);
});
网友评论