1.在执行get()前进行依赖收集 更新后 清除依赖
get() { // 渲染watch Dep.target = watcher; // msg 变化了 需要重新执行watch pushTarget(this) // 让当前传入的函数执行 this.getter(); popTarget() }
2.添加dep.js 文件
let id = 0; class Dep { constructor() { this.id = id++; this.subs = [] } // 订阅 addSub(watcher) { this.subs.push(watcher) } // 发布 notify() { this.subs.forEach(watcher => { watcher.update() }) } depend() { if (Dep.target) { Dep.target.addDep(this) } } } // 保存当前的watcher let stack = []; export function pushTarget(watcher) { Dep.target = watcher; stack.push(watcher) }
// 取出当前的watcher
export function popTarget(watcher) { stack.pop(watcher) Dep.target = stack[stack.length - 1] } // 收集依赖 export default Dep;
添加发布 订阅
addSub(watcher) { this.subs.push(watcher) }
将 所有 的 watcher 添加到数组 中
notify() { this.subs.forEach(watcher => { watcher.update() }) }
将数组中的所有 watcher 拿出 执行 update 方法
3. 在对象进行 Object.defineProperty 执行 get 方法的时候 进行判断
if (Dep.target) { dep.depend(); debugger; // 数组的依赖收集 对象不存在 if (childObj) { console.log(11111000) // 数组也收集依赖 childObj.dep.depend() dependArray(value); } }
先引入 dep
let dep = new Dep()
如果 Dep.target 有值 调用 dep.depend(); 方法 也就是
depend() { if (Dep.target) { Dep.target.addDep(this) } }
渲染watcher 记忆住 Dep
执行 set 方法的时候 发布通知
set(newValue) { if (newValue !== value) return; observe(newValue) value = newValue dep.notify() }
通知调用 dep的 notify 方法
// 发布 notify() { this.subs.forEach(watcher => { watcher.update() }) }
在这个方法中调用了 update 方法 update 又调用了 get 方法
update() { this.get() }
get 方法进行以下操作 又调用了 getter 方法
get() { // 渲染watch Dep.target = watcher; // msg 变化了 需要重新执行watch pushTarget(this) // 让当前传入的函数执行 this.getter(); popTarget() }
getter 方法调用了 Vue.prototype.$update 方法进行 编译更新数据
完整 的 dep.js 和watch.js文件
let id = 0; class Dep { constructor() { this.id = id++; this.subs = [] } // 订阅 addSub(watcher) { this.subs.push(watcher) } // 发布 notify() { this.subs.forEach(watcher => { watcher.update() }) } depend() { if (Dep.target) { Dep.target.addDep(this) } } } // 保存当前的watcher let stack = []; export function pushTarget(watcher) { Dep.target = watcher; stack.push(watcher) } export function popTarget(watcher) { stack.pop(watcher) Dep.target = stack[stack.length - 1] } // 收集依赖 export default Dep;
let id = 0; import { pushTarget, popTarget } from './dep' class Watcher { // watch 有唯一标识 constructor(vm, exprOrfn, cb = () => { }, opts = {}) { // exprOrfn 表达式 cb 回调 this.vm = vm; this.exprOrfn = exprOrfn; if (typeof exprOrfn == 'function') { // getter 就是 Watcher 传入的第2个函数 this.getter = exprOrfn; } this.cb = cb; this.opts = opts; this.id = id++; this.deps = []; this.depsId = new Set(); this.get() } get() { // 渲染watch Dep.target = watcher; // msg 变化了 需要重新执行watch pushTarget(this) // 让当前传入的函数执行 this.getter(); popTarget() } update() { this.get() } addDep(dep) { let id = dep.id; if (!this.depsId.has(id)) { this.depsId.add(id) this.deps.push(dep) dep.addSub(this) } } } export default Watcher;
observe.js 文件
// 定义响应式的数据变化 import { observe } from './index' import { observerArray } from './array' import { arrayMethod } from './array' import Dep from './dep'; export function dependArray(value) { console.log(2222) for (let i = 0; i < value.length; i++) { let current = value[i]; current.__ob__ && current.__ob__.dep.depend() if (Array.isArray(current)) { dependArray(current) } } } export function defineReactive(data, key, value) { let childObj = observe(value); let dep = new Dep() Object.defineProperty(data, key, { get() { // 有值 if (Dep.target) { dep.depend(); debugger; // 数组的依赖收集 对象不存在 if (childObj) { console.log(11111000) // 数组也收集依赖 childObj.dep.depend() dependArray(value); } } return value; }, set(newValue) { if (newValue !== value) return; observe(newValue) value = newValue dep.notify() } }) } class Observe { constructor(data) { // 专门为数组 this.dep = new Dep() // 每个对象都有__obj 属性,返回当前的observe实例 Object.defineProperty(data, '__ob__', { get: () => this }) // 数组 重写push 方法 if (Array.isArray()) { // 只能拦截数组方法 数组的每一个项还需要观测 data._proto = arrayMethod // 观测数组的每一个项 observerArray(data) } else { // 对象 // data 就是我们 定义的 vm._data 的数据 this.walk(data) } } walk(data) { let keys = Object.keys(data); for (let i = 0; i < keys.length; i++) { let key = keys[i]; // key let value = data[keys[i]]; // value defineReactive(data, key, value) } } } export default Observe;
https://gitee.com/guangzhou110/handwritten_vue