zoukankan      html  css  js  c++  java
  • 如何实现一个简单的MVVM框架

    接触过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</title>
    	< script type="text/javascript" src="./Event.js"></script>
    	< script type="text/javascript" src="./Model.js"></script>
    	< script type="text/javascript" src="./View.js"></script>
    	< style type="text/css">
    		#inputId {
    			 300px;
    			height: 30px;
    			border: 1px solid grey;
    			margin: 10px;
    		}
    		#textId {
    			 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"></input>
    	< div id="textId">0</div>
    < /div>
    < script type="text/javascript" src="./index.js"></script>
    < script type="text/javascript">
    var mvvm = new MVVM();
    mvvm.bind({
    	value: "text input"
    }, document.getElementById("inputId"));
    mvvm.bind({
    	value: "div text"
    }, document.getElementById("textId"));
    < /script>
    < /body>
    < /html>
    

    测试代码中绑定了一个输入框和一个div,当输入框中值发生改变时,Model中的值也会相应改变(查看控制台打印信息)。当点击div时,div中的文本数字会加一,对应Model中的数据也会改变。

    到此所有的功能就实现完了,虽说简单了点,但是基本意思算是都到了,收工~~。

  • 相关阅读:
    2015第18周四
    2015第18周三程序员能力
    2015第18周二
    2015第18周一
    2015第17周日活在当下
    2015第17周六去除表中某字段重复记录
    2015第17周五
    2015第17周四
    Mac OS X Yosemite安装Hadoop 2.6记录
    GLEW_ERROR_NO_GL_VERSION的解决方法
  • 原文地址:https://www.cnblogs.com/bingooo/p/5323228.html
Copyright © 2011-2022 走看看