// 参考:https://blog.csdn.net/howgod/article/details/95135265
// // observe、Watch、Dep
class Vue {
constructor(options) {
this.data = options.data;
observe()
new Watcher();
}
}
// function render () {
// console.log('模拟视图渲染')
// }
// let data = {
// name: '浪里行舟',
// location: { x: 100, y: 100 }
// }
// observe(data)
function observe (obj) {
// 判断类型
if (!obj || typeof obj !== 'object') {
return
}
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
function defineReactive (obj, key, value) {
observe(value) // 递归子属性
let dp = new Dep() //新增
Object.defineProperty(obj, key, {
enumerable: true, //可枚举(可以遍历)
configurable: true, //可配置(比如可以删除)
get: function reactiveGetter () {
console.log('get', value) // 监听
// 将 Watcher 添加到订阅
if (Dep.target) {
dp.addSub(Dep.target) // 新增
}
return value
},
set: function reactiveSetter (newVal) {
observe(newVal) //如果赋值是一个对象,也要递归子属性
if (newVal !== value) {
console.log('set', newVal) // 监听
render()
value = newVal
// 执行 watcher 的 update 方法
dp.notify() //新增
}
}
})
}
}
// data.location = {
// x: 1000,
// y: 1000
// } //set {x: 1000,y: 1000} 模拟视图渲染
// data.name // get 浪里行舟
// Dep的简单实现
class Dep {
constructor () {
/* 用来存放Watcher对象的数组 */
this.subs = [];
}
/* 在subs中添加一个Watcher对象 */
addSub (sub) {
this.subs.push(sub);
}
/* 通知所有Watcher对象更新视图 */
notify () {
this.subs.forEach((sub) => {
sub.update();
})
}
}
// 所以当需要依赖收集的时候调用 addSub,当需要派发更新的时候调用 notify。调用也很简单:
// let dp = new Dep()
// dp.addSub(() => {
// console.log('emit here')
// })
// dp.notify()
// Watcher的简单实现
class Watcher {
constructor(obj, key, cb) {
// 将 Dep.target 指向自己
// 然后触发属性的 getter 添加监听
// 最后将 Dep.target 置空
Dep.target = this
this.cb = cb
this.obj = obj
this.key = key
this.value = obj[key]
Dep.target = null
}
update() {
// 获得新值
this.value = this.obj[this.key]
// 我们定义一个 cb 函数,这个函数用来模拟视图更新,调用它即代表更新视图
this.cb(this.value)
}
}
console