Vue3 源码 — 组件详解

组件是一个抽象的概念,它是对一棵 DOM 树的抽象,从表现上看,组件的模板(template 包裹的内容)决定了组件生成的 DOM 标签,在 Vue.js 内部,一个组件想要真正的渲染生成 DOM,需要经历 创建 vnode - 渲染 vnode - 生成 DOM 这几个步骤。

vnode 就是一个可以描述组件信息的 JavaScript 对象

初始化应用程序

首先看一下 Vue3 的应用初始化:

import { createApp } from 'vue'
import App from './app'
const app = createApp(App)
app.mount('#app')

Vue3 和 Vue2 类似,都是把根组件挂载到 id 为 app 的 DOM 节点上,不过 Vue3 导入了一个 createApp 作为入口函数。

export const createApp = ((...args) => {
  // 创建 app 对象
  const app = ensureRenderer().createApp(...args)

  if (__DEV__) {
    injectNativeTagCheck(app)
    injectCompilerOptionsCheck(app)
  }

  const { mount } = app
  // 重写 mount 方法
  app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
    const container = normalizeContainer(containerOrSelector)
    if (!container) return

    const component = app._component
    if (!isFunction(component) && !component.render && !component.template) {
      // __UNSAFE__
      // Reason: potential execution of JS expressions in in-DOM template.
      // The user must make sure the in-DOM template is trusted. If it's
      // rendered by the server, the template should not contain any user data.
      component.template = container.innerHTML
      // 2.x compat check
      if (__COMPAT__ && __DEV__) {
        for (let i = 0; i < container.attributes.length; i++) {
          const attr = container.attributes[i]
          if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
            compatUtils.warnDeprecation(
              DeprecationTypes.GLOBAL_MOUNT_CONTAINER,
              null
            )
            break
          }
        }
      }
    }

    // clear content before mounting
    container.innerHTML = ''
    const proxy = mount(container, false, container instanceof SVGElement)
    if (container instanceof Element) {
      container.removeAttribute('v-cloak')
      container.setAttribute('data-v-app', '')
    }
    return proxy
  }
  // 导出 app
  return app
}) as CreateAppFunction<Element>

创建 app 对象

const app = ensureRenderer().createApp(...args)

Last updated

Was this helpful?