Heim  >  Artikel  >  Web-Frontend  >  So verwenden Sie createApp in vue3

So verwenden Sie createApp in vue3

WBOY
WBOYnach vorne
2023-05-22 23:40:232396Durchsuche

Funktionsdefinition

createApp-Funktion ist in der Datei packets/runtime-dom/src/index.ts definiert

export const createApp = ((...args) => {
  const app = ensureRenderer().createApp(...args)
 
  if (__DEV__) {
    injectNativeTagCheck(app)
    injectCompilerOptionsCheck(app)
  }
 
  const { mount } = app
  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 !== &#39;v-cloak&#39; && /^(v-|:|@)/.test(attr.name)) {
            compatUtils.warnDeprecation(
              DeprecationTypes.GLOBAL_MOUNT_CONTAINER,
              null
            )
            break
          }
        }
      }
    }
 
    // clear content before mounting
    container.innerHTML = &#39;&#39;
    const proxy = mount(container, false, container instanceof SVGElement)
    if (container instanceof Element) {
      container.removeAttribute(&#39;v-cloak&#39;)
      container.setAttribute(&#39;data-v-app&#39;, &#39;&#39;)
    }
    return proxy
  }
 
  return app
}) as CreateAppFunction<Element>

(1) Erstellen Sie zuerst das App-Objekt

(2) Nehmen Sie die Mount-Methode im App-Objekt heraus und schreiben Sie sie neu Die Mount-Methode

  • Rufen Sie zuerst die Funktion normalizeContainer auf, um den Containerknoten abzurufen

    Seine Funktion ist Definiert als
  • function ensureRenderer() {
      return (
        renderer ||
        (renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
      )
    }
ensureRenderer durch Aufruf von createRenderer. Die Funktion createRenderer ist in der Datei packets/runtime-core/src/renderer.ts definiert.
    export function createRenderer<
      HostNode = RendererNode,
      HostElement = RendererElement
    >(options: RendererOptions<HostNode, HostElement>) {
      return baseCreateRenderer<HostNode, HostElement>(options)
    }
  • Letztendlich wird baseCreateRenderer aufgerufen, was letztendlich

    return {
        render,
        hydrate,
        createApp: createAppAPI(render, hydrate)
      }

    createAppAPI
Die Funktion createAppAPI zurückgibt ist in der Datei „packages/runtime-core/src/apiCreateApp.ts“ definiert, ihre Rückgabefunktion
    return function createApp(rootComponent, rootProps = null)
  • mount

    Sie ist in der Datei „packages/runtime-core/src/apiCreateApp.ts“ definiert
  • mount(
            rootContainer: HostElement,
            isHydrate?: boolean,
            isSVG?: boolean
          ): any {
            if (!isMounted) {
              const vnode = createVNode(
                rootComponent as ConcreteComponent,
                rootProps
              )
              // store app context on the root VNode.
              // this will be set on the root instance on initial mount.
              vnode.appContext = context
     
              // HMR root reload
              if (__DEV__) {
                context.reload = () => {
                  render(cloneVNode(vnode), rootContainer, isSVG)
                }
              }
     
              if (isHydrate && hydrate) {
                hydrate(vnode as VNode<Node, Element>, rootContainer as any)
              } else {
                render(vnode, rootContainer, isSVG)
              }
              isMounted = true
              app._container = rootContainer
              // for devtools and telemetry
              ;(rootContainer as any).__vue_app__ = app
     
              if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
                app._instance = vnode.component
                devtoolsInitApp(app, version)
              }
     
              return vnode.component!.proxy
            } else if (__DEV__) {
              warn(
                `App has already been mounted.\n` +
                  `If you want to remount the same app, move your app creation logic ` +
                  `into a factory function and create fresh app instances for each ` +
                  `mount - e.g. \`const createMyApp = () => createApp(App)\``
              )
            }
          }
(1) Aufruf createVNode zum Erstellen eines virtuellen Knotens

