vue3中的createApp怎么使用

其他教程   发布日期:2025年03月03日   浏览次数:161

这篇文章主要介绍“vue3中的createApp怎么使用”,在日常操作中,相信很多人在vue3中的createApp怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue3中的createApp怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

函数定义

createApp函数定义在文件 packages/runtime-dom/src/index.ts中

  1. export const createApp = ((...args) => {
  2. const app = ensureRenderer().createApp(...args)
  3. if (__DEV__) {
  4. injectNativeTagCheck(app)
  5. injectCompilerOptionsCheck(app)
  6. }
  7. const { mount } = app
  8. app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {
  9. const container = normalizeContainer(containerOrSelector)
  10. if (!container) return
  11. const component = app._component
  12. if (!isFunction(component) && !component.render && !component.template) {
  13. // __UNSAFE__
  14. // Reason: potential execution of JS expressions in in-DOM template.
  15. // The user must make sure the in-DOM template is trusted. If it's
  16. // rendered by the server, the template should not contain any user data.
  17. component.template = container.innerHTML
  18. // 2.x compat check
  19. if (__COMPAT__ && __DEV__) {
  20. for (let i = 0; i < container.attributes.length; i++) {
  21. const attr = container.attributes[i]
  22. if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
  23. compatUtils.warnDeprecation(
  24. DeprecationTypes.GLOBAL_MOUNT_CONTAINER,
  25. null
  26. )
  27. break
  28. }
  29. }
  30. }
  31. }
  32. // clear content before mounting
  33. container.innerHTML = ''
  34. const proxy = mount(container, false, container instanceof SVGElement)
  35. if (container instanceof Element) {
  36. container.removeAttribute('v-cloak')
  37. container.setAttribute('data-v-app', '')
  38. }
  39. return proxy
  40. }
  41. return app
  42. }) as CreateAppFunction<Element>

(1)首先创建App对象

(2)取出app对象中的mount方法,重写mount方法

  • 首先调用 normalizeContainer 函数来获取container节点

  • 清空container的innerHTML

  • 调用原mount方法

ensureRenderer

其函数定义为

  1. function ensureRenderer() {
  2. return (
  3. renderer ||
  4. (renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
  5. )
  6. }

ensureRenderer通过调用createRenderer,createRenderer函数定义在 packages/runtime-core/src/renderer.ts文件中

  1. export function createRenderer<
  2. HostNode = RendererNode,
  3. HostElement = RendererElement
  4. >(options: RendererOptions<HostNode, HostElement>) {
  5. return baseCreateRenderer<HostNode, HostElement>(options)
  6. }

最终是调用baseCreateRenderer,其最终返回

  1. return {
  2. render,
  3. hydrate,
  4. createApp: createAppAPI(render, hydrate)
  5. }

createAppAPI

createAppAPI函数定义在 packages/runtime-core/src/apiCreateApp.ts文件中,其返回函数

  1. return function createApp(rootComponent, rootProps = null)

mount

其定义在packages/runtime-core/src/apiCreateApp.ts文件

  1. mount(
  2. rootContainer: HostElement,
  3. isHydrate?: boolean,
  4. isSVG?: boolean
  5. ): any {
  6. if (!isMounted) {
  7. const vnode = createVNode(
  8. rootComponent as ConcreteComponent,
  9. rootProps
  10. )
  11. // store app context on the root VNode.
  12. // this will be set on the root instance on initial mount.
  13. vnode.appContext = context
  14. // HMR root reload
  15. if (__DEV__) {
  16. context.reload = () => {
  17. render(cloneVNode(vnode), rootContainer, isSVG)
  18. }
  19. }
  20. if (isHydrate && hydrate) {
  21. hydrate(vnode as VNode<Node, Element>, rootContainer as any)
  22. } else {
  23. render(vnode, rootContainer, isSVG)
  24. }
  25. isMounted = true
  26. app._container = rootContainer
  27. // for devtools and telemetry
  28. ;(rootContainer as any).__vue_app__ = app
  29. if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
  30. app._instance = vnode.component
  31. devtoolsInitApp(app, version)
  32. }
  33. return vnode.component!.proxy
  34. } else if (__DEV__) {
  35. warn(
  36. `App has already been mounted.
  37. ` +
  38. `If you want to remount the same app, move your app creation logic ` +
  39. `into a factory function and create fresh app instances for each ` +
  40. `mount - e.g. `const createMyApp = () => createApp(App)``
  41. )
  42. }
  43. }

