- 配置入口和出口文件
- 采用 umd 打包方式挂载 global.Vue
- 采用 .babelrc 的 @babel/preset-env 预设插件
- 运行 npm run dev 执行 rollup 打包 -c:指定配置文件 -w:监听文件变化
- 传入用户选项 options
- 调用初始化方法 _init
- 将用户选项挂载在实例上
- 初始化状态 initState
- initData 初始化 data
- 调用 walk 循环对象,对属性进行劫持
- difineReactive 内使用递归,进行深层属性劫持
-
proxy 使用了 defineProperty
-
vm.key => vm._data.key
-
用 __ob__ 标记 Observer 类,并且使其变成不可枚举属性,防止 defineProperty 死循环,可以用作标记已观测数组
-
数组不需要全部进行劫持,只需要对数组内对象进行劫持,调用 observeArray 循环监测对象
-
创造新数组原型指向旧数组原型 newArrayProto.__proto__ = Array.prototype
-
重写数组变异方法,内部调用原来的方法,对新增的对象数据再次进行劫持
- 获取用户模板和用户选项,compileToFunction 将模板转换成 render 函数
-
采用正则,循环匹配了开始标签,结束标签,标签属性,文本内容
-
匹配一段截掉一段,同时利用栈型结构构建 AST 语法树
-
_c 为 createElement _v 为 createTextVNode _s 为 toString
-
利用正则校验,改变正则的 lastIndex,用数组 tokens 保存数据,再拼接数据
-
ast 描述 JS,CSS,HTML 语言本身,vdom 描述 dom 本身,可以增加自定义属性
-
模板引擎实现原理:with + new Function
-
createElementVNode 创建元素虚拟节点,createTextVNode 创建文本虚拟节点
-
path 方法增加真实 DOM,删除旧 DOM
-
patchProps 设置元素属性值,createElm 递归生成元素节点或文本节点
-
调用 vm._update(vm._render()) 更新视图
-
取值时让属性收集器记住当前 Watcher,赋值时通知 Dep 收集的 Watcher 更新
-
Dep 用数组 subs 收集 Watcher,通知时调用 Watcher.update 方法更新
-
watcher 用 Set 收集 Dep,一个 Watcher 对应一个组件
-
更新时调用 queueWatcher,将 watcher 放入队列 queue 中,并根据 id 去重
-
采用定时器异步更新,调用 flushSchedulerQueue 循环执行 watcher
-
将回调放入 callbacks 数组中,通过 Promise.resolve().then 方式去执行
-
也可采用优雅降级的方式,根据不同运行环境调用不同 API 来执行 flushCallbacks
-
Vue.options 初始化,调用 mergeOptions 方法将用户选项与全局选项进行合并
-
实例方法是优先采用子方法,生命周期是采用了策略模式,将多个方法进行合并成数组
- 在不同代码执行时期调用生命周期钩子 callHook 方法,依次执行实例 $options 数组内对应生命周期的方法
-
创建一个计算属性 watcher,lazy:true 标记为计算属性,dirty:true 用于脏值监测,不会直接执行
-
调用 defineComputed 去监控 get 的变化 createComputedGetter
-
页面挂载时创建渲染 watcher,渲染 watcher 获取计算属性时触发计算属性 get
-
createComputedGetter 让计算属性 watcher 去收集上一层 watcher,执行 evaluate
-
evaluate 更新 dirty:false,调用计算属性 watcher 的 get 方法获取值
-
dep 触发 set 时,依次执行 subs 内的 watcher 进行更新,更新时计算属性值不变,只有在获取计算属性时值才进行改变
-
initWatch 方法针对 watch 不同的调用方式,调用 createWatcher 方法调用内部 $watch
-
用 user:true 标记是用户 watcher,将新值和旧值传入 watch 回调函数
- 虚拟节点保存在_vnode 上,将虚拟节点与新节点进行对比
-
不是相同节点:tag 和 key 都不相同 -> 直接进行替换
-
文本节点:tag 不存在 -> 替换文本内容
-
比较节点属性 -> 尽量复用
-
采用双指针 + DFS 深度优先遍历算法进行比较,前后指针重合时停止
-
比较顺序:newStart 与 oldStart,newEnd 与 oldEnd,newEnd 与 oldStart,newStart 与 oldEnd
-
newStartIndex <= newEndIndex 插入剩余的新节点,oldStartIndex <= oldEndIndex 删除剩余的旧节点
-
Vue.component 定义一个 Sub 实例,Sub.prototype.__proto__ = Vue.prototype,并且将用户选项进行合并
-
组件合并时调用 strats.components,通过原型链的方式构建父子组件的关系
-
将生成的组件 definition 记录在 Vue.options.components 上
-
组件挂载时调用 createElementVNode,调用 isReservedTag 根据标签名判断是否是组件标签
-
调用 createComponentVnode 创造组件虚拟节点,构建 data.hook.init 方法
- createElm 方法中调用 createComponent 执行组件的 data.hook.init(vnode) 挂载组件,返回组件实例的 $el