(2) Rufen Sie die Renderfunktion auf, um den Rendering-Vnode zu implementieren. Die Render-Funktion ist einer der Parameter, die übergeben werden, wenn die Funktion „baseCreateRenderer“ zurückkehrt und „createAppAPI“ aufruft. Die Funktion ist in der Datei „packages/runtime-core/src/renderer.ts“ definiert /src/renderer.ts-Datei,

// implementation
function baseCreateRenderer(
  options: RendererOptions,
  createHydrationFns?: typeof createHydrationFunctions
): any {
    ....
  const render: RootRenderFunction = (vnode, container, isSVG) => {
    if (vnode == null) {
      if (container._vnode) {
        unmount(container._vnode, null, null, true)
      }
    } else {
      patch(container._vnode || null, vnode, container, null, null, null, isSVG)
    }
    flushPostFlushCbs()
    container._vnode = vnode
  }
 .....
}

vergleicht die alten und neuen virtuellen Knoten n1 und n2. Wenn n1 leer ist, mounten Sie den Knoten. Zu diesem Zeitpunkt ist n1 leer. Führen Sie mountComponent aus, um den Knoten zu mounten.

mountComponent

Die Funktion ist in der Datei packets/runtime-core/src/renderer.ts definiert createComponentInstance, um die Komponente zu erstellen. Das Instanzobjekt und queueJob planen.

setupRenderEffect

Die Funktion ist in der Datei „packages/runtime-core/src/renderer.ts“ definiert. Der Schlüssel ist die darin definierte Funktion „componentUpdateFn“

const patch: PatchFn = (
    n1,
    n2,
    container,
    anchor = null,
    parentComponent = null,
    parentSuspense = null,
    isSVG = false,
    slotScopeIds = null,
    optimized = __DEV__ && isHmrUpdating ? false : !!n2.dynamicChildren
  ) => {
    // patching & not same type, unmount old tree
    if (n1 && !isSameVNodeType(n1, n2)) {
      anchor = getNextHostNode(n1)
      unmount(n1, parentComponent, parentSuspense, true)
      n1 = null
    }
 
    if (n2.patchFlag === PatchFlags.BAIL) {
      optimized = false
      n2.dynamicChildren = null
    }
 
    const { type, ref, shapeFlag } = n2
    switch (type) {
      case Text:
        processText(n1, n2, container, anchor)
        break
      case Comment:
        processCommentNode(n1, n2, container, anchor)
        break
      case Static:
        if (n1 == null) {
          mountStaticNode(n2, container, anchor, isSVG)
        } else if (__DEV__) {
          patchStaticNode(n1, n2, container, isSVG)
        }
        break
      case Fragment:
        processFragment(
          n1,
          n2,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized
        )
        break
      default:
        if (shapeFlag & ShapeFlags.ELEMENT) {
          processElement(
            n1,
            n2,
            container,
            anchor,
            parentComponent,
            parentSuspense,
            isSVG,
            slotScopeIds,
            optimized
          )
        } else if (shapeFlag & ShapeFlags.COMPONENT) {
          processComponent(
            n1,
            n2,
            container,
            anchor,
            parentComponent,
            parentSuspense,
            isSVG,
            slotScopeIds,
            optimized
          )
        } else if (shapeFlag & ShapeFlags.TELEPORT) {
          ;(type as typeof TeleportImpl).process(
            n1 as TeleportVNode,
            n2 as TeleportVNode,
            container,
            anchor,
            parentComponent,
            parentSuspense,
            isSVG,
            slotScopeIds,
            optimized,
            internals
          )
        } else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
          ;(type as typeof SuspenseImpl).process(
            n1,
            n2,
            container,
            anchor,
            parentComponent,
            parentSuspense,
            isSVG,
            slotScopeIds,
            optimized,
            internals
          )
        } else if (__DEV__) {
          warn(&#39;Invalid VNode type:&#39;, type, `(${typeof type})`)
        }
    }
 
    // set ref
    if (ref != null && parentComponent) {
      setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2)
    }
  }
