$mount 方法在由于跟构建方式相关,所以在很多地方都被定义,我们先来看在原型上定义的$mount。
    目录:src/platform/web/runtime/index.js

    1. Vue.prototype.$mount = function (
    2. el?: string | Element,
    3. hydrating?: boolean
    4. ): Component {
    5. el = el && inBrowser ? query(el) : undefined
    6. return mountComponent(this, el, hydrating)
    7. }

    可以看到$mount方法接受两个参数,第一个参数是el,表示要挂载的元素,el可以使字符串或DOM对象,如果是字符串,则调用query方法转为DOM对象,第二个参数是和服务端渲染相关,在浏览器环境下我们不需要传第二个参数。
    调用$mount方法实际会去调用mountComponent()方法

    mountComponent()方法在src/core/instance/lifecycle.js中定义

    1. export function mountComponent (
    2. vm: Component,
    3. el: ?Element,
    4. hydrating?: boolean
    5. ): Component {
    6. vm.$el = el
    7. if (!vm.$options.render) {
    8. vm.$options.render = createEmptyVNode
    9. if (process.env.NODE_ENV !== 'production') {
    10. /* istanbul ignore if */
    11. if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
    12. vm.$options.el || el) {
    13. warn(
    14. 'You are using the runtime-only build of Vue where the template ' +
    15. 'compiler is not available. Either pre-compile the templates into ' +
    16. 'render functions, or use the compiler-included build.',
    17. vm
    18. )
    19. } else {
    20. warn(
    21. 'Failed to mount component: template or render function not defined.',
    22. vm
    23. )
    24. }
    25. }
    26. }
    27. callHook(vm, 'beforeMount')
    28. let updateComponent
    29. /* istanbul ignore if */
    30. if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
    31. updateComponent = () => {
    32. const name = vm._name
    33. const id = vm._uid
    34. const startTag = `vue-perf-start:${id}`
    35. const endTag = `vue-perf-end:${id}`
    36. mark(startTag)
    37. const vnode = vm._render()
    38. mark(endTag)
    39. measure(`vue ${name} render`, startTag, endTag)
    40. mark(startTag)
    41. vm._update(vnode, hydrating)
    42. mark(endTag)
    43. measure(`vue ${name} patch`, startTag, endTag)
    44. }
    45. } else {
    46. updateComponent = () => {
    47. vm._update(vm._render(), hydrating)
    48. }
    49. }
    50. // we set this to vm._watcher inside the watcher's constructor
    51. // since the watcher's initial patch may call $forceUpdate (e.g. inside child
    52. // component's mounted hook), which relies on vm._watcher being already defined
    53. new Watcher(vm, updateComponent, noop, {
    54. before () {
    55. if (vm._isMounted && !vm._isDestroyed) {
    56. callHook(vm, 'beforeUpdate')
    57. }
    58. }
    59. }, true /* isRenderWatcher */)
    60. hydrating = false
    61. // manually mounted instance, call mounted on self
    62. // mounted is called for render-created child components in its inserted hook
    63. if (vm.$vnode == null) {
    64. vm._isMounted = true
    65. callHook(vm, 'mounted')
    66. }
    67. return vm
    68. }

    上面代码可以看到mountComponent()的核心就是先实例化一个Wancher,然后在回调中调用updateComponent,在updateComponent中调用vm.render方法生成虚拟Node最终调用vm._update更新DOM。
    Watcher在这里起两个作用,一个是初始化的时候会执行回调函数,触发执行vm._render和vm._updata,另一个是当vm实例中监测的数据发生变化是执行回调函数(后面介绍)。

    函数最后判断为根节点的时候设置 vm._isMounted 为 true, 表示这个实例已经挂载了,同时执行 mounted 钩子函数。 这里注意 vm.$vnode 表示 Vue 实例的父虚拟 Node,所以它为 Null 则表示当前是根 Vue 的实例