接触过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框架的更多相关文章

  1. 基于vue实现一个简单的MVVM框架(源码分析)

    不知不觉接触前端的时间已经过去半年了,越来越发觉对知识的学习不应该只停留在会用的层面,这在我学jQuery的一段时间后便有这样的体会. 虽然jQuery只是一个JS的代码库,只要会一些JS的基本操作学 ...

  2. 230行实现一个简单的MVVM

    作者:mirone链接:https://zhuanlan.zhihu.com/p/24451202来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. MVVM这两年在前端届 ...

  3. 用Python写一个简单的Web框架

    一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...

  4. 一个简单的web框架实现

    一个简单的web框架实现 #!/usr/bin/env python # -- coding: utf-8 -- __author__ = 'EchoRep' from wsgiref.simple_ ...

  5. 自己实现的一个简单的EF框架(反射实现)

    我实现了一个简单的EF框架,主要用于操纵数据库.实现了对数据库的基本操纵--CRUD 这是项目结构 这是一个 core 下的 DLL 写了一个数据库工厂,用于执行sql语句.调用sql语句工厂 写了一 ...

  6. koa2源码解读及实现一个简单的koa2框架

    阅读目录 一:封装node http server. 创建koa类构造函数. 二:构造request.response.及 context 对象. 三:中间件机制的实现. 四:错误捕获和错误处理. k ...

  7. Core1.1环境下,自己实现的一个简单的CRUD框架(反射实现)

    我实现了一个简单的EF框架,主要用于操纵数据库.实现了对数据库的基本操纵--CRUD 这是项目结构 这是一个 core 下的 DLL 写了一个数据库工厂,用于执行sql语句.调用sql语句工厂 写了一 ...

  8. 动手造轮子:实现一个简单的 AOP 框架

    动手造轮子:实现一个简单的 AOP 框架 Intro 最近实现了一个 AOP 框架 -- FluentAspects,API 基本稳定了,写篇文章分享一下这个 AOP 框架的设计. 整体设计 概览 I ...

  9. 徒手撸一个简单的RPC框架

    来源:https://juejin.im/post/5c4481a4f265da613438aec3 之前在牛逼哄哄的 RPC 框架,底层到底什么原理得知了RPC(远程过程调用)简单来说就是调用远程的 ...

随机推荐

  1. C# DataGridView控件动态添加新行

    C# DataGridView控件动态添加新行 DataGridView控件在实际应用中非常实用,特别需要表格显示数据时.可以静态绑定数据源,这样就自动为DataGridView控件添加相应的行.假如 ...

  2. try catch finally的用法

    http://hi.baidu.com/vincentwen/blog/item/b92d0923f1e4c64793580757.html try catch finally 1.将预见可能引发异常 ...

  3. SurfaceView和SurfaceHolder的基本用法

    仅做记录使用,新手也可以来看看,怎么得到一个surfaceholder. 1.在xml文件中增加一个surfaceView控件. <SurfaceView android:layout_widt ...

  4. python 中如何判断list中是否包含某个元素

    在python中可以通过in和not in关键字来判读一个list中是否包含一个元素 theList = ['a','b','c'] if 'a' in theList: print 'a in th ...

  5. 51nod1228 序列求和(伯努利数)

    题面 传送门 题解 \(O(n^2)\)预处理伯努利数 不知道伯努利数是什么的可以看看这篇文章 不过这个数据范围拉格朗日差值应该也没问题--吧--大概-- //minamoto #include< ...

  6. ubutu16.04修改分辨率

    http://blog.csdn.net/oiken/article/details/71088230 vmware不能自动适应Ubuntu16.04的分辨率,而且Ubuntu16.04的displa ...

  7. iOS APP日志写入文件(日志收集)

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launc ...

  8. Centos7服务器启动jar包项目最佳方式

    jar后台运行:nohup java -jar xx.jar >/dev/null & 此处的“>/dev/null”作用是将终端输出信息输出到空洞中,即不保存输出信息,若要查看输 ...

  9. flex 实例Demo

    Flex 页面布局 很方便 快捷 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  10. Qt 学习之路 2(61):使用 SAX 处理 XML

    Qt 学习之路 2(61):使用 SAX 处理 XML  豆子  2013年8月13日  Qt 学习之路 2  没有评论 前面两章我们介绍了使用流和 DOM 的方式处理 XML 的相关内容,本章将介绍 ...