vue2 源码解析-初始化
· 分享镜#vue
源码目录结构
src
├─compiler 编译相关
├─core Vue核心库
├─platforms 平台相关代码
├─server SSR,服务端渲染
├─sfc .vue 文件编译为 js 对象
└─shared 公共的代码
Vue 的不同构建版本
- 完整版:同时包含编辑器和运行时的版本
- 编辑器:用来将模板字符串编译称为JavaScript渲染函数的代码,体积大、效率低。
- 运行时:用来创建Vue实例、渲染并处理虚拟DOM等的代码,体积小、效率高。基本上就是除去编译器的代码。比完整版体积少30%左右。
- *.vue文件中的模板是在构建时预编译的,最终打包后的结果不需要编译器,只需要运行时版本即可
- UMD
- CommonJs
- ES Module
从入口开始
- src/platform/web/entry-runtime-with-compiler.js
Vue 的构造函数在哪里
- src/platform/web/entry-runtime-with-compiler.js 中引用了 './runtime/index'
- src/platform/web/runtime/index.js
- 设置 Vue.config
- 设置平台相关的指令和组件
- 指令 v-model、v-show
- 组件 transition、transition-group
- 设置平台相关的 patch 方法(打补丁方法,对比新旧的 VNode)
- 设置 $mount 方法,挂载 DOM
// install platform runtime directives & components
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)
// install platform patch function
Vue.prototype.__patch__ = inBrowser ? patch : noop
// public mount method
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
- src/platform/web/runtime/index.js 中引用了 'core/index'
- src/core/index.js
- 定义了 Vue 的静态方法
- initGlobalAPI(Vue)
- extend
- mixin
- use
- src/core/index.js 中引用了 './instance/index'
- src/core/instance/index.js
- 定义了Vue的构造函数
function Vue (options) {
if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue) ){
warn('Vue is a constructor and should be called with the `new` keyword')
}
// 调用 _init() 方法
this._init(options)
}
// 注册 vm 的 _init() 方法,初始化 vm
initMixin(Vue)
// 注册 vm 的 $data/$props/$set/$delete/$watch
stateMixin(Vue)
// 初始化事件相关方法
// $on/$once/$off/$emit
eventsMixin(Vue)
// 初始化生命周期相关的混入方法
// _update/$forceUpdate/$destroy
lifecycleMixin(Vue)
// 混入 render
// $nextTick/_render
renderMixin(Vue)
四个导出 Vue 的模块
- src/platforms/web/entry-runtime-with-compiler.js
- web 平台相关的入口
- 重写了平台相关的 $mount() 方法
- 注册了 Vue.compile() 方法,传递一个 HTML 字符串返回 render 函数
- src/platforms/web/runtime/index.js
- web 平台相关
- 注册和平台相关的全局指令:v-model、v-show
- 注册和平台相关的全局组件: v-transition、v-transition-group
- 全局方法:
- patch:把虚拟 DOM 转换成真实 DOM
- $mount:挂载方法
- src/core/index.js
- 与平台无关
- 设置了 Vue 的静态方法,initGlobalAPI(Vue)
- src/core/instance/index.js
- 与平台无关
- 定义了构造函数,调用了 this._init(options) 方法
- 给 Vue 中混入了常用的实例成员
Vue 的初始化
静态方法初始化
// 注册 Vue 的静态属性/方法
initGlobalAPI(Vue)
// src/core/global-api/index.js
// 初始化 Vue.config 对象 Object.defineProperty(Vue, 'config', configDef)
// exposed util methods.
// NOTE: these are not considered part of the public API - avoid relying on // them unless you are aware of the risk.
// 这些工具方法不视作全局API的一部分,除非你已经意识到某些风险,否则不要去依赖他们
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
// 静态方法 set/delete/nextTick
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
// 2.6 explicit observable API
// 让一个对象可响应
Vue.observable = <T>(obj: T): T => {
observe(obj)
return obj }
// 初始化 Vue.options 对象,并给其扩展
// components/directives/filters/_base
Vue.options = Object.create(null) ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
// this is used to identify the "base" constructor to extend all plain-
object
// components with in Weex's multi-instance scenarios.
Vue.options._base = Vue
// 设置 keep-alive 组件
extend(Vue.options.components, builtInComponents)
// 注册 Vue.use() 用来注册插件
initUse(Vue)
// 注册 Vue.mixin() 实现混入
initMixin(Vue)
// 注册 Vue.extend() 基于传入的 options 返回一个组件的构造函数
initExtend(Vue)
// 注册 Vue.directive()、 Vue.component()、Vue.filter()
initAssetRegisters(Vue)
Vue实例初始化
- 定义 Vue 的构造函数
- 初始化 Vue 的实例成员
// 此处不用 class 的原因是因为方便,后续给 Vue 实例混入实例成员
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
){
warn('Vue is a constructor and should be called with the `new`
keyword') }
this._init(options)
}
// 注册 vm 的 _init() 方法,初始化 vm
initMixin(Vue)
// 注册 vm 的 $data/$props/$set/$delete/$watch
stateMixin(Vue)
// 初始化事件相关方法
// $on/$once/$off/$emit
eventsMixin(Vue)
// 初始化生命周期相关的混入方法
// _update/$forceUpdate/$destroy
lifecycleMixin(Vue)
// 混入 render
// $nextTick/_render
renderMixin(Vue)
- initMixin(Vue)
- 初始化_init()方法
// 给 Vue 实例增加 _init() 方法
// 合并 options / 初始化操作
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
// a uid
vm._uid = uid++
let startTag, endTag
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
startTag = `vue-perf-start:${vm._uid}`
endTag = `vue-perf-end:${vm._uid}`
mark(startTag)
}
// a flag to avoid this being observed
// 如果是 Vue 实例不需要被 observe
vm._isVue = true
// merge options
// 合并 options
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
initProxy(vm)
} else {
vm._renderProxy = vm
}
// expose real self
vm._self = vm
// vm 的生命周期相关变量初始化
// $children/$parent/$root/$refs
initLifecycle(vm)
// vm 的事件监听初始化, 父组件绑定在当前组件上的事件
initEvents(vm)
// vm 的编译render初始化
// $slots/$scopedSlots/_c/$createElement/$attrs/$listeners
initRender(vm)
// beforeCreate 生命钩子的回调
callHook(vm, 'beforeCreate')
// 把 inject 的成员注入到 vm 上
initInjections(vm) // resolve injections before data/props
// 初始化 vm 的 _props/methods/_data/computed/watch
initState(vm)
// 初始化 provide
initProvide(vm) // resolve provide after data/props
// created 生命钩子的回调
callHook(vm, 'created')
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
vm._name = formatComponentName(vm, false)
mark(endTag)
measure(`vue ${vm._name} init`, startTag, endTag)
}
// 调用 $mount() 挂载
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
首次渲染过程
- Vue 初始化,实例成员,静态成员
- new Vue()
- this._init()
- 合并options
- initLifecycle(vm) 初始化生命周期的相关变量
- initEvents(vm) 将父组件的事件绑定到当前实例的事件中
- initRender(vm) 初始化 slots /createElement/ attrs/listeners
- 执行beforeCreate 钩子
- initInjections(vm) 把 inject 的成员注入到 vm 上
- initState(vm) 初始化状态相关的参数,data/props/methods/computed/watch
- initProvide(vm) 初始化provide
- 执行created 钩子
- 如果传递了el 直接执行 $mount()
- vm.$mount()
- 编辑版本
- 重写$mount
- 如果传递了render 直接执行
- 如果没有传递render 获取template,生成render 渲染函数
- 运行时版本
- 调用mountComponent()
- 编辑版本
- mountComponent(this, el)
- 触发beforeMount钩子
- 定义updateComponent
- vm._update(vm._render)
- vm._render()渲染,虚拟dom
- vm.update()更新,将VDom 转换成真实dom
- 创建Watcher实例
- before 中执行beforeUpdate钩子
- 触发mounted
- return vm
- watcher.get()
- 创建完watcher 会调用一次get
- 调用updateComponent()
- 调用vm._render() 创建VNode
- 调用vm.update()
- 调用vm.patch(vm.$el, vnode) 挂载真实dom
- 记录vm.$el
简述
- 初始化Vue 静态方法和实例方法
- 实例化Vue new Vue()
- 执行this._init() 处理vm 的参数
- 执行beforeCreate 钩子
- 创建vm的data、props、methods等
- 执行created钩子
- 执行$mount()
- 编辑版本
- 将template处理生成render 函数
- 运行时版本
- 执行mountComponent()
- 编辑版本
- mountComponent()
- 执行beforeMount 钩子
- 生成updateComponent 函数
- vm._update(vm._render)
- 添加Watcher 实例
- Watcher中before 参数中执行beforeUpdate钩子
- Watcher实例化会执行一次get方法 将执行updateComponent函数
- updateComponent函数中
- vm._render() 生成虚拟dom并返回vnode
- vm._update()中有个vm.patch(vm.$el, vnode)将vnode挂载到真实dom中
- 记录vm.$el 作为下一次对比的旧vnode
评论(6)
登录后参与评论。
- 游游客

- 游游客
厉害
- 游游客
666
- 游游客

- 游游客
666
- 游游客
666

