Reactivity响应式简单实现

7/23/2022 vue

最简单的响应式主要只包含三个元素:ObserverDepWatcher

  • Observer:递归地监听对象上的所有属性,在属性值改变的时候,触发相应的watcher
  • Watcher:观察者,当监听的数据值修改时,执行响应的回调函数(Vue里面的更新模板内容)
  • Dep:连接ObserverWatcher的桥梁,每一个Observer对应一个Dep,它内部维护一个数组,保存与该Observer相关的Watcher
function Observer(target, key, value) {
	let dep = new Dep()
	if (Object.prototype.toString.call(value) == '[object Object]') Reflect.ownKeys(value).forEach((key) => new Observer(value, key, value[key]))
	Object.defineProperty(target, key, {
		enumerable: true,
		configurable: false,
		get() {
			Dep.target && dep.addSub(Dep.target) // 订阅
			return value
		},
		set(newVal) {
			dep.notify() // 通知
			value = newVal
		},
	})
}
class Dep {
	constructor() {
		this.subs = [] // watchers数组
	}
	addSub(watcher) {
		!this.subs.includes(watcher) && this.subs.push(watcher) // 避免重复收集
	}
	notify() {
		this.subs.forEach((watcher) => watcher.update())
	}
}
class Watcher {
	// 观察者模式
	constructor(renderCb) {
		this.renderCb = renderCb
	}
	update() {
		Dep.target = this
		this.renderCb()
		Dep.target = null
	}
}

官方原理图如下 image.png

// 测试
let app = document.getElementById('app')
let vm = {
	data: {
		id: 1007,
		goods: { price: 1 },
	},
}
let ob = new Observer(vm, 'data', vm.data)
let watcher = new Watcher(() => (app.innerHTML = vm.data.goods.price))
watcher.update()

let btn = document.getElementById('btn')
btn.onclick = () => vm.data.goods.price++

对照测试示例如下 image.png

    一定要爱着点什么,
    恰似草木对光阴的钟情。
    红莲华
    x
    loading...