(二)手写 Vue 源码 —— 渲染更新

上一篇我们实现了数据到视图的映射,这一篇我们实现数据驱动,当数据改变的时候,我们无需手动操作 DOM ,视图会自动更新。

模拟更新

现在当我们改变数据的时候,data 数据源已经改变了,但是视图并没有改变,需要手动调用 vm._update(vm._render()) 才能更新视图,所以我们需要一个机制在数据变动的时候自动去更新。

一、定义 Watcher

src/observer/watcher.js

js 复制代码
// 全局变量 id 每次 new Watcher 都会自增
let id = 0;

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++;
		if (typeof exprOrFn === 'function') {
			this.getter = exprOrFn;
		}
		this.get();
	}

	get () {
		this.getter();
	}
}

export default Watcher;

在 observer 文件夹下新建 watcher.js 代表和观察者相关 这里首先介绍 Vue 里面使用到的观察者模式,我们可以把 Watcher 当做观察者 它需要订阅数据的变动 当数据变动之后 通知它去执行某些方法 其实本质就是一个构造函数 初始化的时候会去执行 get 方法

二、创建渲染 Watcher

src/lifecycle.js

在组件挂载方法里面定义一个渲染 Watcher 主要功能就是执行核心渲染页面的方法

三、定义 Dep

src/observer/dep.js

Dep 是一个构造函数,可以把他理解为观察者模式里面的被观察者在 subs 里面收集 watcher ;当数据变动的时候通知自身 subs 所有的 watcher 更新;

四、对象的依赖收集

Object.defineProperty数据劫持核心 兼容性在ie9以及以上

src/observer/index.js

上诉代码就是依赖收集和派发更新的核心 其实就是在数据被访问的时候 把我们定义好的渲染 Watcher 放到 dep 的 subs 数组里面 同时把 dep 实例对象也放到渲染 Watcher 里面去 数据更新时就可以通知 dep 的 subs 存储的 watcher 更新

五、 完善watcher

src/observer/watcher.js

watcher 在调用 getter 方法前后分别把自身赋值给 Dep.target 方便进行依赖收集;

六、完善 dep

src/observer/dep.js

定义相关的方法把收集依赖的同时把自身也放到 watcher 的 deps 容器里面去

这时对象的更新已经可以满足了 但是如果是数组 类似{a:1,2,3} a.push(4) 并不会触发自动更新 因为我们数组并没有收集依赖

七、数组的依赖收集

  • childOb 就是Observer实例,表示 属性的值依然是一个对象 包含数组和对象 childOb指代的就是Observer实例对象 里面的dep进行依赖收集
  • 比如{a:1,2,3} 属性a对应的值是一个数组 观测数组的返回值就是对应数组的Observer实例对象
  • e.__ob__代表e已经被响应式观测了 但是没有收集依赖 所以把他们收集到自己的Observer实例的dep里面

如果对象属性的值是一个数组,那么执行 childOb.dep.depend() 收集数组的依赖;如果数组里面还包含数组,需要递归遍历收集,因为只有访问数据触发了 get 才会去收集依赖,一开始只是递归对数据进行响应式处理无法收集依赖,这两点要分清。

八、数组的派发更新

src/observer/array.js

ob 指的是数组对应的 observer 实例,我们在 get 的时候判断如果属性的值还是对象name就在 observer 实例的 dep 收集依赖,所以这里是一一对应的,可以直接更新。

九、总结

从设计模式理解 Vue 响应式原理

数据劫持-->模板解析-->模板渲染-->数据变化视图自动更新

文章参考:

作者: 前端鲨鱼哥

链接:juejin.cn/post/693822...

相关推荐
头发还在的女程序员41 分钟前
Java在线租房系统源码解析:Spring Boot+Vue 3+UniApp房源管理与预约看房方案
java·vue.js·spring boot·租房小程序·租房系统·租房软件
FYKJ_20101 小时前
springboot同人周边订单管理系统48955-计算机毕业设计、课程设计
java·javascript·vue.js·spring boot·django·php·课程设计
梯度下降者10 小时前
Nuxt框架
vue.js·服务端渲染·全栈开发·混合渲染·nuxt框架
yuyuxun118 小时前
协同过滤的校园二手物品智能推荐系统的设计与实现 毕业设计-附源码40082
javascript·vue.js·spring boot·python·数据分析·django·课程设计
FungLeo1 天前
成为全栈·Vue 管理后台篇·编辑器图片上传:从文件选择到文章附件关联
前端·vue.js·编辑器·markdown·文件上传·formdata·附件管理
码云社区1 天前
智慧物业系统选型指南:房屋档案、账单管理与报修协作
前端·javascript·vue.js·智慧物业
ruanno_top2 天前
表单重置后,验证码还显示已通过:Vue 受控组件的 3 种假同步
vue.js
ruanno_top2 天前
给标签页加 roving tabindex,整组反而键盘进不去了
vue.js
仨孩子的爹2 天前
CSS打印样式:字体族与行高在纸上的对照实测
vue.js
OpenTiny社区2 天前
AI Agent场景组件库 TinyRobot v1.0 正式发布:一站式打造您的AI助手
vue.js·github