使用copilot生成vue响应式原理

何时进行响应式处理

1. 在new Vue的时候,会调用observe函数,observe函数会调用Observer类,Observer类会调用walk函数,walk函数会调用defineReactive函数,defineReactive函数会调用Object.defineProperty函数,从而实现响应式处理。
2. 在属性被读取的时候触发get()方法,Dep.target进行赋值调用dep.depend(Dep.target)进行依赖收集。
3. 在属性被赋值的时候触发set()方法,对newValue进行observe处理,调用dep.notify()通知依赖进行更新。
4. Dep是依赖收集器/发布者,Watcher是观察者/订阅者,是属性与界面的中介,当属性变化时通知中介去更新视图,当


相关代码如下

// 生成vue的响应式原理
function defineReactive(obj, key, val) {
// 递归
observe(val);
// 创建Dep实例
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
// 收集依赖
Dep.target && dep.addDep(Dep.target);
return val;
},
set(newVal) {
if (newVal !== val) {
// 递归
observe(newVal);
val = newVal;
// 发送通知
dep.notify();
}
},
});
}
// 生成vue响应式的observe函数
function observe(obj) {
if (typeof obj !== "object" || obj === null) {
return;
}
new Observer(obj);
}
// 生成vue响应式的Observer类
// Obeserver类对应的中文名称是什么 => Observer对应的中文名称是 观察者
// Obeserver和watcher的区别是什么 => Obeserver是一个类,用来实例化一个Observer对象,Observer对象中有一个value属性,value属性对应的值就是data中的数据;
// watcher是一个类,用来实例化一个watcher对象,watcher对象中有一个getter属性,getter属性对应的值是一个函数,函数中调用了data中的属性,从而触发属性的getter函数
class Observer {
constructor(value) {
this.value = value;
// 判断value的类型
if (Array.isArray(value)) {
// todo
} else {
this.walk(value);
}
}
// 遍历对象的每一个key,对每一个key调用defineReactive
walk(obj) {
Object.keys(obj).forEach((key) => {
defineReactive(obj, key, obj[key]);
});
}
}
// 生成vue响应式的Dep类,用来收集依赖和发送通知
// Dep中文名称是什么 => Dep对应的中文名称是 【依赖收集器】
// 定义一个全局的target属性,用来存储当前的watcher
// Dep.target是一个全局的唯一的watcher,因此在使用的时候需要先保存之前的值,使用完之后再恢复
class Dep {
static target = '';
constructor() {
this.deps = [];
}
addDep(dep) {
this.deps.push(dep);
}
notify() {
// 何时调用notify => 在属性的setter函数中调用
this.deps.forEach((dep) => dep.update());
}
}
// Dep.target在何时赋值 => 在Watcher的get方法中赋值
// 生成vue响应式的Watcher类,用来收集依赖和发送通知
// watcher是什么 => watcher是一个类,用来实例化一个watcher对象
// watcher有什么作用 => watcher的作用是在数据发生变化的时候,执行对应的更新函数
// watcher有哪些属性 => watcher有getter、options两个属性
// watcher有哪些方法 => watcher有get、update两个方法
// watcher对于的中文名称是什么 => 【Watcher】对应的中文名称是 观察者 或者 【订阅者】
// 发布者是谁 => 【发布者是Dep】
class Watcher {
constructor(getter, options) {
// getter是一个函数,函数中调用了data中的属性,从而触发属性的getter函数
this.getter = getter;
// options是一个对象,包含了watcher的一些配置,例如:immediate、deep、lazy等
this.options = options;
this.get();
}
get() {
// 将Dep.target指向当前的Watcher实例
// @ts-ignore
// this是当前的watcher实例
Dep.target = this;
// 执行getter函数,触发属性的getter函数
this.getter();
// 将Dep.target置为null
// @ts-ignore
Dep.target = null;
}
update() {
// if (this.options.sync) {
// this.run();
// } else {
// queueWatcher(this);
// }
}
run() {
// const value = this.get();
// if (value !== this.value || isObject(value) || this.deep) {
// const oldValue = this.value;
// this.value = value;
// if (this.user) {
// try {
// this.cb.call(this.vm, value, oldValue);
// } catch (e) {
// console.error(e, this.vm, `callback for watcher "${this.expression}"`);
// }
// } else {
// this.cb.call(this.vm, value, oldValue);
// }
// }
}
queueWatcher(watcher) {
// const id = watcher.id;
// if (has[id] == null) {
// has[id] = true;
// if (!flushing) {
// queue.push(watcher);
// } else {
// // if already flushing, splice the watcher based on its id
// // if already past its id, it will be run next immediately.
// let i = queue.length - 1;
// while (i > index && queue[i].id > watcher.id) {
// i--;
// }
// queue.splice(i + 1, 0, watcher);
// }
// // queue the flush
// if (!waiting) {
// waiting = true;
// nextTick(flushSchedulerQueue);
// }
// }
}
}
// watcher在何时创建 => 在组件的mounted钩子函数中创建
// 在mounted中如何创建watcher => 通过调用render函数来创建watcher
// render函数在何时调用 => 在组件的render函数中调用 => new Watcher(getter, options)
// getter是一个函数,函数中调用了data中的属性,从而触发属性的getter函数
// getter具体长啥样:() => { this._update(this._render()) }
// render函数示例
// render函数中何时用到了watcher
// 在render函数中调用了h函数,h函数中调用了data中的属性,从而触发属性的getter函数
function render() {
// 生成虚拟dom
const vnode = h("div", { id: "app" }, [
h("p", null, "hello world"),
h("p", null, "hello world"),
h("p", null, "hello world"),
]);
// 将虚拟dom转换为真实dom
const container = document.getElementById("app");
patch(container, vnode);
}
// 生成vue的h函数,作用是生成虚拟dom
function h(tag, props, children) {
return {
tag,
props,
children,
};
}
// 生成vue的patch函数,作用是将虚拟dom转换为真实dom
function patch(container, vnode) {
const el = createElm(vnode);
container.appendChild(el);
}
// 生成vue的createElm函数,作用是将虚拟dom转换为真实dom
function createElm(vnode) {
const { tag, props, children } = vnode;
// 创建元素
const el = document.createElement(tag);
// 处理属性
if (props) {
for (let key in props) {
el.setAttribute(key, props[key]);
}
}
// 处理子节点
if (children) {
if (typeof children === "string") {
el.textContent = children;
} else {
children.forEach((child) => {
patch(el, child);
});
}
}
return el;
}
posted @   脆皮鸡  阅读(217)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示