自己动手实现一个mvvm库
2017-11-02 22:22
375 查看
一、总体大纲
要实现一个我们自己的mvvm库,我们首先需要做的事情不是写代码,而是整理一下思路,捋清楚之后再动手绝对会让你事半功倍。先上流程图,我们对着流程图来捋思路如上图所示,我们可以看到,整体实现分为四步
实现一个
Observer,对数据进行劫持,通知数据的变化
实现一个
Compile,对指令进行解析,初始化视图,并且订阅数据的变更,绑定好更新函数
实现一个
Watcher,将其作为以上两者的一个中介点,在接收数据变更的同时,让
Dep添加当前
Watcher,并及时通知视图进行
update
实现
MVVM,整合以上三者,作为一个入口函数
二、动手时间
思路捋清楚了,接下来要做的事就是开始动手。能动手的我决不动口
1、实现Observer
这里我们需要做的事情就是实现数据劫持,并将数据变更给传递下去。那么这里将会用到的方法就是Object.defineProperty()来做这么一件事。先不管三七二十一,咱先用用
Object.defineProperty()试试手感。
function observe (data) { if (!data || typeof data !== 'object') { return; } Object.keys(data).forEach(key => { observeProperty(data, key, data[key]) }) } function observeProperty (obj, key, val) { observe(val); Object.defineProperty(obj, key, { enumerable: true, // 可枚举 configurable: true, // 可重新定义 get: function () { return val; }, set: function (newVal) { if (val === newVal || (newVal !== newVal && val !== val)) { return; } console.log('数据更新啦 ', val, '=>', n 4000 ewVal); val = newVal; } }); }
调用
var data = { a: 'hello' } observe(data);
效果如下
看完是不是发现
JavaScript提供给我们的
Object.defineProperty()方法功能巨强大巨好用呢。
其实到这,我们已经算是完成了数据劫持,完整的
Observer则需要将数据的变更传递给
Dep实例,然后接下来的事情就丢给
Dep去通知下面完成接下来的事情了,完整代码如下所示
/** * @class 发布类 Observer that are attached to each observed * @param {[type]} value [vm参数] */ function observe(value, asRootData) { if (!value || typeof value !== 'object') { return; } return new Observer(value); } function Observer(value) { this.value = value; this.walk(value); } Observer.prototype = { walk: function (obj) { let self = this; Object.keys(obj).forEach(key => { self.observeProperty(obj, key, obj[key]); }); }, observeProperty: function (obj, key, val) { let dep = new Dep(); let childOb = observe(val); Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function() { if (Dep.target) { dep.depend(); } if (childOb) { childOb.dep.depend(); } return val; }, set: function(newVal) { if (val === newVal || (newVal !== newVal && val !== val)) { return; } val = newVal; // 监听子属性 childOb = observe(newVal); // 通知数据变更 dep.notify(); } }) } } /** * @class 依赖类 Dep */ let uid = 0; function Dep() { // dep id this.id = uid++; // array 存储Watcher this.subs = []; } Dep.target = null; Dep.prototype = { /** * [添加订阅者] * @param {[Watcher]} sub [订阅者] */ addSub: function (sub) { this.subs.push(sub); }, /** * [移除订阅者] * @param {[Watcher]} sub [订阅者] */ removeSub: function (sub) { let index = this.subs.indexOf(sub); if (index !== -1) { this.subs.splice(index ,1); } }, // 通知数据变更 notify: function () { this.subs.forEach(sub => { // 执行sub的update更新函数 sub.update(); }); }, // add Watcher depend: function () { Dep.target.addDep(this); } } // 结合Watcher /** * Watcher.prototype = { * get: function () { * Dep.target = this; * let value = this.getter.call(this.vm, this.vm); * Dep.target = null; * return value; * }, * addDep: function (dep) { * dep.addSub(this); * } * } */
至此,我们已经实现了数据的劫持以及notify数据变化的功能了。
2、实现Compile
按理说我们应该紧接着实现Watcher,毕竟从上面代码看来,
Observer和
Watcher关联好多啊,但是,我们在捋思路的时候也应该知道了,
Watcher和
Compile也是有一腿的哦。所以咱先把
Compile也给实现了,这样才能更好的让他们3P。
我不是老司机,我只是一个纯洁的开电动车的孩子
相关文章推荐
- 自己动手实现一个mvvm库
- 自己动手实现一个MVVM库
- 自己动手系列——实现一个简单的LinkedLis
- 自己动手实现一个简单的string类(一)
- 自己动手实现一个Android Studio插件
- 自己动手实现一个简单的JSON解析器
- 自己动手实现一个《倒水解密》游戏
- 自己动手实现一个队列LGQueue
- 自己动手实现一个简单的string类(二)
- 自己动手实现一个Android Studio插件
- 自己动手实现一个Android Studio插件
- 源码分析之动手实现手写一个自己的SpringMVC框架(三)
- 自己动手实现一个简单的 IOC
- 练习:自己动手实现一个轻量级的信号量(二)
- 扔掉log4j、log4j2,自己动手实现一个多功能日志记录框架,包含文件,数据库日志写入,实测5W+/秒日志文件写入,2W+/秒数据库日志写入,虽然它现在还没有logback那么强大
- 自己动手实现一个队列LGQueue(刚刚)
- 自己动手实现一个简单的 IOC
- Flash/Flex学习笔记(36):自己动手实现一个滑块控件(JimmySilder)
- 自己动手创建一个Web Server(非Socket实现)
- [置顶] 一个简单的JAVA字符集过滤器实现 -vb2005xu 自己动手