(1)调用createVNode创建虚拟结点

(2)调用 render 函数来实现渲染vnode。render函数是baseCreateRenderer 函数返回调用 createAppAPI 时传入的参数之一

  1. // implementation
  2. function baseCreateRenderer(
  3. options: RendererOptions,
  4. createHydrationFns?: typeof createHydrationFunctions
  5. ): any {
  6. ....
  7. const render: RootRenderFunction = (vnode, container, isSVG) => {
  8. if (vnode == null) {
  9. if (container._vnode) {
  10. unmount(container._vnode, null, null, true)
  11. }
  12. } else {
  13. patch(container._vnode || null, vnode, container, null, null, null, isSVG)
  14. }
  15. flushPostFlushCbs()
  16. container._vnode = vnode
  17. }
  18. .....
  19. }

patch

函数定义在 packages/runtime-core/src/renderer.ts文件中

  1. const patch: PatchFn = (
  2. n1,
  3. n2,
  4. container,
  5. anchor = null,
  6. parentComponent = null,
  7. parentSuspense = null,
  8. isSVG = false,
  9. slotScopeIds = null,
  10. optimized = __DEV__ && isHmrUpdating ? false : !!n2.dynamicChildren
  11. ) => {
  12. // patching & not same type, unmount old tree
  13. if (n1 && !isSameVNodeType(n1, n2)) {
  14. anchor = getNextHostNode(n1)
  15. unmount(n1, parentComponent, parentSuspense, true)
  16. n1 = null
  17. }
  18. if (n2.patchFlag === PatchFlags.BAIL) {
  19. optimized = false
  20. n2.dynamicChildren = null
  21. }
  22. const { type, ref, shapeFlag } = n2
  23. switch (type) {
  24. case Text:
  25. processText(n1, n2, container, anchor)
  26. break
  27. case Comment:
  28. processCommentNode(n1, n2, container, anchor)
  29. break
  30. case Static:
  31. if (n1 == null) {
  32. mountStaticNode(n2, container, anchor, isSVG)
  33. } else if (__DEV__) {
  34. patchStaticNode(n1, n2, container, isSVG)
  35. }
  36. break
  37. case Fragment:
  38. processFragment(
  39. n1,
  40. n2,
  41. container,
  42. anchor,
  43. parentComponent,
  44. parentSuspense,
  45. isSVG,
  46. slotScopeIds,
  47. optimized
  48. )
  49. break
  50. default:
  51. if (shapeFlag & ShapeFlags.ELEMENT) {
  52. processElement(
  53. n1,
  54. n2,
  55. container,
  56. anchor,
  57. parentComponent,
  58. parentSuspense,
  59. isSVG,
  60. slotScopeIds,
  61. optimized
  62. )
  63. } else if (shapeFlag & ShapeFlags.COMPONENT) {
  64. processComponent(
  65. n1,
  66. n2,
  67. container,
  68. anchor,
  69. parentComponent,
  70. parentSuspense,
  71. isSVG,
  72. slotScopeIds,
  73. optimized
  74. )
  75. } else if (shapeFlag & ShapeFlags.TELEPORT) {
  76. ;(type as typeof TeleportImpl).process(
  77. n1 as TeleportVNode,
  78. n2 as TeleportVNode,
  79. container,
  80. anchor,
  81. parentComponent,
  82. parentSuspense,
  83. isSVG,
  84. slotScopeIds,
  85. optimized,
  86. internals
  87. )
  88. } else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
  89. ;(type as typeof SuspenseImpl).process(
  90. n1,
  91. n2,
  92. container,
  93. anchor,
  94. parentComponent,
  95. parentSuspense,
  96. isSVG,
  97. slotScopeIds,
  98. optimized,
  99. internals
  100. )
  101. } else if (__DEV__) {
  102. warn('Invalid VNode type:', type, `(${typeof type})`)
  103. }
  104. }
  105. // set ref
  106. if (ref != null && parentComponent) {
  107. setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2)
  108. }
  109. }
  110. const patch: PatchFn = (
  111. n1,
  112. n2,
  113. container,
  114. anchor = null,
  115. parentComponent = null,
  116. parentSuspense = null,
  117. isSVG = false,
  118. slotScopeIds = null,
  119. optimized = __DEV__ && isHmrUpdating ? false : !!n2.dynamicChildren
  120. ) => {
  121. // patching & not same type, unmount old tree
  122. if (n1 && !isSameVNodeType(n1, n2)) {
  123. anchor = getNextHostNode(n1)
  124. unmount(n1, parentComponent, parentSuspense, true)
  125. n1 = null
  126. }
  127. if (n2.patchFlag === PatchFlags.BAIL) {
  128. optimized = false
  129. n2.dynamicChildren = null
  130. }
  131. const { type, ref, shapeFlag } = n2
  132. switch (type) {
  133. case Text:
  134. processText(n1, n2, container, anchor)
  135. break
  136. case Comment:
  137. processCommentNode(n1, n2, container, anchor)
  138. break
  139. case Static:
  140. if (n1 == null) {
  141. mountStaticNode(n2, container, anchor, isSVG)
  142. } else if (__DEV__) {
  143. patchStaticNode(n1, n2, container, isSVG)
  144. }
  145. break
  146. case Fragment:
  147. processFragment(
  148. n1,
  149. n2,
  150. container,
  151. anchor,
  152. parentComponent,
  153. parentSuspense,
  154. isSVG,
  155. slotScopeIds,
  156. optimized
  157. )
  158. break
  159. default:
  160. if (shapeFlag & ShapeFlags.ELEMENT) {
  161. processElement(
  162. n1,
  163. n2,
  164. container,
  165. anchor,
  166. parentComponent,
  167. parentSuspense,
  168. isSVG,
  169. slotScopeIds,
  170. optimized
  171. )
  172. } else if (shapeFlag & ShapeFlags.COMPONENT) {
  173. processComponent(
  174. n1,
  175. n2,
  176. container,
  177. anchor,
  178. parentComponent,
  179. parentSuspense,
  180. isSVG,
  181. slotScopeIds,
  182. optimized
  183. )
  184. } else if (shapeFlag & ShapeFlags.TELEPORT) {
  185. ;(type as typeof TeleportImpl).process(
  186. n1 as TeleportVNode,
  187. n2 as TeleportVNode,
  188. container,
  189. anchor,
  190. parentComponent,
  191. parentSuspense,
  192. isSVG,
  193. slotScopeIds,
  194. optimized,
  195. internals
  196. )
  197. } else if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
  198. ;(type as typeof SuspenseImpl).process(
  199. n1,
  200. n2,
  201. container,
  202. anchor,
  203. parentComponent,
  204. parentSuspense,
  205. isSVG,
  206. slotScopeIds,
  207. optimized,
  208. internals
  209. )
  210. } else if (__DEV__) {
  211. warn('Invalid VNode type:', type, `(${typeof type})`)
  212. }
  213. }
  214. // set ref
  215. if (ref != null && parentComponent) {
  216. setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2)
  217. }
  218. }

