接触过web开发的同学想必都接触过MVVM,业界著名的MVVM框架就有AngelaJS。今天闲来无事,决定自己实现一个简单的MVVM框架玩一玩。所谓简单,就是仅仅实现一个骨架,仅表其意,不摹其形。

分析

MVVM最大的特点莫过于双向绑定了,数据的变化能及时更新到视图上,同时视图的变化也能及时的更新到数据中。

那么怎么实现这样的双向绑定呢?最直接的方式莫过于事件了。

所以,我们需要实现一个事件的订阅与分发机制,这个功能很常见,网上搜一搜一大堆。

有了这么一套事件的订阅与分发机制,我们就可以通过它将Model和View关联起来,这样不管是Model还是View有变化,都可以通过事件通知到对方了。

实现

首先要实现一套事件的订阅与分发机制,直接贴代码了:

  1. function Event() {
  2. this.handlers = {};
  3. }
  4. Event.prototype.on = function (eventName, handler) {
  5. if (!this.handlers) {
  6. this.handlers = {};
  7. }
  8. if (this.handlers[eventName]) {
  9. this.handlers[eventName].push(handler);
  10. } else {
  11. this.handlers[eventName] = [handler];
  12. }
  13. }
  14. Event.prototype.fire = function (eventName, eventData) {
  15. if (this.handlers[eventName]) {
  16. this.handlers[eventName].forEach(function (handler) {
  17. handler(eventData);
  18. });
  19. }
  20. }
  21. Event.prototype.off = function (eventName, handler) {
  22. if (this.handlers[eventName]) {
  23. for (var i = 0; i < this.handlers[eventName].length; i++) {
  24. if (this.handlers[eventName][i] === handler) {
  25. this.handlers[eventName].splice(i, 1);
  26. }
  27. }
  28. }
  29. }

上诉代码实现了某个事件的监听、触发与移除操作。

有了事件,如何将其与View和Model结合起来呢? 继承。

  1. function Model(data) {
  2. this.data = data;
  3. }
  4. Model.prototype = new Object(Event.prototype);
  5. Model.prototype.constructor = Model;
  6. Model.prototype.set = function (key, value) {
  7. if (this.data[key]) {
  8. this.data[key] = value;
  9. }
  10. this.fire("change", value);
  11. }
  12. Model.prototype.get = function (key) {
  13. console.log("key: ", key, " value: ", this.data[key]);
  14. }
  1. function View(model, el) {
  2. this.el = el;
  3. this.model = model;
  4. this.init();
  5. }
  6. View.prototype.init = function () {
  7. var me = this;
  8. this.model.on("change", function (value) {
  9. me.model.get("value");
  10. if (me.el.type === "text") {
  11. me.el.value = value;
  12. } else {
  13. me.el.innerText = value;
  14. }
  15. });
  16. if (this.el.type === "text") {
  17. this.el.addEventListener("change", function () {
  18. me.model.set("value", this.value);
  19. });
  20. } else {
  21. this.el.addEventListener("click", function () {
  22. var num = new Number(this.innerText || 0);
  23. me.model.set("value", num + 1);
  24. });
  25. }
  26. }

View中为了简单处理,直接进行了硬编码,实际应用过程中需要详细处理。

到此,Model和View都有了,下面再加一段代码将他们关联起来:


  1. function MVVM() {
  2. this.cache = {};
  3. }
  4. MVVM.prototype.bind = function (data, el) {
  5. var model = new Model(data);
  6. var view = new View(model, el);
  7. var key = "key_" + (new Date()).getTime();
  8. this.cache[key] = {
  9. model: model,
  10. view: view
  11. };
  12. }

测试代码如下:

  1. < !DOCTYPE html>
  2. < html>
  3. < head>
  4. < title>MVVM</title>
  5. < script type="text/javascript" src="./Event.js"></script>
  6. < script type="text/javascript" src="./Model.js"></script>
  7. < script type="text/javascript" src="./View.js"></script>
  8. < style type="text/css">
  9. #inputId {
  10. width: 300px;
  11. height: 30px;
  12. border: 1px solid grey;
  13. margin: 10px;
  14. }
  15. #textId {
  16. width: 300px;
  17. height: 100px;
  18. text-align: center;
  19. border: 1px solid black;
  20. line-height: 100px;
  21. font-size: 20px;
  22. }
  23. < /style>
  24. < /head>
  25. < body>
  26. < div>
  27. < input id="inputId" type="text"></input>
  28. < div id="textId">0</div>
  29. < /div>
  30. < script type="text/javascript" src="./index.js"></script>
  31. < script type="text/javascript">
  32. var mvvm = new MVVM();
  33. mvvm.bind({
  34. value: "text input"
  35. }, document.getElementById("inputId"));
  36. mvvm.bind({
  37. value: "div text"
  38. }, document.getElementById("textId"));
  39. < /script>
  40. < /body>
  41. < /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. 组合(Composite)模式 *

    组合(Composite)模式:将对象组合树形结构以表示‘部分-整体’的层次结构. 组合模式使得用户对单个对象和组合对象具有一致性 /* * 抽象构件(Component)角色:这是一个抽象角色,它给 ...

  2. wp8 与wp7.5图标规格说明

    wp8 小图标 159*159 中图标 336*336 大图标 691*336 wp7.5 173*173

  3. Vue 兄弟组件通过事件广播传递数据

    非父子组件传值 通过事件广播实现非父子组件传值1.新建js,引入并实例化Vue import Vue from 'vue' var VueEvent = new Vue(); export defau ...

  4. html5 video微信浏览器视频不能自动播放

    html5 video微信浏览器视频不能自动播放 一.微信浏览器(x5内核): 1.不能自动播放 2.全屏 3.最顶层(z层的最顶层) 二.ios系统解决方案:(无phone手机未测试) <au ...

  5. App Store提交审核报错 ERROR ITMS-90087解决办法

    1.原因说明 app对Wifi进行配网, 使用了GizWifiSDK.framework提交App Store时候报错了 App Store Connect Operation Error ERROR ...

  6. 【AGC013D】Pilling Up dp

    Description 红蓝球各无限多个. 初始时随意地从中选择 n 个, 扔入箱子 初始有一个空的序列 接下来依次做 m 组操作, 每组操作为依次执行下述三个步骤 (1) 从箱子中取出一个求插入序列 ...

  7. Link cut tree 实现不高效的 LCA

    https://www.luogu.org/problemnew/show/P3379 求 a 和 b 的 LCA 考虑先 access(a),此时 a 和 root 在一条链上,再 access(b ...

  8. Mysql的用户基本操作

    创建用户: mysql> create user 'cai'@'localhost' identified by '123456'; Query OK, 0 rows affected (0.0 ...

  9. LNMP之Php的安装配置

    此配置的编译参数是: ./configure --prefix=/opt/php7.2.3 --with-openssl --with-zlib --with-curl --enable-ftp -- ...

  10. 【BlockingQueue】BlockingQueue 阻塞队列实现

    前言: 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便 ...