Vue3.0 - 01 - 02

80 阅读2分钟

回顾

Vue3.0 初始化渲染如下


import { createApp } from 'vue'

import App from './App.vue'

createApp(App).mount('#app')

上一篇已经分析过了 createApp 函数的源码,已经知道了执行完 createApp 函数后,得到的 app 对象的具体属性及方法。

接下来继续介绍 app.mount('#app') 方法

mount


export const createApp = ((...args) => {

    // ...

    const { mount } = app

    // 重写 app.mount 方法

    app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {

        // 本质上调用 document.querySelector 获取 id = '#app' 的 DOM 元素

        const container = normalizeContainer(containerOrSelector)

        if (!container) return

        const component = app._component

        // 若根组件非函数对象且未设置 render 和 template 属性,则使用容器的 innerHTML 作为模板的内容

        if (!isFunction(component) && !component.render && !component.template) {

            component.template = container.innerHTML

            if (__COMPAT__ && __DEV__) {

                // 向下兼容 ...

            }

        }

        // 清空原本容器(#app)里的内容

        container.innerHTML = ''

        // 进行 mount 操作

        const proxy = mount(container, false, container instanceof SVGElement)

        // ...

        return proxy

    }

    return app

}) as CreateAppFunction<Element>

重写 mount 函数,目的是为了跨平台。因为要跨平台,所以原 mount 函数不应该包含任何特定平台相关的逻辑,意味着这些代码的执行逻辑都与平台无关。因此我们需要在外部重写这个方法,来完善 Web 平台下的渲染逻辑。

重写后的 mount 函数,本质还是调用 ensureRenderer().createApp(...args) 函数返回的 mount 方法

做了三件事:

  1. 标准化 container dom 容器;

  2. 给 component.template 赋值;

  3. 执行 mount 进行挂载。


export function createAppAPI<HostElement>(

render: RootRenderFunction,

hydrate?: RootHydrateFunction

): CreateAppFunction<HostElement> {

    return function createApp(rootComponent, rootProps = null) {

    // ...

    const app: App = (context.app = {

    // ...

    mount(

    rootContainer: HostElement,

    isHydrate?: boolean,

    isSVG?: boolean

    ): any {

        // 是否渲染

        if (!isMounted) {

            // 创建 vnode

            const vnode = createVNode(

                rootComponent as ConcreteComponent,

                rootProps

            )

            // 将 context 挂载到根节点

            vnode.appContext = context

            // ...

            if (isHydrate && hydrate) {

                // ssr 渲染

            } else {

                // 普通渲染

                render(vnode, rootContainer, isSVG)

            }

            isMounted = true

            // 将容器挂载到 app._container 上

            app._container = rootContainer

            // ...

            if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {

                // 初始化devtools

            }

            return getExposeProxy(vnode.component!) || vnode.component!.proxy

            } else if (__DEV__) {

                // ...

            }

        },

        // ...

    })

    // ...

    // app 对象本体

    return app

}

简单来说做了三件事:

  1. 创建根组件对应的VNode对象;

  2. 设置 VNode 对象上的应用上下文属性;

  3. 执行渲染操作

到这里,基本结束了初始化 vue3.0 项目代码分析,既分析了 createApp(App).mount('#app') 这行代码具体干了什么。