Vue 源码草图
2021-08-21 17:23:57 16 举报
Vue 源码草图,持续更新。 参考文档:https://ustbhuangyi.github.io/vue-analysis/v2/prepare/
作者其他创作
大纲/内容
initProvide
响应式对象
当做元素的directives处理,属性放到了prop上1. 增加props,input事件等2. 对trim,number处理,(blur的时候forceUpdate)3. composing 处理 IEM 问题
Dep 建立watcher和数据之间的桥梁
调用Ctor构造函数生成vnode返回
delete
对象:已有属性,直接赋值没有的调用defineReactive
更新占位符节点
updateChildComponent
新旧节点相同
tag为对象
createElm,parentElm从老的节点获取
找不到相同的VNode,会进行插入
数组调用splice改变
自定义事件
文本节点直接对比,赋值
popTarget
创建新节点
只能有一个vnode根节点
set
tag为函数
object调用defineReactive
静态属性target 当前计算的watcher
子组件的update
1. init参数合并,子组件的parent指向父组件(activeInstance),_parentVNode 指向占位VNode。2. lifecycle中更新当前实例activeInstance,并建立父子组件的父子关系
initEvents
const createCompiler = createCompilerCreator(baseCompile(){...})
合并extendOptions(组件定义的Options)以及Vue.Options 作为组件实例$options的原型
Vue
普通节点直接插入
执行子组件的构造函数创建实例,调用_init方法(Vue的init函数)
生成render
updateComponent
根据一定的算法和排序,对子节点进行处理。
get => 触发依赖收集
events
是否对当前状态下的值进行遍历执行defineReactive。1. 子组件不必要对props的值调用defineReactive2. 父组件未传值,就需要对值进行递归调用defineReactive
新旧节点不同
props的type优先级按照数组中的位置。如果type是Object或Array,并且没有props传进来,组件将会沿用初次执行生成的默认值,从而避免对应的刷新。
清除不再使用的数据订阅
通过model中的prop和event,绑定自定义事件1. 将属性放到了el.model中
props validate
Dep.target.addDep
渲染watcher
1. children 拍平为一维数组2. 连续文本节点,合并为一个处理
自定义组件
parse生成ast
Promise
_render
watcher.run
mounted
addSub
flushSchedulerQueue
组件Vnode 执行prepatch
createElm
updateDOMListeners
组件合并配置,Ctor构造函数中会有mergeOptions
patch
pushTarget
update方法,vnode 渲染成真实的dom
检测数据变化
toogleObserve
自增id
set => 触发更新
initRender
合并配置
表单元素
子组件的$attrs,$listener,props更新
定义createElement,$listeners,$attrs
optimize
initProps
生命周期
组件注册
initData
将当前watcher实例赋值给Dep.target
只有老节点有children
dep.notify
insert,子节点插入父节点
queueWatcher
defineReactive
array调用observe
根实例的props需要调用ObservermergeOptions中会将props处理成统一格式
created
lazy = true初始的时候不会求值,当调用该computed的时候,会先去判断dirty是否为true,(dirty在computed中的依赖值发生变化时会置为false),若dirty === true,调用watcher的evaluate,求值,然后收集依赖。
调用Vue.extend(非原型方法)将对象转化为构造器
mounted 生命周期hook在此添加
Observe this.value=datathis.dep=new Depvalue.__ob__ = this
compileToFuncitons
对push,pop,shift,unshift,splice,sort,revert进行了重写,调用之后触发ob.dep.notify,新增数据会调用observe进行监测
createCompiler(){return function createCompiler(){...}}
deep,会循环遍历watch的第一个参数在vm实例上的变量,遍历过程中,收集依赖。sync,同步执行。immediate,立即调用一次。
codegen
initWatch
生命周期合并为数组
传入的参数 _isComponent,_parentVnode(当前组件的占位VNode,比如hello-world组件,在父组件中使用时的占位),parent(activeInstance,当前vm实例)
通过宏任务/微任务将传入的回调放到下一个tick中,指出传参,或者promise的形式
beforeMount
子节点或子组件的渲染
遍历queuewatcher 通过id排序1. 组件更新由父到子2. user watch 在渲染watcher之前3. 父组件在watcher中销毁了子组件,子组件的watcher不再执行。
createCompiler
1. 校验是否是保留标签
初次渲染时,会将真实的dom($el)转化为vnode,会将原本真实dom挂到vnode的elm属性上;vm.$el 为 patch 结果,自定义组件
addHandler
局部注册
编译
createCompilerCreator
全局注册
非文本节点
genHandlers
subs.update
initMethods
老节点的text置空,插入新节点
dep.depend
render函数
create1、普通节点创建完成之后2、组件创建完成之后update1、普通节点更新时2、组件创建更新时
函数柯理化的形式,将浏览器的方法记录下来。modules 定义attrs,klass,events等属性
cleanupDeps
subs,订阅数据变化的watcher
initState
insert
组件
恢复上次的target
patchVnode
添加init,prepatch,insert,destroy钩子函数到data.hook中
将watcher放到队列queue中,避免重复手机
确定父子组件,$root
自定义组件节点
patch完成之后执行,父子组件的hook放到一个数组中,完成渲染后,数组遍历执行
dep = new Dep
组件调用createComponent
$mount
newDepIds记录depIdnewDeps 记录dep并触发dep的addSub,将watcher添加到subs中
生成VNode
不断向上找到最后一个占位符节点
mergeOptions
对不需要更新的静态节点尽心标记
绑定(patchVnode阶段)
init
移除老节点
baseCompile
key 相同 && 组件类型相同(是否异步组件)&& tag 相同&& isComment && 定义 data && sameInputType可以值相同,也可以都是undefined可以使用不同的key,达到重新渲染的效果
调用插入的init hook,组件的patch在这个阶段完成
触发子组件监听数据的setter
same组件调用patchVNode
组件更新
高级异步组件
watcher.addDep
初始化、组件更新时调用组件的$vnode 指向占位VNode,并不是渲染VNode。渲染VNode(vm._vnode)的parent指向占位VNode。
只有新节点有children
组件vnode挂载,生成的真实DOM放到elm属性上;如果子节点,对子节点key进行验重,然后再调用createElm进行挂载。
普通元素
1. 生成Sub构造函数,prototype 指向 Vue.prototype2. 将extend,mixin,use,components等添加到Sub3. 通过cid记录当前Vue实例,并作了缓存优化,避免多次执行init等操作。4. 调用 initProps 等方法,避免在每个组件实例上进行多次initProps。
删除老的节点
按照事件名称将事件放到evenets对象,modifier作为属性存到对应的事件属性上。
1、通过modify生成必要的代码,比如\"$event.preventDefault();$event.stopPropagation();\"2、拼接生成的代码,和原本传入的代码,如果原本传入的是个函数,会增加apply。
异步组件
addEventListeners添加事件只会执行一次,通过更改匿名函数的fns属性,变更绑定的函数。
挂到Vue.options上
优化
updateChildren:子组件遍历
observe(data){ ... new Observer(data) ...}
非Keepalive组件调用createComponentInstanceForVnode,生成 componentInstance(vm实例),componentInstance上有$el属性。调用子组件$mount方法
组件内容的渲染init,最终通过insert挂到父节点
createElment
数组调用splice,对象直接进行删除,触发notify
添加与移除事件都是调用的add与remove方法,最终调用的方法即DOM的addEventListener方法与removeEventListener方法
initInjections
initComputed
beforeCreate
parse
生成vnode
工厂函数
生成/获取render函数
获取组件children
createElement的时候,在vm实例上,及原型上寻找
mounteComponent中的new Watcher
initLifecycle
普通节点,新老节点都有children
nextTick
vdom挂载
mountComponent
最终的渲染,必须要有render函数,template会经过处理转换成render函数
v-model
1. 插入是将子节点的elm(真实DOM)插入到父节点的elm(真实DOM)2. 最外层的是$el对应的父节点,最终插入节点的时候,会将原本的$el删除
0 条评论
下一页