如何实现一个简单的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 {
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"></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中的数据也会改变。
到此所有的功能就实现完了,虽说简单了点,但是基本意思算是都到了,收工~~。
如何实现一个简单的MVVM框架的更多相关文章
- 基于vue实现一个简单的MVVM框架(源码分析)
不知不觉接触前端的时间已经过去半年了,越来越发觉对知识的学习不应该只停留在会用的层面,这在我学jQuery的一段时间后便有这样的体会. 虽然jQuery只是一个JS的代码库,只要会一些JS的基本操作学 ...
- 230行实现一个简单的MVVM
作者:mirone链接:https://zhuanlan.zhihu.com/p/24451202来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. MVVM这两年在前端届 ...
- 用Python写一个简单的Web框架
一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...
- 一个简单的web框架实现
一个简单的web框架实现 #!/usr/bin/env python # -- coding: utf-8 -- __author__ = 'EchoRep' from wsgiref.simple_ ...
- 自己实现的一个简单的EF框架(反射实现)
我实现了一个简单的EF框架,主要用于操纵数据库.实现了对数据库的基本操纵--CRUD 这是项目结构 这是一个 core 下的 DLL 写了一个数据库工厂,用于执行sql语句.调用sql语句工厂 写了一 ...
- koa2源码解读及实现一个简单的koa2框架
阅读目录 一:封装node http server. 创建koa类构造函数. 二:构造request.response.及 context 对象. 三:中间件机制的实现. 四:错误捕获和错误处理. k ...
- Core1.1环境下,自己实现的一个简单的CRUD框架(反射实现)
我实现了一个简单的EF框架,主要用于操纵数据库.实现了对数据库的基本操纵--CRUD 这是项目结构 这是一个 core 下的 DLL 写了一个数据库工厂,用于执行sql语句.调用sql语句工厂 写了一 ...
- 动手造轮子:实现一个简单的 AOP 框架
动手造轮子:实现一个简单的 AOP 框架 Intro 最近实现了一个 AOP 框架 -- FluentAspects,API 基本稳定了,写篇文章分享一下这个 AOP 框架的设计. 整体设计 概览 I ...
- 徒手撸一个简单的RPC框架
来源:https://juejin.im/post/5c4481a4f265da613438aec3 之前在牛逼哄哄的 RPC 框架,底层到底什么原理得知了RPC(远程过程调用)简单来说就是调用远程的 ...
随机推荐
- C# DataGridView控件动态添加新行
C# DataGridView控件动态添加新行 DataGridView控件在实际应用中非常实用,特别需要表格显示数据时.可以静态绑定数据源,这样就自动为DataGridView控件添加相应的行.假如 ...
- try catch finally的用法
http://hi.baidu.com/vincentwen/blog/item/b92d0923f1e4c64793580757.html try catch finally 1.将预见可能引发异常 ...
- SurfaceView和SurfaceHolder的基本用法
仅做记录使用,新手也可以来看看,怎么得到一个surfaceholder. 1.在xml文件中增加一个surfaceView控件. <SurfaceView android:layout_widt ...
- python 中如何判断list中是否包含某个元素
在python中可以通过in和not in关键字来判读一个list中是否包含一个元素 theList = ['a','b','c'] if 'a' in theList: print 'a in th ...
- 51nod1228 序列求和(伯努利数)
题面 传送门 题解 \(O(n^2)\)预处理伯努利数 不知道伯努利数是什么的可以看看这篇文章 不过这个数据范围拉格朗日差值应该也没问题--吧--大概-- //minamoto #include< ...
- ubutu16.04修改分辨率
http://blog.csdn.net/oiken/article/details/71088230 vmware不能自动适应Ubuntu16.04的分辨率,而且Ubuntu16.04的displa ...
- iOS APP日志写入文件(日志收集)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launc ...
- Centos7服务器启动jar包项目最佳方式
jar后台运行:nohup java -jar xx.jar >/dev/null & 此处的“>/dev/null”作用是将终端输出信息输出到空洞中,即不保存输出信息,若要查看输 ...
- flex 实例Demo
Flex 页面布局 很方便 快捷 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...
- Qt 学习之路 2(61):使用 SAX 处理 XML
Qt 学习之路 2(61):使用 SAX 处理 XML 豆子 2013年8月13日 Qt 学习之路 2 没有评论 前面两章我们介绍了使用流和 DOM 的方式处理 XML 的相关内容,本章将介绍 ...