const patch: PatchFn = (
    n1,
    n2,
    container,
    anchor = null,
    parentComponent = null,
    parentSuspense = null,
    isSVG = false,
    slotScopeIds = null,
    optimized = __DEV__ && isHmrUpdating ? false : !!n2.dynamicChildren
  ) => {
    // patching & not same type, unmount old tree
    if (n1 && !isSameVNodeType(n1, n2)) {
      anchor = getNextHostNode(n1)
      unmount(n1, parentComponent, parentSuspense, true)
      n1 = null
    }
 
    if (n2.patchFlag === PatchFlags.BAIL) {
      optimized = false
      n2.dynamicChildren = null
    }
 
    const { type, ref, shapeFlag } = n2
    switch (type) {
      case Text:
        processText(n1, n2, container, anchor)
        break
      case Comment:
        processCommentNode(n1, n2, container, anchor)
        break
      case Static:
        if (n1 == null) {
          mountStaticNode(n2, container, anchor, isSVG)
        } else if (__DEV__) {
          patchStaticNode(n1, n2, container, isSVG)
        }
        break
      case Fragment:
        processFragment(
          n1,
          n2,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          slotScopeIds,
          optimized
        )
        break
      default:
        if (shapeFlag & ShapeFlags.ELEMENT) {
          processElement(
            n1,
            n2,
            container,
            anchor,
            parentComponent,
            parentSuspense,
            isSVG,
            slotScopeIds,
            optimized
          )
        } else if (shapeFlag & ShapeFlags.COMPONENT) {
          processComponent(
            n1,
            n2,
            container,
            anchor,
            parentComponent,
            parentSuspense,
            isSVG,
            slotScopeIds,
            optimized
          )
        } else if (shapeFlag & ShapeFlags.TELEPORT) {
          ;(type as typeof TeleportImpl).process(
            n1 as TeleportVNode,
            n2 as TeleportVNode,
            container,
            anchor,
            parentComponent,
            parentSuspense,
            isSVG,
            slotScopeIds,
            optimized,
            internals
          )
        } else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
          ;(type as typeof SuspenseImpl).process(
            n1,
            n2,
            container,
            anchor,
            parentComponent,
            parentSuspense,
            isSVG,
            slotScopeIds,
            optimized,
            internals
          )
        } else if (__DEV__) {
          warn(&#39;Invalid VNode type:&#39;, type, `(${typeof type})`)
        }
    }
 
    // set ref
    if (ref != null && parentComponent) {
      setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2)
    }
  }

Wenn die Komponente nicht gemountet wurde, muss sie gemountet werden. und nach dem Mounten Nachdem der Download abgeschlossen ist, setzen Sie die isMounted-Eigenschaft der Komponente auf true, um anzuzeigen, dass die Komponente erfolgreich gemountet wurde. Wenn die Komponente bereits gemountet ist, aktualisieren Sie sie.

Rekursiv die Patch-Funktion aufrufen, um die Komponente zu mounten

processFragment

Die Funktion ist in der Datei packets/runtime-core/src/renderer.ts definiert

const processComponent = (
    n1: VNode | null,
    n2: VNode,
    container: RendererElement,
    anchor: RendererNode | null,
    parentComponent: ComponentInternalInstance | null,
    parentSuspense: SuspenseBoundary | null,
    isSVG: boolean,
    slotScopeIds: string[] | null,
    optimized: boolean
  ) => {
    n2.slotScopeIds = slotScopeIds
    if (n1 == null) {
      if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
        ;(parentComponent!.ctx as KeepAliveContext).activate(
          n2,
          container,
          anchor,
          isSVG,
          optimized
        )
      } else {
        mountComponent(
          n2,
          container,
          anchor,
          parentComponent,
          parentSuspense,
          isSVG,
          optimized
        )
      }
    } else {
      updateComponent(n1, n2, optimized)
    }
  }

(1) Wenn n1 leer ist, führen Sie mountChildren aus

