一、源码目录:
目录 | 说明 |
---|
compiler | 编译相关 |
core | vue核心代码 |
platforms | 平台,web和weex |
server | 服务端渲染 |
sfc | .vue文件解析 |
shared | 共享代码 |
二、Vue执行流程:
1、编译入口文件(platforms/web/entry-runtime-with-compiler.js)
- 引入 platforms/web/runtime/index.js 得到Vue类
- 缓存Vue的原型链上添加$mount方法,并重写该方法
2、platforms/web/runtime/index.js
- 引入 core/index.js 得到Vue类
- 往Vue类的config属性上添加mustUseProp,isReservedTag,isReservedAttr,getTagNamespace,isUnknownElement
- 扩展Vue类options属性的directives,components
- 给Vue类添加实例方法__patch__,$mount
3、core/index.js
- 引入core/instance/index.js得到Vue类
- 为Vue类添加添加全局API
- 设置Vue实例属性isServer,ssrContext
- 设置Vue类属性 FunctionalRenderContext
- 添加Vue类的版本号
4、初始文件(core/instance/index.js)
- 声明Vue类
- 将Vue类传入各种初始化方法initMixin,stateMixin,eventsMixin,lifecycleMixin,renderMixin
三、初始文件core/instance/index.js
- 溯源大致到此,现在从
core/instance/index.js
开始走读,可看到initMixin(Vue)
,
stateMixin(Vue)
、eventsMixin(Vue)
、lifecycleMixin(Vue)
、renderMixin(Vue)
import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
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)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
1、initMixin(Vue):
- 获取options,挂载至 vm.$options上
- initLifecycle(vm):初始化vm属性值
初始化
vm.$parent = parent
vm.$root = parent ? parent.$root : vm
vm.$children = []
vm.$refs = {}
vm._watcher = null
vm._inactive = null
vm._directInactive = false
vm._isMounted = false
vm._isDestroyed = false
vm._isBeingDestroyed = false
的属性值
- initEvents(vm): 初始化vm._events, 是父组件在模板中使用v-on或@注册的监听子组件内触发的事件
vm._events = Object.create(null)
vm._hasHookEvent = false
const listeners = vm.$options._parentListeners
if (listeners) {
updateComponentListeners(vm, listeners)
}
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
- callHook(vm, 'beforeCreate'):
调用 beforeCreate 生命周期钩子
- initInjections(vm) :
初始化initInjections(inject:依赖和注入)
- initState(vm):
初始化state, props, methods, computed, watch
- initProvide(vm):
初始化initProvide(provide:依赖和注入)
- callHook(vm, 'created'):
调用 created 生命周期钩子
- vm.mount(vm.options.el):
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
2、stateMixin(Vue):
- 定义Vue.prototype.data,Vue.prototype.props,Vue.prototype.set,delete, $watch:
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)
Vue.prototype.$set = set
Vue.prototype.$delete = del
Vue.prototype.$watch = fn (){...}
3、eventsMixin(Vue):
- 定义on,once, off,emit 事件方法

4、lifecycleMixin(Vue):
- 定义 _update, forceUpdate,destroy方法

5、renderMixin(Vue):
- 定义$nextTick, _render方法
- _render(): 该方法会调用vm.$createElement创建虚拟DOM,如果返回值vnode不是虚拟DOM类型,将创建一个空的虚拟DOM。
if (!(vnode instanceof VNode)) {
if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {
warn(
'Multiple root nodes returned from render function. Render function ' +
'should return a single root node.',
vm
)
}
vnode = createEmptyVNode()
}
6、core/instance/index.js
初始化到此完毕,小块总结:
- 其初始化了state, props, methods, computed, watch,destory,data,props,forceUpdate等
- 对_data, _props使用 Object.defineProperty 添加响应式
- 设置访问数据代理,访问this.xx,实际上访问的是vm._data[xx], vm._props[xx]
- 添加event事件系统,实际上初始化的是父组件在模板中使用v-on或@注册的监听子组件内触发的事件
- 挂载createElement,为后续render返回虚拟DOM做准备。
- 调用对应的组件生命周期钩子, beforeCreate, created
四、关于$mount()
Vue.prototype.$mount = function(el?: string | Element, hydrating?: boolean): Component {
el = el && query(el)
const options = this.$options
if (!options.render) {
let template = options.template
if (template) {
}else {
}
const { render, staticRenderFns } = compileToFunctions(template, {...})
options.render = render
}
return mount.call(this, el, hydrating)
}
- 由于el参数有两种类型,可能是string 或者 element,调用query方法,统一转化为Element类型
- 如果没有手写render函数, 那么先获取template内容。再将template做为参数,调用compileToFunctions方法,返回render函数。
- 最后调用mount.call,这个方法实际上会调用runtime/index.js的mount方法,这个方法将会调用mountComponent方法, 即挂载组件。
五、挂载组件mountComponent()
export function mountComponent (
vm: Component,
el: ?Element,
hydrating?: boolean
): Component {
vm.$el = el
if (!vm.$options.render) {
vm.$options.render = createEmptyVNode
if (process.env.NODE_ENV !== 'production') {
if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
vm.$options.el || el) {
warn(
'You are using the runtime-only build of Vue where the template ' +
'compiler is not available. Either pre-compile the templates into ' +
'render functions, or use the compiler-included build.',
vm
)
} else {
warn(
'Failed to mount component: template or render function not defined.',
vm
)
}
}
}
callHook(vm, 'beforeMount')
let updateComponent
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
updateComponent = () => {
const name = vm._name
const id = vm._uid
const startTag = `vue-perf-start:${id}`
const endTag = `vue-perf-end:${id}`
mark(startTag)
const vnode = vm._render()
mark(endTag)
measure(`vue ${name} render`, startTag, endTag)
mark(startTag)
vm._update(vnode, hydrating)
mark(endTag)
measure(`vue ${name} patch`, startTag, endTag)
}
} else {
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
}
new Watcher(vm, updateComponent, noop, {
before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate')
}
}
}, true )
hydrating = false
if (vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')
}
return vm
}
- 调用beforeMount钩子
- 创建 updateComponent 函数, 之后更新数据 updateComponent 会被触发执行
- 实例化渲染watcher,执行回调
- 根据render函数获取VNode节点树
- 执行update方法,实际上是patch过程,vue会执行diff算法,完成一次渲染
- 调用mounted钩子
...Loading
...Loading
...Loading
- 六、创建虚拟节点
- Dom的创建流程
- Component的创建流程:
- Tag的创建流程:
Last、关于vue的生命周期:


vue2 | vue3 |
---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestroy | onBeforeUnmount |
destroyed | onUnmounted |
七、总结: