1 实现observer 能够对对象的所有变动进行监听,当发生变动时通知订阅者
var data = {name: 'kindeng'};
observe(data);
data.name = 'dmq'; // 哈哈哈,监听到值变化了 kindeng --> dmq
function observe(data) {
if (!data || typeof data !== 'object') {
return;
}
// 取出所有属性遍历
Object.keys(data).forEach(function(key) {
defineReactive(data, key, data[key]);
});
};
function defineReactive(data, key, val) {
observe(val); // 监听子属性
Object.defineProperty(data, key, {
enumerable: true, // 可枚举
configurable: false, // 不能再define
get: function() {
return val;
},
set: function(newVal) {
console.log('哈哈哈,监听到值变化了 ', val, ' --> ', newVal);
val = newVal;
}
});
}
就是
Object.keys遍历data对象然后传给Object.defineProperty中的get/set钩子
然后实现一个消息订阅器
function Dep() {
this.subs = [];
}
Dep.prototype = {
addSub: function(sub) {
this.subs.push(sub);
},
notify: function() {
this.subs.forEach(function(sub) {
sub.update();
});
}
};
2 compiler主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
具体思路有几点
- 根据el把相对应的元素转换成fragment
- 然后遍历所有节点和子节点,调用相对应指令函数进行渲染,并调用相对应指令进行函数绑定
3 实现watcher 作为连接compile和observer的桥梁 能够订阅并收到属性变动的通知 执行指令绑定的相对应的回调函数
Watcher订阅者作为Observer和Compile之间通信的桥梁,主要做的事情是:
- 在自身实例化时往属性订阅器(dep)里面添加自己
- 自身必须有一个update()方法
- 待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退.
4 mvvm入口函数,整合以上三者
通过observer来监听自己model数据变化,通过compile来编译模版指令,利用watcher来搭起observer和compile之间通信的桥梁。
达到 数据变化>=视图更新 视图更新>=数据变化的效果