准备工作
认识Flow
- flow是Facebook出品的JavaScript静态类型检查工具
- 类型检查是当前动态类型语言的发展趋势
- 工作方式
- 类型推断:通过上下文推断类型
- 类型注释:事先注释期待的类型;以:开头,可以在函数参数、返回值和变量声明中使用
- .flowconfig为配置文件
目录设计
- compiler:编译相关,将模板ast语法树的解析、优化、代码生成等
- core:vue核心代码,包括内置组件、全局API封装、Vue实例化、观察者、虚拟dom、工具函数等
- platform:vuejs不同平台的入口
- server:服务端使用的vue先关
- sfc:将.vue解析为js对象
- shared:共用的工具方法
源码构建
- 基于rollup构建
- entry:构建入口文件地址
- dest:构建后文件地址
- format:构建的个税
- cjs:commonJS规范
- es:ES Module规范
- umd:UMD规范
- Runtime Only:运行时不做编译,编译提前完成
- Runtime Compiler:运行时编译
- 构建过程:
- step1:package.json -> node scripts/build
- step2:scripts/build
- step2.1:从./config中获取所有配置
- step2.2:根据脚本参数进行过滤
- step2.3:递归进行build
引入vue过程
- 过程:
- step1:src/platforms/web/entry-runtime-with-compiler.js:重新定义$mount方法,将template转为render函数,并调用原有的$mount方法
- step2:src/platforms/web/runtime/index.js:定义$mount方法,扩展config.option等属性
- step3:src/core/index.js:定义vue原型上属性,以及一些静态方法(initGlobalAPI)
- step4:src/core/instance/index.js:定义Vue函数,并混入原型方法
- 优点:Function实现类,按功能分散到多个模块中去,利于代码维护和管理
数据驱动
数据驱动:指视图是由数据驱动生成的,我们对视图的修改不会直接操作dom,而是修改数据
new Vue发生了什么
- 检测是否为new调用
- 调用_init方法
- 将this赋值给vm
- 定义vm.uid
- 定义vm._isVue
- 定义vm.$option
- 是组件:调用initInternalComponent
- 否则:合并传入的options
- 定义定义vm._renderProxy(生产和开发环境)
- 定义vm._self为vm
- 初始化生命周期
- 初始事件中心
- 初始化渲染
- 调用生命周期钩子beforeCreate
- 初始化注入
- 初始化state(prop,method,data等)
- 初始化provider
- 调用生命周期钩子created
- 调用vm.$mount【】
Vue实例挂载的实现
- 调用vm.$mount
- 将el转为dom(并判断el为body或html时,退出函数)
- 创建render函数,挂载到vm.$options.render上
- 转换tempalte
- 可能是自定义
- 可能是id所代表的dom
- 可能是el
- 调用compileToFunctions定义option的render和staticRenderFns
- 转换tempalte
- 调用mount【】
- 调用mount
- 调用mountComponent【】
- 调用mountComponent
- 将el赋值给vm.$el
- 调用生命周期钩子beforeMount
- 定义updateComponent方法
- 创建一个渲染watcher【】,创建时会调用一次updateComponent【】
- 调用updateComponent
- 先调用vm._render生成vnode【】
- 再调用vm._update将上一步生成的vnode转成dom并挂载【】
render
- 调用render(vm.
createElement)
Virtual DOM
- 用原生js对象去描述dom节点,只用来映射到真实dom渲染,不包含dom操作方法
- 从vnode到dom包含create、diff、patch等过程
createElement
- 调用vm.$createElement
- 对参数进行调整
- 调用_createElement【】
- 调用_createElement
- 当data为响应式数据是,返回empty vnode
- 当tag不存在时,返回empty vnode
- 当tag为string时:
- 将children先转换为children的vnode
- 再根据tag、children等生成自身vnode
- 当tag不为string时:调用createComponent
- 再根据生成vnode的情况,做一下过滤
update
vm._update的调用时机有两个一个是首次渲染,一个是数据更新
- 调用vm.__ patch__createPatchFunction(nodeOps,modules)生成的,nodeOps:dom相关的操作,modules:dom属性的
- oldVnode
- 未定义
- ...
- 定义
- 非真实dom且oldVnode与vnode相同
- ...
- 其他
- 调用emptyNodeAt,创建了一个空的和el相同标签元素的vnode,并且将dom挂在elm上了
- 调用createElm,完成dom的生成
- 先尝试创建组件
- 再根据vnode,创建chidren(在创建chidren时,会递归调用createElm)
- 再将其挂载到调用emptyNodeAt生成的dom上
- 对vnode.parent进行相关操作
- 删除父级dom
- 非真实dom且oldVnode与vnode相同
- 未定义
- 调用invokeInsertHook
- oldVnode
组件化
createComponent
当render传参为一个component时,调用createComponent(定义在src/core/vdom/create-component中)方式生成vnode
- 调用Vue.extend【】方法(定义在src/core/global-api/extend.js中),重新定义组件的构造函数
- 定义组件周期钩子:installComponentHooks
- 调用VNode构造函数创建vnode(children定义为undefined且定义了componentOptions)