# 模板编译都经历了那些什么

首先回顾一下vue._init()这个函数

Vue.prototype._init = function (options?: Object) {
    // …………,各种状态初始化

    // 如果传入了el,那么渲染
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
}
1
2
3
4
5
6
7
8

从上面的代码中可以看出,在init函数最后,执行了$mount这个函数。

# $mount

// platforms/web/runtime/index.js
// public mount method
Vue.prototype.$mount = function (
    el?: string | Element,
    hydrating?: boolean
): Component {
    el = el && inBrowser ? query(el) : undefined
    return mountComponent(this, el, hydrating)
}

// core/instance/lifecycle
export function mountComponent (
    vm: Component,
    el: ?Element,
    hydrating?: boolean
): Component {
    vm.$el = el

    // 渲染节点
    if (!vm.$options.render) {
        vm.$options.render = createEmptyVNode
    }
    callHook(vm, 'beforeMount')

    let updateComponent
    updateComponent = () => {
        vm._update(vm._render(), hydrating)
    }

    // 创建一个watcher,其回调是其render函数
    new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */)
    hydrating = false

    // 改变内部变量的状态_isMounted,触发钩子
    if (vm.$vnode == null) {
        vm._isMounted = true
        callHook(vm, 'mounted')
    }
    return vm
}


// platfrom/web/entry-runtime-with-compiler.js
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
    el?: string | Element,
    hydrating?: boolean
): Component {
    // 获取到要渲染的节点
    el = el && query(el)

    // 不可以是body或者document
    if (el === document.body || el === document.documentElement) {
        return this
    }

    const options = this.$options
    // 如果render函数不存在
    if (!options.render) {
        let template = options.template

        // 确认模版,template存在的时候,获取template,不存在的时候获取el的outerHtml
        if (template) {
            if (typeof template === 'string') {
                if (template.charAt(0) === '#') {
                    template = idToTemplate(template)
                }
            } else if (template.nodeType) {
                template = template.innerHTML
            } else {
                return this
            }
        } else if (el) {
            template = getOuterHTML(el)
        }

        // 使template编译成render函数
        if (template) {
            const { render, staticRenderFns } = compileToFunctions(template, {
                shouldDecodeNewlines,
                shouldDecodeNewlinesForHref,
                delimiters: options.delimiters,
                comments: options.comments
            }, this)
            options.render = render
            options.staticRenderFns = staticRenderFns
        }
    }
    return mount.call(this, el, hydrating)
}
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
88
89
90

# 那么模版是怎么编译的

从上面的代码中,可以看出,最后执行了compileToFunctions函数得到了renderstaticRenderFns函数。那么也就是是,模版的解析是在compileToFunctions这个函数中实现的。继续扒代码

// src/paltforms/compiler/index

const { compile, compileToFunctions } = createCompiler(baseOptions)

1
2
3
4
上次更新: 1/10/2020, 2:20:13 PM