vue实例化
- initGlobalAPI(Vue) 初始化全局函数
为Vue 添加 config,util,set,delete,nextTick,observable,options,
use mixin extend 'component', directive filter 等属性和方法
- initMixin(Vue)
给Vue的原型添加 _init方法
- stateMixin(Vue)
给Vue的原型添加 $data,$props,$set,$delete,$watch
- eventsMixin(Vue)
给Vue的原型添加 $on, $emit, $off, $once 四个方法
- lifecycleMixin(Vue)
给 Vue的原型添加_update,$forceUpdate, $destroy
- renderMixin(Vue)
// 给Vue的原型添加
// target._o = markOnce
// target._n = toNumber
// target._s = toString
// target._l = renderList
// target._t = renderSlot
// target._q = looseEqual
// target._i = looseIndexOf
// target._m = renderStatic
// target._f = resolveFilter
// target._k = checkKeyCodes
// target._b = bindObjectProps
// target._v = createTextVNode
// target._e = createEmptyVNode
// target._u = resolveScopedSlots
// target._g = bindObjectListeners
// target._d = bindDynamicKeys
// target._p = prependModifier
// 以及$nextTick, _render
- new Vue
初始化Vue,并且执行 this._init(options), initProxy(vm);
- initLifecycle(vm)
为vue实例添加属性 $parent $children $root $refs
- initEvents(vm)
为vue的实例 添加 _events _hasHookEvent,初始化组件通过@on监听的事件
- initRender(vm)
为实例添加 $slots .$scopedSlots _c $createElement $attrs $listeners
将$attrs $listeners响应式处理, 不做依赖收集
- callHook(vm, 'beforeCreate')
执行beforeCreate钩子
- initInjections(vm)
处理提供的 inject ,inject不做响应式处理 - initState(vm)
初始化 props methods data computed watch, 并做响应式处理
- initProps(vm, opts.props)
- for (var key in propsOptions) loop( key ); ,遍历初始化传入的props
- var value = validateProp(key, propsOptions, propsData, vm);
- validateProp对props的的属性的值进行observe,比如 props: {
fatherProp: {
type : Object,
default: () => ({
testprop: '测试props'
})
}
}validateProp函数会对 {testprop: '测试props'}进行observe
2. loop函数内部调用defineReactive(props, key, value)- defineReactive函数内部调用observe(val);递归观测
- proxy(vm,
_props
, key),将_props 的属性代理到 vm实例上- initMethods(vm, opts.methods)
- vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
- initData(vm)
- observe(data, true /* asRootData */)
- ob = new Observer(value)
- this.walk(value)
- defineReactive(obj, keys[i])
- initComputed(vm, opts.computed)
- initWatch(vm, opts.watch)
- initProvide(vm)
给 vue实例添加 _provided属性,初始化组件的provide
- callHook(vm, 'created')
调用 created钩子
- vm.$mount(vm.$options.el)
开始执行挂载
- 调用compileToFunctions生成编译render函数
// src/compiler/to-function.js function createFunction (code, errors) { try { return new Function(code) } catch (err) { errors.push({ err, code }) return noop } } export function createCompileToFunctionFn (compile) { return function compileToFunctions ( template, options, vm ){ // 对模板进行编译 const compiled = compile(template, options) res.render = createFunction(compiled.render, fnGenErrors) res.staticRenderFns = compiled.staticRenderFns.map(code => { return createFunction(code, fnGenErrors) }) return (cache[key] = res) } } // src/compiler/create-compiler.js export function createCompilerCreator (baseCompile) { return function createCompiler (baseOptions) { function compile ( template, options ){ const compiled = baseCompile(template.trim(), finalOptions) return compiled } return { compile, compileToFunctions: createCompileToFunctionFn(compile) } } }
// src/compiler/index.js
import { createCompilerCreator } from './create-compiler'
// `createCompilerCreator` allows creating compilers that use alternative
// parser/optimizer/codegen, e.g the SSR optimizing compiler.
// Here we just export a default compiler using the default parts.
export const createCompiler = createCompilerCreator(function baseCompile (
template: string,
options: CompilerOptions
) {
const ast = parse(template.trim(), options)
if (options.optimize !== false) {
optimize(ast, options)
}
const code = generate(ast, options)
return {
ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
})
// src/platforms/web/compiler/index.js
import { createCompiler } from 'compiler/index'
const { compile, compileToFunctions } = createCompiler(baseOptions)
export { compile, compileToFunctions }
// src/platforms/web/entry-runtime-with-compiler.js
import { compileToFunctions } from './compiler/index'
const { render, staticRenderFns } = compileToFunctions(template, {
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
// ref.render 此时已经成了 new Function('with(this){}')
var render = ref.render;
- 调用function compile (){}
- 调用function baseCompile(){}
- var ast = parse(template.trim(), options)
- 调用generate(ast, options);
- 调用genElement(ast, state);
- genChildren()
- (children.map(function (c) { return gen(c, state); })
- gen 函数就是 genNode,递归调用genElement生成渲染函数
```js
function genNode (node, state) {
if (node.type === 1) {
return genElement(node, state)
} else if (node.type === 3 && node.isComment) {
return genComment(node)
} else {
return genText(node)
}
}
- 调用genElement返回【code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")";】
- return {
render: ("with(this){return " + code + "}"),
staticRenderFns: state.staticRenderFns
}
- 调用mount.call(this, el, hydrating) 实际调用Vue.prototype.$mount
- mountComponent(this, el, hydrating),开始挂载组件
- callHook(vm, 'beforeMount'); 调用 beforeMount钩子
- updateComponent = function () { vm._update(vm._render(), hydrating); }; 定义updateComponent函数,等待调用
- 调用new Watcher()
new Watcher(vm, updateComponent, noop, {
before: function before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate');
}
}
}, true /* isRenderWatcher */);
- this.get()
- this.getter.call(vm, vm);
- updateComponent()
- vm._render()
- render.call(vm._renderProxy, vm.$createElement);
(function anonymous() {
with(this) {
return _c('div', {
attrs: {
"id": "app"
}
}, [_c('h1', [_v(_s(fatherData))]), _v(" "), _c('h2', [_v(_s(fatherProp3))]), _v(" "), _c('test-test', {
on: {
"xxxx": xxxx
}
})], 1)
}
})
- render函数内部获取了props和data定义的数据,所以调用了reactiveGetter(),开始依赖收集
- dep.depend();
Dep.prototype.depend = function depend () {
if (Dep.target) {
// this 是dep实例
// Dep.target 是watcher实例
Dep.target.addDep(this);
}
};
- Dep.target.addDep(this); this是dep实例
Watcher.prototype.addDep = function addDep (dep) {
var id = dep.id;
// this 是watcher实例
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id);
this.newDeps.push(dep);
if (!this.depIds.has(id)) {
// 依赖收集
dep.addSub(this);
}
}
};
- 调用vm._update(vm._render(), hydrating);
// 第一次渲染没有prevVnode, 直接移除旧的
if (!prevVnode) {
// initial render
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
} else {
// updates
vm.$el = vm.__patch__(prevVnode, vnode);
}
- patch (oldVnode, vnode, hydrating, removeOnly){}
- createElm()
createElm(
vnode,
insertedVnodeQueue,
// extremely rare edge case: do not insert if old element is in a
// leaving transition. Only happens when combining transition +
// keep-alive + HOCs. (#4590)
oldElm._leaveCb ? null : parentElm,
nodeOps.nextSibling(oldElm)
);
-
setScope(vnode); 为scoped Css设置data-v-5132e20a 唯一id
-
createChildren( (vnode, children, insertedVnodeQueue))
- checkDuplicateKeys(children); 当元素设置key的时候,比如for循环
- 遍历生成children
for (var i = 0; i < children.length; ++i) { createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i); }
- 如果发现了自定义组件则调用 createComponentInstanceForVnode()
- 重复执行步骤16 - 21
- removeVnodes([oldVnode], 0, 0); 移除老的node节点