( 2) Andernfalls führen Sie „patchChildren“ aus.

mountChildren

Die Funktion ist in der Datei „packages/runtime-core/src/renderer.ts“ definiert packets/runtime-core/ In der Datei src/renderer.ts

const mountComponent: MountComponentFn = (
    initialVNode,
    container,
    anchor,
    parentComponent,
    parentSuspense,
    isSVG,
    optimized
  ) => {
    // 2.x compat may pre-creaate the component instance before actually
    // mounting
    const compatMountInstance =
      __COMPAT__ && initialVNode.isCompatRoot && initialVNode.component
    const instance: ComponentInternalInstance =
      compatMountInstance ||
      (initialVNode.component = createComponentInstance(
        initialVNode,
        parentComponent,
        parentSuspense
      ))
 
    // inject renderer internals for keepAlive
    if (isKeepAlive(initialVNode)) {
      ;(instance.ctx as KeepAliveContext).renderer = internals
    }
 
    // resolve props and slots for setup context
    if (!(__COMPAT__ && compatMountInstance)) {
      setupComponent(instance)
    }
 
    // setup() is async. This component relies on async logic to be resolved
    // before proceeding
    if (__FEATURE_SUSPENSE__ && instance.asyncDep) {
      parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect)
 
      // Give it a placeholder if this is not hydration
      // TODO handle self-defined fallback
      if (!initialVNode.el) {
        const placeholder = (instance.subTree = createVNode(Comment))
        processCommentNode(null, placeholder, container!, anchor)
      }
      return
    }
 
    setupRenderEffect(
      instance,
      initialVNode,
      container,
      anchor,
      parentSuspense,
      isSVG,
      optimized
    )
  }

(1) Wenn n1 leer ist, rufen Sie mountElement auf, um das Element zu mounten

(2) Wenn n1 nicht leer ist, rufen Sie patchElement auf, um das Element zu aktualisieren

Führen Sie zu diesem Zeitpunkt das Mount-Element aus.

mountElement

Die Funktion ist in der Datei packets/runtime-core/src/renderer.ts definiert