processComponent

函数定义在packages/runtime-core/src/renderer.ts文件中

  1. const processComponent = (
  2. n1: VNode | null,
  3. n2: VNode,
  4. container: RendererElement,
  5. anchor: RendererNode | null,
  6. parentComponent: ComponentInternalInstance | null,
  7. parentSuspense: SuspenseBoundary | null,
  8. isSVG: boolean,
  9. slotScopeIds: string[] | null,
  10. optimized: boolean
  11. ) => {
  12. n2.slotScopeIds = slotScopeIds
  13. if (n1 == null) {
  14. if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
  15. ;(parentComponent!.ctx as KeepAliveContext).activate(
  16. n2,
  17. container,
  18. anchor,
  19. isSVG,
  20. optimized
  21. )
  22. } else {
  23. mountComponent(
  24. n2,
  25. container,
  26. anchor,
  27. parentComponent,
  28. parentSuspense,
  29. isSVG,
  30. optimized
  31. )
  32. }
  33. } else {
  34. updateComponent(n1, n2, optimized)
  35. }
  36. }

比较旧的虚拟结点n1和新的虚拟节点n2,如果n1为空则挂载结点,否则更新结点。此时n1为空,执行mountComponent挂载结点

mountComponent

函数定义在packages/runtime-core/src/renderer.ts文件中

  1. const mountComponent: MountComponentFn = (
  2. initialVNode,
  3. container,
  4. anchor,
  5. parentComponent,
  6. parentSuspense,
  7. isSVG,
  8. optimized
  9. ) => {
  10. // 2.x compat may pre-creaate the component instance before actually
  11. // mounting
  12. const compatMountInstance =
  13. __COMPAT__ && initialVNode.isCompatRoot && initialVNode.component
  14. const instance: ComponentInternalInstance =
  15. compatMountInstance ||
  16. (initialVNode.component = createComponentInstance(
  17. initialVNode,
  18. parentComponent,
  19. parentSuspense
  20. ))
  21. // inject renderer internals for keepAlive
  22. if (isKeepAlive(initialVNode)) {
  23. ;(instance.ctx as KeepAliveContext).renderer = internals
  24. }
  25. // resolve props and slots for setup context
  26. if (!(__COMPAT__ && compatMountInstance)) {
  27. setupComponent(instance)
  28. }
  29. // setup() is async. This component relies on async logic to be resolved
  30. // before proceeding
  31. if (__FEATURE_SUSPENSE__ && instance.asyncDep) {
  32. parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect)
  33. // Give it a placeholder if this is not hydration
  34. // TODO handle self-defined fallback
  35. if (!initialVNode.el) {
  36. const placeholder = (instance.subTree = createVNode(Comment))
  37. processCommentNode(null, placeholder, container!, anchor)
  38. }
  39. return
  40. }
  41. setupRenderEffect(
  42. instance,
  43. initialVNode,
  44. container,
  45. anchor,
  46. parentSuspense,
  47. isSVG,
  48. optimized
  49. )
  50. }

