接触过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. POJ - 3984 迷宫问题 BFS求具体路径坐标

    迷宫问题 定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, ...

  2. ICallbackEventHandler使用

    后端:页面需继承ICallbackEventHandler protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack ...

  3. C#时常需要调用C++DLL

    在合作开发时,C#时常需要调用C++DLL,当传递参数时时常遇到问题,尤其是传递和返回字符串是,现总结一下,分享给大家: VC++中主要字符串类型为:LPSTR,LPCSTR, LPCTSTR, st ...

  4. 以太坊系列之五: p2p的nat模块--以太坊源码学习

    p2p的nat模块 该模块相对比较简单,因为nat的真正实现并不在此模块,主要是使用了第三方的nat-upnp和nat-pmp来实现真正的穿透(端口映射). 对外公布的接口 ```go // An i ...

  5. 第五篇 Python内置函数

    内置函数 abs() delattr() hash() memoryview() set() all()    dict()  help() min() setattr() any()  dir()  ...

  6. 「CF622F」The Sum of the k-th Powers「拉格朗日插值」

    题意 求\(\sum_{i=1}^n i^k\),\(n \leq 10^9,k \leq 10^6\) 题解 观察可得答案是一个\(k+1\)次多项式,我们找\(k+2\)个值带进去然后拉格朗日插值 ...

  7. VINS-Mono Installation

    Prerequisites 1.1 ** Ubuntu 16.04, ROS Kinetic ** sudo apt-get install ros-kinetic-cv-bridge ros-kin ...

  8. 扩展jQuery---选中指定索引的文本

    <script type="text/javascript"> //1.扩展jQuery $.fn.selectRange = function (start, end ...

  9. 25.Remove Nth Node From End of List(删除链表的倒数第n个节点)

    Level:   Medium 题目描述: Given a linked list, remove the n-th node from the end of list and return its ...

  10. day--42 前端基础小结

    前端基础总结 一:前端实现的原理: 小实例: 01:第一步:创建一个socket服务端: import socket server=socket.socket() ip_port=("127 ...