const componentUpdateFn = () => {
      if (!instance.isMounted) {
        let vnodeHook: VNodeHook | null | undefined
        const { el, props } = initialVNode
        const { bm, m, parent } = instance
 
        effect.allowRecurse = false
        // beforeMount hook
        if (bm) {
          invokeArrayFns(bm)
        }
        // onVnodeBeforeMount
        if ((vnodeHook = props && props.onVnodeBeforeMount)) {
          invokeVNodeHook(vnodeHook, parent, initialVNode)
        }
        if (
          __COMPAT__ &&
          isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
        ) {
          instance.emit(&#39;hook:beforeMount&#39;)
        }
        effect.allowRecurse = true
 
        if (el && hydrateNode) {
          // vnode has adopted host node - perform hydration instead of mount.
          const hydrateSubTree = () => {
    
            instance.subTree = renderComponentRoot(instance)
            
            hydrateNode!(
              el as Node,
              instance.subTree,
              instance,
              parentSuspense,
              null
            )
            
          }
 
          if (isAsyncWrapper(initialVNode)) {
            (initialVNode.type as ComponentOptions).__asyncLoader!().then(
              // note: we are moving the render call into an async callback,
              // which means it won&#39;t track dependencies - but it&#39;s ok because
              // a server-rendered async wrapper is already in resolved state
              // and it will never need to change.
              () => !instance.isUnmounted && hydrateSubTree()
            )
          } else {
            hydrateSubTree()
          }
        } else {
          
          const subTree = (instance.subTree = renderComponentRoot(instance))
         
          patch(
            null,
            subTree,
            container,
            anchor,
            instance,
            parentSuspense,
            isSVG
          )
          
          initialVNode.el = subTree.el
        }
        // mounted hook
        if (m) {
          queuePostRenderEffect(m, parentSuspense)
        }
        // onVnodeMounted
        if ((vnodeHook = props && props.onVnodeMounted)) {
          const scopedInitialVNode = initialVNode
          queuePostRenderEffect(
            () => invokeVNodeHook(vnodeHook!, parent, scopedInitialVNode),
            parentSuspense
          )
        }
        if (
          __COMPAT__ &&
          isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
        ) {
          queuePostRenderEffect(
            () => instance.emit(&#39;hook:mounted&#39;),
            parentSuspense
          )
        }
 
        // activated hook for keep-alive roots.
        // #1742 activated hook must be accessed after first render
        // since the hook may be injected by a child keep-alive
        if (initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
          instance.a && queuePostRenderEffect(instance.a, parentSuspense)
          if (
            __COMPAT__ &&
            isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
          ) {
            queuePostRenderEffect(
              () => instance.emit(&#39;hook:activated&#39;),
              parentSuspense
            )
          }
        }
        instance.isMounted = true
        // #2458: deference mount-only object parameters to prevent memleaks
        initialVNode = container = anchor = null as any
      } else {
        // updateComponent
        // This is triggered by mutation of component&#39;s own state (next: null)
        // OR parent calling processComponent (next: VNode)
        let { next, bu, u, parent, vnode } = instance
        let originNext = next
        let vnodeHook: VNodeHook | null | undefined
 
        if (next) {
          next.el = vnode.el
          updateComponentPreRender(instance, next, optimized)
        } else {
          next = vnode
        }
 
        // Disallow component effect recursion during pre-lifecycle hooks.
        effect.allowRecurse = false
        // beforeUpdate hook
        if (bu) {
          invokeArrayFns(bu)
        }
        // onVnodeBeforeUpdate
        if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) {
          invokeVNodeHook(vnodeHook, parent, next, vnode)
        }
        if (
          __COMPAT__ &&
          isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
        ) {
          instance.emit(&#39;hook:beforeUpdate&#39;)
        }
        effect.allowRecurse = true
 
        // render
        const nextTree = renderComponentRoot(instance)
        const prevTree = instance.subTree
        instance.subTree = nextTree
        patch(
          prevTree,
          nextTree,
          // parent may have changed if it&#39;s in a teleport
          hostParentNode(prevTree.el!)!,
          // anchor may have changed if it&#39;s in a fragment
          getNextHostNode(prevTree),
          instance,
          parentSuspense,
          isSVG
        )
     
        next.el = nextTree.el
        if (originNext === null) {
          // self-triggered update. In case of HOC, update parent component
          // vnode el. HOC is indicated by parent instance&#39;s subTree pointing
          // to child component&#39;s vnode
          updateHOCHostEl(instance, nextTree.el)
        }
        // updated hook
        if (u) {
          queuePostRenderEffect(u, parentSuspense)
        }
        // onVnodeUpdated
        if ((vnodeHook = next.props && next.props.onVnodeUpdated)) {
          queuePostRenderEffect(
            () => invokeVNodeHook(vnodeHook!, parent, next!, vnode),
            parentSuspense
          )
        }
        if (
          __COMPAT__ &&
          isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
        ) {
          queuePostRenderEffect(
            () => instance.emit(&#39;hook:updated&#39;),
            parentSuspense
          )
        }
      }
    }

(1) Rufen Sie hostCreateElement auf, um einen DOM-Elementknoten basierend auf dem Typ und anderen Attributen zu erstellen

(2) Bestimmen der Typ des untergeordneten Knotens. Wenn der untergeordnete Knoten Klartext ist, wird der Klartext hostSetElementText direkt verarbeitet. Wenn der untergeordnete Knoten ein Array ist, wird die Funktion mountChildren aufgerufen, um die Attribute des untergeordneten Knotens tief zu durchlaufen. Hauptsächlich wird hostPatchProp und setScopeId aufgerufen. (4) HostInsert aufrufen, um el in den Container einzubinden

Das obige ist der detaillierte Inhalt vonSo verwenden Sie createApp in vue3. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen