JavaScript简单实现MVC

最近看了“30行代码实现Javascript中的MVC”这篇文章(http://web.jobbole.com/85108/),受益良多,在此记录下学习的心得。

提到MVC,基本都会从一些框架开始,比如angularJs之类的,要在短时间内透过复杂的框架看到某一种设计模式并非是一件容易的事情。那么如何通过最简单的代码实现一个简单的MVC呢

1. MVC的基础是观察者模式,这是实现Model与View同步的关键。


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');
})();

2. 实现bind方法,绑定model与view


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');
})();

3. 实现controller,将绑定从逻辑代码中解耦


function Controller(callback) {
var models = {};
// 找到所有有bind属性的元素
var views = document.querySelectorAll('[bind]');
// 将views处理为普通数组
views = Array.prototype.slice.call(views, 0);
views.forEach(function (view) {
var modelName = view.getAttribute('bind');
// 取出或新建该元素所绑定的model
models[modelName] = models[modelName] || new Model();
// 完成该元素和指定model的绑定
models[modelName].bind(view);
});
// 调用controller的具体逻辑,将models传入,方便业务处理
callback.call(this, models);
}

演示代码:


// html:
<div id="div1" bind="model1"></div>
<div id="div2" bind="model1"></div>
// 逻辑代码:

new Controller(function (models) {
var model1 = models.model1;
model1.set('this is a div');
});

以下是根据我自己的理解,封装的代码,简单的实现了双向绑定(利用了构造器实现)和模仿了angularjs部分形式:


var app = (function(){
var Model = function(value){
this._v = value;
this._listeners = [];
}
Model.prototype.set = function(value){
var self = this;
self._v = value;
setTimeout(function(){
self._listeners.forEach(function(listener){
listener.call(this,value);
})
})
}
Model.prototype.watch = function(func){
this._listeners.push(func);
}
Model.prototype.bind = function(node){
var self = this;
this.watch(function(value){
if(node.tagName.toUpperCase()=="INPUT"  && !self.inputEvent){
node.addEventListener("keyup",function(){
var _v = this.value;
if(_v != value){
self.set(_v);
}
self.inputEvent = 1;
})
node.value = value;
}else{
node.innerHTML = value;
}
})
}
function controller(controllername,callback){
var models = {},
search = typeof controllername=="string" ? "[controller=" + controllername + "]" : "[controller]",
controller = document.querySelector(search),init = eval("("+controller.getAttribute("init")+")"),$scope = {};
if(!controller) return;
var views = Array.prototype.slice.call(controller.querySelectorAll("[bind]"),0);
views.forEach(function(view){
var modelname = view.getAttribute("bind");
(models[modelname] = models[modelname] || new Model()).bind(view);
$scope = createVisitors($scope,models[modelname],modelname);
});
for(var index in init){
$scope[index] = init[index];
}
callback.call(this,$scope);
}
function createVisitors($scope,model,property){
$scope.__defineSetter__(property,function(value){
model.set(value);
})
return $scope;
}
return {
controller : controller
}
})();

在线demo:http://demo.deanhan.cn/js-mvc/

  • 支付宝二维码 支付宝
  • 微信二维码 微信

本文地址: https://www.deanhan.cn/js-mvc.html

版权声明: 本文为原创文章,版权归 逐梦个人博客 所有,欢迎分享本文,转载请保留出处!

相关文章