原文地址
转自: http://www.cnblogs.com/front-end-ralph/p/5190442.html
学习了这篇文章,自己敲了几行代码验证,作为记录,尊重原创的作者
我的记录
Demo1
MVC框架,在前端中,我们用html作为View,因此此处只需关注model 和 controller即可。首先定义一下Model
function Model(value){
//如果value没有定义,则设置为0
this._value = typeof value ==='undefined'?"":value;
//_listeners保存了监听该module的回调函数
this._listeners =[];
}
为了简化Model, 我们假设Model中只有一个value的值需要被订阅(观察者模式)。this._listeners中保存了所有的观察者的回调函数。
接下来,需要编写一个修改 value值的函数
//Model的set函数
Model.prototype.set=function(value){
var self = this;
self._value = value;
//set函数会改变model的value值,因此需要通知监听model的函数
//按照Javascript事件处理的一般机制,采用异步调用回调函数
setTimeout(function(){
self._listeners.forEach(function(listener){
listener.call(self,value);
})
})
};
set函数会修改model的value值,在该值被修改之后,异步调用观察者队列中的回调函数,将新的value作为参数传入回调函数中。
那么还有一个问题, 如何为model添加观察者? 那就再编写一个函数用来添加model
//Model的watch函数
Model.prototype.watch=function(listener){
this._listeners.push(listener);
}
第一步完成,接下来如何使用这个model。如下:
(function(){
//首先new一个model
var model = new Model();
var div1 = document.getElementById("div1");
//调用model的watch函数,开始监听model的value变化,并在值变化时,修改div的innerHTML
model.watch(function(value){
div1.innerHTML = value;
});
//当model的set函数被执行,watch中的函数会被异步调用,设置 div的innerHTML
model.set("hello,this is a div");
})()
完整代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Javascript实现MVC(1)</title>
</head>
<script>
function Model(value){
//如果value没有定义,则设置为0
this._value = typeof value ==='undefined'?"":value;
//_listeners保存了监听该module的回调函数
this._listeners =[];
}
//Model的set函数
Model.prototype.set=function(value){
var self = this;
self._value = value;
//set函数会改变model的value值,因此需要通知监听model的函数
//按照Javascript事件处理的一般机制,采用异步调用回调函数
setTimeout(function(){
self._listeners.forEach(function(listener){
listener.call(self,value);
})
})
};
//Model的watch函数
Model.prototype.watch=function(listener){
this._listeners.push(listener);
}
</script>
<body>
<div id="div1"></div>
</body>
<script>
//测试代码
(function(){
var model = new Model();
var div1 = document.getElementById("div1");
//调用model的watch函数,开始监听model的value变化
model.watch(function(value){
div1.innerHTML = value;
});
//当model的set函数被执行,watch中的函数会被异步调用,设置 div的innerHTML
model.set("hello,this is a div");
})()
</script>
</html>
运行结果:
hello,this is a div
Demo2
在Demo1的基础上,感觉watch函数太底层,希望对watch函数做一层封装。继续在model上添加一个bind函数
Model.prototype.bind=function(node){
//将watch的逻辑和通用的回调函数放这里
this.watch(function(value){
node.innerHTML = value;
})
}
那么我们在使用时就更简单了,只需要在model的bind中传入监听的node, 在model的value改变时,node的innerHTML就会被改变
(function(){
var model = new Model();
model.bind(document.getElementById("div1"));
model.bind(document.getElementById("div2"));
model.set("this is a div ");
})()
完整的代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Javascript实现MVC(2)</title>
</head>
<script>
function Model(value){
//如果value没有定义,则设置为0
this._value = typeof value ==='undefined'?"":value;
//_listeners保存了监听该module的回调函数
this._listeners =[];
}
//Model的set函数
Model.prototype.set=function(value){
var self = this;
self._value = value;
//set函数会改变model的value值,因此需要通知监听model的函数
//按照Javascript事件处理的一般机制,采用异步调用回调函数
setTimeout(function(){
self._listeners.forEach(function(listener){
listener.call(self,value);
})
})
};
//Model的watch函数
Model.prototype.watch=function(listener){
this._listeners.push(listener);
}
Model.prototype.bind=function(node){
//将watch的逻辑和通用的回调函数放这里
this.watch(function(value){
node.innerHTML = value;
})
}
</script>
<body>
<div id="div1"></div>
<div id="div2"></div>
</body>
<script>
//测试代码
(function(){
var model = new Model();
model.bind(document.getElementById("div1"));
model.bind(document.getElementById("div2"));
model.set("this is a div ");
})()
</script>
</html>
运行结果:
this is a div
this is a div
Demo3
demo1 和 demo2 都只设计了model,并没有讲到 controller 。
我们现在不想要自己手动在js代码中绑定bind, 想要通过在html上的属性bind就自动绑定到一个model。 为了实现这样的功能,我们定义一个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);
}
这个controller会帮我们将html上的bind属性自动绑定到一个model上,而且controller会自动帮我们调用一次自定义的回调函数callback,因此我们只需要在callback中写入业务逻辑代码即可。
//测试代码1
new Controller(function (models) {
var model = models.myModel;
model.set('this is a div');
});
如上代码所示,我们的业务逻辑代码是想要修改绑定了myModel这个model的div的值。
完整代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Javascript实现MVC(2)</title>
</head>
<script>
function Model(value){
//如果value没有定义,则设置为0
this._value = typeof value ==='undefined'?"":value;
//_listeners保存了监听该module的回调函数
this._listeners =[];
}
//Model的set函数
Model.prototype.set=function(value){
var self = this;
self._value = value;
//set函数会改变model的value值,因此需要通知监听model的函数
//按照Javascript事件处理的一般机制,采用异步调用回调函数
setTimeout(function(){
self._listeners.forEach(function(listener){
listener.call(self,value);
})
})
};
//Model的watch函数
Model.prototype.watch=function(listener){
this._listeners.push(listener);
}
Model.prototype.bind=function(node){
//将watch的逻辑和通用的回调函数放这里
this.watch(function(value){
node.innerHTML = value;
})
}
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);
}
</script>
<body>
<div id="div1" bind="myModel"></div>
<div id="div2" bind="myModel"></div>
<span bind="hour"></span> : <span bind="minute"></span> : <span bind="second"></span>
</body>
<script>
//测试代码1
new Controller(function (models) {
var model = models.myModel;
model.set('this is a div');
});
//测试代码2
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);
});
</script>
</html>
运行结果:
this is a div
this is a div
12 : 53 : 25