其执行流程为

(1)首先调用createComponentInstance创建组件的实例对象

(2)调用setupComponent来初始化属性及slots属性

(3)调用设置和渲染有副作用的函数setupRenderEffect,主要是执行ReactiveEffect的run方法来执行componentUpdateFn以及调度queueJob。

setupRenderEffect

函数定义在packages/runtime-core/src/renderer.ts文件中,关键的是当中定义的函数componentUpdateFn

  1. const componentUpdateFn = () => {
  2. if (!instance.isMounted) {
  3. let vnodeHook: VNodeHook | null | undefined
  4. const { el, props } = initialVNode
  5. const { bm, m, parent } = instance
  6. effect.allowRecurse = false
  7. // beforeMount hook
  8. if (bm) {
  9. invokeArrayFns(bm)
  10. }
  11. // onVnodeBeforeMount
  12. if ((vnodeHook = props && props.onVnodeBeforeMount)) {
  13. invokeVNodeHook(vnodeHook, parent, initialVNode)
  14. }
  15. if (
  16. __COMPAT__ &&
  17. isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
  18. ) {
  19. instance.emit('hook:beforeMount')
  20. }
  21. effect.allowRecurse = true
  22. if (el && hydrateNode) {
  23. // vnode has adopted host node - perform hydration instead of mount.
  24. const hydrateSubTree = () => {
  25. instance.subTree = renderComponentRoot(instance)
  26. hydrateNode!(
  27. el as Node,
  28. instance.subTree,
  29. instance,
  30. parentSuspense,
  31. null
  32. )
  33. }
  34. if (isAsyncWrapper(initialVNode)) {
  35. (initialVNode.type as ComponentOptions).__asyncLoader!().then(
  36. // note: we are moving the render call into an async callback,
  37. // which means it won't track dependencies - but it's ok because
  38. // a server-rendered async wrapper is already in resolved state
  39. // and it will never need to change.
  40. () => !instance.isUnmounted && hydrateSubTree()
  41. )
  42. } else {
  43. hydrateSubTree()
  44. }
  45. } else {
  46. const subTree = (instance.subTree = renderComponentRoot(instance))
  47. patch(
  48. null,
  49. subTree,
  50. container,
  51. anchor,
  52. instance,
  53. parentSuspense,
  54. isSVG
  55. )
  56. initialVNode.el = subTree.el
  57. }
  58. // mounted hook
  59. if (m) {
  60. queuePostRenderEffect(m, parentSuspense)
  61. }
  62. // onVnodeMounted
  63. if ((vnodeHook = props && props.onVnodeMounted)) {
  64. const scopedInitialVNode = initialVNode
  65. queuePostRenderEffect(
  66. () => invokeVNodeHook(vnodeHook!, parent, scopedInitialVNode),
  67. parentSuspense
  68. )
  69. }
  70. if (
  71. __COMPAT__ &&
  72. isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS, instance)
  73. ) {
  74. queuePostRenderEffect(
  75. () => instance.emit('hook:mounted'),
  76. parentSuspense
  77. )
  78. &a

以上就是vue3中的createApp怎么使用的详细内容,更多关于vue3中的createApp怎么使用的资料请关注九品源码其它相关文章!