从零到一手写迷你版 Vue
Vue 响应式设计思路
Vue 响应式主要包含:
数据响应式
监听数据变化,并在视图中更新
Vue2 使用
Object.defineProperty
实现数据劫持Vu3 使用
Proxy
实现数据劫持模板引擎
提供描述视图的模板语法
插值表达式
{{}}
指令
v-bind
,v-on
,v-model
,v-for
,v-if
渲染
将模板转换为 html
解析模板,生成
vdom
,把vdom
渲染为普通 dom
数据响应式原理
数据变化时能自动更新视图,就是数据响应式 Vue2 使用Object.defineProperty
实现数据变化的检测
原理解析
new Vue()
⾸先执⾏初始化,对data
执⾏响应化处理,这个过程发⽣在Observer
中同时对模板执⾏编译,找到其中动态绑定的数据,从
data
中获取并初始化视图,这个过程发⽣在Compile
中同时定义⼀个更新函数和
Watcher实例
,将来对应数据变化时,Watcher 会调⽤更新函数由于
data
的某个key
在⼀个视图中可能出现多次,所以每个key
都需要⼀个管家 Dep 来管理多个Watcher
将来
data
中数据⼀旦发⽣变化,会⾸先找到对应的Dep
,通知所有Watcher
执⾏更新函数
一些关键类说明
CVue
:自定义 Vue 类 Observer
:执⾏数据响应化(分辨数据是对象还是数组) Compile
:编译模板,初始化视图,收集依赖(更新函数、 watcher 创建) Watcher
:执⾏更新函数(更新 dom) Dep
:管理多个 Watcher 实例,批量更新
涉及关键方法说明
observe
: 遍历vm.data
的所有属性,对其所有属性做响应式,会做简易判断,创建Observer实例
进行真正响应式处理
html 页面
CVue
创建基本 CVue 构造函数:
执⾏初始化,对
data
执⾏响应化处理
参考 前端手写面试题详细解答
为 vm.$data 做代理
方便实例上设置和获取数据
例如
原本应该是
代理之后后,可以使用如下方式
给 vm.$data 做代理
编译
初始化视图
根据节点类型进行编译
编译插值表达式
编译元素节点和指令
需要取出指令和指令绑定值使用数据更新视图
以上完成初次渲染,但是数据变化后,不会触发页面更新
依赖收集
视图中会⽤到 data 中某 key,这称为依赖。同⼀个 key 可能出现多次,每次出现都需要收集(⽤⼀个 Watcher 来维护维护他们的关系),此过程称为依赖收集。多个Watcher
需要⼀个Dep
来管理,需要更新时由Dep
统⼀通知。
data 中的 key 和 dep 是一对一关系
视图中 key 出现和 Watcher 关系,key 出现一次就对应一个 Watcher
dep 和 Watcher 是一对多关系
实现思路
在
defineReactive
中为每个key
定义一个Dep实例
编译阶段,初始化视图时读取 key, 会创建
Watcher实例
由于读取过程中会触发 key 的
getter
方法,便可以把Watcher实例
存储到 key 对应的Dep实例
中当 key 更新时,触发 setter 方法,取出对应的
Dep实例
,Dep实例
调用notiy
方法通知所有 Watcher 更新
定义 Watcher 类
监听器,数据变化更新对应节点视图
修改 Compile 类中的更新函数,创建 Watcher 实例
定义 Dep 类
data 的一个属性对应一个 Dep 实例
管理多个
Watcher
实例,通知所有Watcher
实例更新
创建 Watcher 时触发 getter
defineReactive 中作依赖收集,创建 Dep 实例
监听事件指令@xxx
在创建 vue 实例时,需要缓存
methods
到 vue 实例上编译阶段取出 methods 挂载到 Compile 实例上
编译元素时
识别出
v-on
指令时,进行事件的绑定识别出
@
属性时,进行事件绑定事件绑定:通过指令或者属性获取对应的函数,给元素新增事件监听,使用
bind
修改监听函数的 this 指向为组件实例
v-model 双向绑定
实现v-model
绑定input
元素时的双向绑定功能
数组响应式
获取数组原型
数组原型创建对象作为数组拦截器
重写数组的 7 个方法
评论