先来看下目录结构:
xvue原理学习
├─ MVue.js
├─ Observe.js
├─ index.html
1.Observe.js中的劫持监听
先来看看Mvue.js中对Observe类的使用:
- 通过
new Observer(this.$data)将数据传递给Observer类
//①入口类MVue
class MVue {
constructor(options) {
this.$el = options.el;
this.$data = options.data;
this.$options = options;
//如果有这个$el根节点
if (this.$el) {
//🌵实现一个数据观察者
new Observer(this.$data)
//实现一个指令解析器
new Compile(this.$el, this)
}
}
}
然后再来看下如何完成对数据的劫持和监听:
-
创建
Observe类,constructor中传入想要监听的数据data -
在
observe方法中对data进行判断,然后forEach遍历,对每个item数据子项调用defineReactive方法从而完成对data数据的劫持。-
Object.keys()遍历对象的属性名key,返回一个属性名字组成的数组 -
Object.defineProperty():developer.mozilla.org/zh-CN/docs/… -
问题:如果直接通过vm.$data.person = {a;1}去修改了person对象,那么新修改的person对象不会被监听。 -
解决办法:Object.defineProperty()的set方法,需要调用this.observe(newVal),这样如果vm.$data.person对象被重写,也会被监听。
-
-
defineReactive方法写完之后可以在浏览器控制台中输入vm.$data,然后改变vm.$data中person对象的值,看看是否会出现set和get方法。
//Observe.js
// data中可能的数据结构
// {
// person: {
// name: "悟空",
// age: 18,
// fav: '姑娘'
// },
// }
class Observer{
constructor(data){
//①🌵
this.observe(data)
}
//②🌵
observe(data){
if(data && typeof data === "object")
{
console.log("我是所有的keys",Object.keys(data));//["person", "msg", "htmlStr"]
Object.keys(data).forEach((key)=>{
//劫持监听方法
this.defineReactive(data,key,data[key]);
})
}
}
//③🌵和这个方法写完之后可以在浏览器控制台中输入vm.$data,然后改变vm.$data中对象的值
defineReactive(obj,key,value){
//看看数据是否有多层,有的话,需要递归遍历
this.observe(value);
Object.defineProperty(obj,key,{
enumerable:true,
configurable:false,
get(){
//订阅数据变化时,往Dep中添加观察者(收集每个观察者的依赖)
return value;
},
set:(newVal)=>{
//如果vm.$data.person对象被重写,那么就不会被监听,所以这里通过箭头函数来再次调用observe方法(箭头函数来归正this指向问题),让新值也被监听
this.observe(newVal);
if(newVal !== value)
{
value = newVal
}
}
})
}
}
下篇将继续完成对劫持的数据进行更新,以及Watcher类...