没有合适的资源?快使用搜索试试~ 我知道了~
首页详细分析vue响应式原理
资源详情
资源评论
资源推荐
详细分析详细分析vue响应式原理响应式原理
主要介绍了vue响应式原理的的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友
可以了解下
前言前言
响应式原理作为 Vue 的核心,使用数据劫持实现数据驱动视图。在面试中是经常考查的知识点,也是面试加分项。
本文将会循序渐进的解析响应式原理的工作流程,主要以下面结构进行:
1. 分析主要成员,了解它们有助于理解流程
2. 将流程拆分,理解其中的作用
3. 结合以上的点,理解整体流程
文章稍长,但大部分是代码实现,还请耐心观看。为了方便理解原理,文中的代码会进行简化,如果可以请对照源码学习。
主要成员主要成员
响应式原理中,Observe、Watcher、Dep这三个类是构成完整原理的主要成员。
Observe,响应式原理的入口,根据数据类型处理观测逻辑
Watcher,用于执行更新渲染,组件会拥有一个渲染Watcher,我们常说的收集依赖,就是收集 Watcher
Dep,依赖收集器,属性都会有一个Dep,方便发生变化时能够找到对应的依赖触发更新
下面来看看这些类的实现,包含哪些主要属性和方法。
Observe:我会对数据进行观测:我会对数据进行观测
温馨提示:代码里的序号对应代码块下面序号的讲解
// 源码位置:/src/core/observer/index.js
class Observe {
constructor(data) {
this.dep = new Dep()
// 1
def(data, '__ob__', this)
if (Array.isArray(data)) {
// 2
protoAugment(data, arrayMethods)
// 3
this.observeArray(data)
} else {
// 4
this.walk(data)
}
}
walk(data) {
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key])
})
}
observeArray(data) {
data.forEach(item => {
observe(item)
})
}
}
1. 为观测的属性添加 __ob__ 属性,它的值等于 this,即当前 Observe 的实例
2. 为数组添加重写的数组方法,比如:push、unshift、splice 等方法,重写目的是在调用这些方法时,进行更新渲染
3. 观测数组内的数据,observe 内部会调用 new Observe,形成递归观测
4. 观测对象数据,defineReactive 为数据定义 get 和 set ,即数据劫持
Dep:我会为数据收集依赖:我会为数据收集依赖
// 源码位置:/src/core/observer/dep.js
let id = 0
class Dep{
constructor() {
this.id = ++id // dep 唯一标识
this.subs = [] // 存储 Watcher
}
// 1
depend() {
Dep.target.addDep(this)
}
// 2
addSub(watcher) {
this.subs.push(watcher)
}
// 3
notify() {
this.subs.forEach(watcher => watcher.update())
}
}
// 4
Dep.target = null
export function pushTarget(watcher) {
Dep.target = watcher
}
export function popTarget(){
Dep.target = null
}
export default Dep
1. 据收集依赖的主要方法,Dep.target 是一个 watcher 实例
2. 添加 watcher 到数组中,也就是添加依赖
3. 属性在变化时会调用 notify 方法,通知每一个依赖进行更新
4. Dep.target 用来记录 watcher 实例,是全局唯一的,主要作用是为了在收集依赖的过程中找到相应的 watcher
pushTarget 和 popTarget 这两个方法显而易见是用来设置 Dep.target的。Dep.target 也是一个关键点,这个概念可能初次查
看源码会有些难以理解,在后面的流程中,会详细讲解它的作用,需要注意这部分的内容。
Watcher:我会触发视图更新:我会触发视图更新
// 源码位置:/src/core/observer/watcher.js
let id = 0
export class Watcher {
constructor(vm, exprOrFn, cb, options){
this.id = ++id // watcher 唯一标识
this.vm = vm
this.cb = cb
this.options = options
// 1
this.getter = exprOrFn
this.deps = []
this.depIds = new Set()
this.get()
}
run() {
this.get()
}
get() {
pushTarget(this)
this.getter()
popTarget(this)
}
// 2
addDep(dep) {
// 防止重复添加 dep
if (!this.depIds.has(dep.id)) {
this.depIds.add(dep.id)
this.deps.push(dep)
dep.addSub(this)
}
}
// 3
update() {
queueWatcher(this)
}
}
1. this.getter 存储的是更新视图的函数
2. watcher 存储 dep,同时 dep 也存储 watcher,进行双向记录
3. 触发更新,queueWatcher 是为了进行异步更新,异步更新会调用 run 方法进行更新页面
响应式原理流程响应式原理流程
对于以上这些成员具有的功能,我们都有大概的了解。下面结合它们,来看看这些功能是如何在响应式原理流程中工作的。
数据观测数据观测
数据在初始化时会通过 observe 方法来创建 Observe 类
// 源码位置:/src/core/observer/index.js
export function observe(data) {
// 1
if (!isObject(data)) {
return
}
let ob;
// 2
if (data.hasOwnProperty('__ob__') && data.__ob__ instanceof Observe) {
ob = data.__ob__
} else {
// 3
ob = new Observe(data)
}
return ob
}
在初始化时,observe 拿到的 data 就是我们在 data 函数内返回的对象。
1. observe 函数只对 object 类型数据进行观测
2. 观测过的数据都会被添加上 __ob__ 属性,通过判断该属性是否存在,防止重复观测
3. 创建 Observe 类,开始处理观测逻辑
对象观测对象观测
进入 Observe 内部,由于初始化的数据是一个对象,所以会调用 walk 方法:
walk(data) {
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key])
})
}
defineReactive 方法内部使用 Object.defineProperty 对数据进行劫持,是实现响应式原理最核心的地方。
function defineReactive(obj, key, value) {
// 1
let childOb = observe(value)
// 2
const dep = new Dep()
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
// 3
dep.depend()
if (childOb) {
childOb.dep.depend()
}
}
return value
},
set(newVal) {
if (newVal === value) {
return
}
value = newVal
// 4
childOb = observe(newVal)
// 5
dep.notify()
return value
}
})
}
1. 由于值可能是对象类型,这里需要调用 observe 进行递归观测
2. 这里的 dep 就是上面讲到的每一个属性都会有一个 dep,它是作为一个闭包的存在,负责收集依赖和通知更新
3. 在初始化时,Dep.target 是组件的渲染 watcher,这里 dep.depend 收集的依赖就是这个 watcher,childOb.dep.depend
主要是为数组收集依赖
4. 设置的新值可能是对象类型,需要对新值进行观测
5. 值发生改变,dep.notify 通知 watcher 更新,这是我们改变数据后能够实时更新页面的触发点
剩余12页未读,继续阅读
冷月鱼
- 粉丝: 295
- 资源: 944
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- RTL8188FU-Linux-v5.7.4.2-36687.20200602.tar(20765).gz
- c++校园超市商品信息管理系统课程设计说明书(含源代码) (2).pdf
- 建筑供配电系统相关课件.pptx
- 企业管理规章制度及管理模式.doc
- vb打开摄像头.doc
- 云计算-可信计算中认证协议改进方案.pdf
- [详细完整版]单片机编程4.ppt
- c语言常用算法.pdf
- c++经典程序代码大全.pdf
- 单片机数字时钟资料.doc
- 11项目管理前沿1.0.pptx
- 基于ssm的“魅力”繁峙宣传网站的设计与实现论文.doc
- 智慧交通综合解决方案.pptx
- 建筑防潮设计-PowerPointPresentati.pptx
- SPC统计过程控制程序.pptx
- SPC统计方法基础知识.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论10