接触过web开发的同学想必都接触过mvvm,业界著名的mvvm框架就有angelajs。今天闲来无事,决定自己实现一个简单的mvvm框架玩一玩。所谓简单,就是仅仅实现一个骨架,仅表其意,不摹其形。
分析
mvvm最大的特点莫过于双向绑定了,数据的变化能及时更新到视图上,同时视图的变化也能及时的更新到数据中。
那么怎么实现这样的双向绑定呢?最直接的方式莫过于事件了。
所以,我们需要实现一个事件的订阅与分发机制,这个功能很常见,网上搜一搜一大堆。
有了这么一套事件的订阅与分发机制,我们就可以通过它将model和view关联起来,这样不管是model还是view有变化,都可以通过事件通知到对方了。
实现
首先要实现一套事件的订阅与分发机制,直接贴代码了:
function event() {
this.handlers = {};
}
event.prototype.on = function (eventname, handler) {
if (!this.handlers) {
this.handlers = {};
}
if (this.handlers[eventname]) {
this.handlers[eventname].push(handler);
} else {
this.handlers[eventname] = [handler];
}
}
event.prototype.fire = function (eventname, eventdata) {
if (this.handlers[eventname]) {
this.handlers[eventname].foreach(function (handler) {
handler(eventdata);
});
}
}
event.prototype.off = function (eventname, handler) {
if (this.handlers[eventname]) {
for (var i = 0; i < this.handlers[eventname].length; i ) {
if (this.handlers[eventname][i] === handler) {
this.handlers[eventname].splice(i, 1);
}
}
}
}
上诉代码实现了某个事件的监听、触发与移除操作。
有了事件,如何将其与view和model结合起来呢? 继承。
function model(data) {
this.data = data;
}
model.prototype = new object(event.prototype);
model.prototype.constructor = model;
model.prototype.set = function (key, value) {
if (this.data[key]) {
this.data[key] = value;
}
this.fire("change", value);
}
model.prototype.get = function (key) {
console.log("key: ", key, " value: ", this.data[key]);
}
function view(model, el) {
this.el = el;
this.model = model;
this.init();
}
view.prototype.init = function () {
var me = this;
this.model.on("change", function (value) {
me.model.get("value");
if (me.el.type === "text") {
me.el.value = value;
} else {
me.el.innertext = value;
}
});
if (this.el.type === "text") {
this.el.addeventlistener("change", function () {
me.model.set("value", this.value);
});
} else {
this.el.addeventlistener("click", function () {
var num = new number(this.innertext || 0);
me.model.set("value", num 1);
});
}
}
view中为了简单处理,直接进行了硬编码,实际应用过程中需要详细处理。
到此,model和view都有了,下面再加一段代码将他们关联起来:
function mvvm() {
this.cache = {};
}
mvvm.prototype.bind = function (data, el) {
var model = new model(data);
var view = new view(model, el);
var key = "key_" (new date()).gettime();
this.cache[key] = {
model: model,
view: view
};
}
测试代码如下:
< !doctype html>
< html>
< head>
< title>mvvm
< script type="text/javascript" src="./event.js">
< script type="text/javascript" src="./model.js">
< script type="text/javascript" src="./view.js">
< style type="text/css">
#inputid {
width: 300px;
height: 30px;
border: 1px solid grey;
margin: 10px;
}
#textid {
width: 300px;
height: 100px;
text-align: center;
border: 1px solid black;
line-height: 100px;
font-size: 20px;
}
< /style>
< /head>
< body>
< div>
< input id="inputid" type="text">
< div id="textid">0