正文
上段代码 我们在 setTimeout 里面调用 vm._update(vm._render())来实现更新功能 因为从上一篇初始渲染的原理可知 此方法就是渲染的核心 但是我们不可能每次数据变化都要求用户自己去调用渲染方法更新视图 我们需要一个机制在数据变动的时候自动去更新
1.定义 Watcher
// src/observer/watcher.js
// 全局变量id 每次new Watcher都会自增
let id = 0;
export default class Watcher {
constructor(vm, exprOrFn, cb, options) {
this.vm = vm;
this.exprOrFn = exprOrFn;
this.cb = cb; //回调函数 比如在watcher更新之前可以执行beforeUpdate方法
this.options = options; //额外的选项 true代表渲染watcher
this.id = id++; // watcher的唯一标识
// 如果表达式是一个函数
if (typeof exprOrFn === “function”) {
this.getter = exprOrFn;
}
// 实例化就会默认调用get方法
this.get();
}
get() {
this.getter();
}
}
在 observer 文件夹下新建 watcher.js 代表和观察者相关 这里首先介绍 Vue 里面使用到的观察者模式 我们可以把 Watcher 当做观察者 它需要订阅数据的变动 当数据变动之后 通知它去执行某些方法 其实本质就是一个构造函数 初始化的时候会去执行 get 方法
2.创建渲染 Watcher
// src/lifecycle.js
export function mountComponent(vm, el) {
// _update和._render方法都是挂载在Vue原型的方法 类似_init
// 引入watcher的概念 这里注册一个渲染watcher 执行vm._update(vm._render())方法渲染视图
let updateComponent = () => {
console.log(“刷新页面”);
vm._update(vm._render());
};
new Watcher(vm, updateComponent, null, true);
}
我们在组件挂载方法里面 定义一个渲染 Watcher 主要功能就是执行核心渲染页面的方法
3.定义 Dep
// src/observer/dep.js
// dep和watcher是多对多的关系
// 每个属性都有自己的dep
let id = 0; //dep实例的唯一标识
export default class Dep {
constructor() {
this.id = id++;
this.subs = []; // 这个是存放watcher的容器
}
}
// 默认Dep.target为null
Dep.target = null;
Dep 也是一个构造函数 可以把他理解为观察者模式里面的被观察者 在 subs 里面收集 watcher 当数据变动的时候通知自身 subs 所有的 watcher 更新
Dep.target 是一个全局 Watcher 指向 初始状态是 null
4.对象的依赖收集
// src/observer/index.js
// Object.defineProperty数据劫持核心 兼容性在ie9以及以上
function defineReactive(data, key, value) {
observe(value);
let dep = new Dep(); // 为每个属性实例化一个Dep
Object.defineProperty(data, key, {
get() {
// 页面取值的时候 可以把watcher收集到dep里面–依赖收集
if (Dep.target) {
// 如果有watcher dep就会保存watcher 同时watcher也会保存dep
dep.depend();
}
return value;
},
set(newValue) {
if (newValue === value) return;
// 如果赋值的新值也是一个对象 需要观测
observe(newValue);
value = newValue;
dep.notify(); // 通知渲染watcher去更新–派发更新
},
});
}
上诉代码就是依赖收集和派发更新的核心 其实就是在数据被访问的时候 把我们定义好的渲染 Watcher 放到 dep 的 subs 数组里面 同时把 dep 实例对象也放到渲染 Watcher 里面去 数据更新时就可以通知 dep 的 subs 存储的 watcher 更新
5.完善 watcher
// src/observer/watcher.js
import { pushTarget, popTarget } from “./dep”;
// 全局变量id 每次new Watcher都会自增
let id = 0;
export default class Watcher {
constructor(vm, exprOrFn, cb, options) {
this.vm = vm;
this.exprOrFn = exprOrFn;
this.cb = cb; //回调函数 比如在watcher更新之前可以执行beforeUpdate方法
this.options = options; //额外的选项 true代表渲染watcher
this.id = id++; // watcher的唯一标识
this.deps = []; //存放dep的容器
this.depsId = new Set(); //用来去重dep
// 如果表达式是一个函数
if (typeof exprOrFn === “function”) {
this.getter = exprOrFn;
}
// 实例化就会默认调用get方法
this.get();
}
get() {
pushTarget(this); // 在调用方法之前先把当前watcher实例推到全局Dep.target上
this.getter(); //如果watcher是渲染watcher 那么就相当于执行 vm._update(vm._render()) 这个方法在render函数执行的时候会取值 从而实现依赖收集
popTarget(); // 在调用方法之后把当前watcher实例从全局Dep.target移除
}
// 把dep放到deps里面 同时保证同一个dep只被保存到watcher一次 同样的 同一个watcher也只会保存在dep一次
addDep(dep) {
let id = dep.id;
if (!this.depsId.has(id)) {
this.depsId.add(id);
this.deps.push(dep);
// 直接调用dep的addSub方法 把自己–watcher实例添加到dep的subs容器里面
dep.addSub(this);
}
}
// 这里简单的就执行以下get方法 之后涉及到计算属性就不一样了
update() {
this.get();
}
}
watcher 在调用 getter 方法前后分别把自身赋值给 Dep.target 方便进行依赖收集 update 方法用来更新
6.完善 dep
// src/observer/dep.js
// dep和watcher是多对多的关系
// 每个属性都有自己的dep
let id = 0; //dep实例的唯一标识
export default class Dep {
constructor() {
this.id = id++;
this.subs = []; // 这个是存放watcher的容器
}
depend() {
// 如果当前存在watcher
if (Dep.target) {
Dep.target.addDep(this); // 把自身-dep实例存放在watcher里面
}
}
notify() {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数同学面临毕业设计项目选题时,很多人都会感到无从下手,尤其是对于计算机专业的学生来说,选择一个合适的题目尤为重要。因为毕业设计不仅是我们在大学四年学习的一个总结,更是展示自己能力的重要机会。
因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!
由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频
如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
择一个合适的题目尤为重要。因为毕业设计不仅是我们在大学四年学习的一个总结,更是展示自己能力的重要机会。**
因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
[外链图片转存中…(img-L89qRaqH-1712580552781)]
[外链图片转存中…(img-yFaPxpzr-1712580552782)]
[外链图片转存中…(img-YKdR3nWW-1712580552783)]
既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!
由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频
如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
[外链图片转存中…(img-oG1Hx9uK-1712580552783)]