# 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 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, 并做响应式处理
1. initProps(vm, opts.props)
1. for (var key in propsOptions) loop( key ); ,遍历初始化传入的props
1. var value = validateProp(key, propsOptions, propsData, vm);
1. validateProp对props的的属性的值进行observe,比如 props: {
fatherProp: {
type : Object,
default: () => ({
testprop: '测试props'
})
}
}validateProp函数会对 {testprop: '测试props'}进行observe
2. loop函数内部调用defineReactive(props, key, value)
1. defineReactive函数内部调用observe(val);递归观测
2. proxy(vm, `_props`, key),将_props 的属性代理到 vm实例上
2. initMethods(vm, opts.methods)
1. vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
3. initData(vm)
1. observe(data, true /* asRootData */)
1. ob = new Observer(value)
1. this.walk(value)
1. defineReactive(obj, keys[i])
1. var childOb = !shallow && observe(val); 对数据进行递归处理
4. initComputed(vm, opts.computed)
5. initWatch(vm, opts.watch)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- initProvide(vm)
给 vue实例添加 _provided属性,初始化组件的provide
- callHook(vm, 'created')
调用 created钩子
- vm.$mount(vm.$options.el)
开始执行挂载
- 调用compileToFunctions生成编译render函数
var ref = compileToFunctions(template, {
outputSourceRange: "development" !== 'production',
shouldDecodeNewlines: shouldDecodeNewlines,
shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this);
// 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;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
- 调用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生成渲染函数
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) } }
1
2
3
4
5
6
7
8
9
- (children.map(function (c) { return gen(c, state); })
- genChildren()
- 调用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 */);
1
2
3
4
5
6
7
2
3
4
5
6
7
- 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)
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- render函数内部获取了props和data定义的数据,所以调用了reactiveGetter(),开始依赖收集
- dep.depend();
Dep.prototype.depend = function depend () {
if (Dep.target) {
// this 是dep实例
// Dep.target 是watcher实例
Dep.target.addDep(this);
}
};
1
2
3
4
5
6
7
2
3
4
5
6
7
- 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);
}
}
};
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 调用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);
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- 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)
);
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 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); }
1
2
3
- 如果发现了自定义组件则调用 createComponentInstanceForVnode()
- 重复执行步骤16 - 21
- removeVnodes([oldVnode], 0, 0); 移除老的node节点
# 简
- initEvents
- callHook(vm, 'beforeCreate');
- initState
- callHook(vm, 'created');
- 生成render函数
- $mount =》mountComponent(this, el, hydrating)开始挂载
- callHook(vm, 'beforeMount');
- new Watcher()
- updateComponent()
- vm._update(vm._render(), hydrating)
- 调用render函数
- 依赖收集
- 调用 vm._update
- 调用 patch函数,function patch (oldVnode, vnode, hydrating, removeOnly)
- 更新dom
- callHook(vm, 'mounted');
← vue diff算法 vue打包优化 →