vue3 地址 https://github.com/vuejs/core

首先看看vue文档什么是 Vue?



Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。

下面是一个最基本的示例:

  1. import { createApp, ref } from 'vue'
  2. createApp({
  3. setup() {
  4. return {
  5. count: ref(0)
  6. }
  7. }
  8. }).mount('#app')

学习vue 开发 都是从这个例子开始学习,在这个例子中涉及了这些api

  • 1 createApp
  • 2 mount
  • 3 ref
  • 4 setup

其中 ref 属于reactivity:反应系统 就暂时先不深究了

setup 属于vue3 新的语法糖 也先不深究了

就先看看最简单的createApp 和mount

createApp

先看看vue 仓库中的packages/vue/src/index.ts

地址 https://github.com/vuejs/core/blob/main/packages/vue/src/index.ts

  1. export { compileToFunction as compile }
  2. export * from '@vue/runtime-dom'

可以看到到处了一个编译的方法 和 @vue/runtime-dom 中的方法

根据上文

runtime-dom:针对浏览器的运行时。包括原生 DOM API、属性、属性、事件处理程序等的处理。

在runtime-dom 包中找到相关的方法

地址 https://github.com/vuejs/core/blob/main/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>
  43. function ensureRenderer() {
  44. return (
  45. renderer ||
  46. (renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions))
  47. )
  48. }

走查代码可以发现 选是创建了一个渲染器Renderer

然后调用了渲染器的方法 createApp

查看具体方法

地址 https://github.com/vuejs/core/blob/main/packages/runtime-core/src/renderer.ts

创建渲染器的方法是一个比较长的方法

里面的很多方法看名称,更多的设计对dom的操作,不过我们还是先关注createApp 干了些什么

  1. function baseCreateRenderer(
  2. options: RendererOptions,
  3. createHydrationFns?: typeof createHydrationFunctions
  4. ): any {
  5. ......
  6. return {
  7. render,
  8. hydrate,
  9. createApp: createAppAPI(render, hydrate)
  10. }
  11. }

发现createAppAPI 来自apiCreateApp 文件

地址 https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiCreateApp.ts

  1. import { createAppAPI, CreateAppFunction } from './apiCreateApp'

代码如下

  1. export function createAppAPI<HostElement>(
  2. render: RootRenderFunction<HostElement>,
  3. hydrate?: RootHydrateFunction
  4. ): CreateAppFunction<HostElement> {
  5. return function createApp(rootComponent, rootProps = null) {
  6. if (!isFunction(rootComponent)) {
  7. rootComponent = extend({}, rootComponent)
  8. }
  9. if (rootProps != null && !isObject(rootProps)) {
  10. __DEV__ && warn(`root props passed to app.mount() must be an object.`)
  11. rootProps = null
  12. }
  13. const context = createAppContext()
  14. // TODO remove in 3.4
  15. if (__DEV__) {
  16. Object.defineProperty(context.config, 'unwrapInjectedRef', {
  17. get() {
  18. return true
  19. },
  20. set() {
  21. warn(
  22. `app.config.unwrapInjectedRef has been deprecated. ` +
  23. `3.3 now always unwraps injected refs in Options API.`
  24. )
  25. }
  26. })
  27. }
  28. const installedPlugins = new WeakSet()
  29. let isMounted = false
  30. const app: App = (context.app = {
  31. _uid: uid++,
  32. _component: rootComponent as ConcreteComponent,
  33. _props: rootProps,
  34. _container: null,
  35. _context: context,
  36. _instance: null,
  37. version,
  38. get config() {
  39. return context.config
  40. },
  41. set config(v) {
  42. if (__DEV__) {
  43. warn(
  44. `app.config cannot be replaced. Modify individual options instead.`
  45. )
  46. }
  47. },
  48. use(plugin: Plugin, ...options: any[]) {
  49. if (installedPlugins.has(plugin)) {
  50. __DEV__ && warn(`Plugin has already been applied to target app.`)
  51. } else if (plugin && isFunction(plugin.install)) {
  52. installedPlugins.add(plugin)
  53. plugin.install(app, ...options)
  54. } else if (isFunction(plugin)) {
  55. installedPlugins.add(plugin)
  56. plugin(app, ...options)
  57. } else if (__DEV__) {
  58. warn(
  59. `A plugin must either be a function or an object with an "install" ` +
  60. `function.`
  61. )
  62. }
  63. return app
  64. },
  65. mixin(mixin: ComponentOptions) {
  66. if (__FEATURE_OPTIONS_API__) {
  67. if (!context.mixins.includes(mixin)) {
  68. context.mixins.push(mixin)
  69. } else if (__DEV__) {
  70. warn(
  71. 'Mixin has already been applied to target app' +
  72. (mixin.name ? `: ${mixin.name}` : '')
  73. )
  74. }
  75. } else if (__DEV__) {
  76. warn('Mixins are only available in builds supporting Options API')
  77. }
  78. return app
  79. },
  80. component(name: string, component?: Component): any {
  81. if (__DEV__) {
  82. validateComponentName(name, context.config)
  83. }
  84. if (!component) {
  85. return context.components[name]
  86. }
  87. if (__DEV__ && context.components[name]) {
  88. warn(`Component "${name}" has already been registered in target app.`)
  89. }
  90. context.components[name] = component
  91. return app
  92. },
  93. directive(name: string, directive?: Directive) {
  94. if (__DEV__) {
  95. validateDirectiveName(name)
  96. }
  97. if (!directive) {
  98. return context.directives[name] as any
  99. }
  100. if (__DEV__ && context.directives[name]) {
  101. warn(`Directive "${name}" has already been registered in target app.`)
  102. }
  103. context.directives[name] = directive
  104. return app
  105. },
  106. mount(
  107. rootContainer: HostElement,
  108. isHydrate?: boolean,
  109. isSVG?: boolean
  110. ): any {
  111. if (!isMounted) {
  112. // #5571
  113. if (__DEV__ && (rootContainer as any).__vue_app__) {
  114. warn(
  115. `There is already an app instance mounted on the host container.\n` +
  116. ` If you want to mount another app on the same host container,` +
  117. ` you need to unmount the previous app by calling \`app.unmount()\` first.`
  118. )
  119. }
  120. const vnode = createVNode(rootComponent, rootProps)
  121. // store app context on the root VNode.
  122. // this will be set on the root instance on initial mount.
  123. vnode.appContext = context
  124. // HMR root reload
  125. if (__DEV__) {
  126. context.reload = () => {
  127. render(cloneVNode(vnode), rootContainer, isSVG)
  128. }
  129. }
  130. if (isHydrate && hydrate) {
  131. hydrate(vnode as VNode<Node, Element>, rootContainer as any)
  132. } else {
  133. render(vnode, rootContainer, isSVG)
  134. }
  135. isMounted = true
  136. app._container = rootContainer
  137. // for devtools and telemetry
  138. ;(rootContainer as any).__vue_app__ = app
  139. if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
  140. app._instance = vnode.component
  141. devtoolsInitApp(app, version)
  142. }
  143. return getExposeProxy(vnode.component!) || vnode.component!.proxy
  144. } else if (__DEV__) {
  145. warn(
  146. `App has already been mounted.\n` +
  147. `If you want to remount the same app, move your app creation logic ` +
  148. `into a factory function and create fresh app instances for each ` +
  149. `mount - e.g. \`const createMyApp = () => createApp(App)\``
  150. )
  151. }
  152. },
  153. unmount() {
  154. if (isMounted) {
  155. render(null, app._container)
  156. if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
  157. app._instance = null
  158. devtoolsUnmountApp(app)
  159. }
  160. delete app._container.__vue_app__
  161. } else if (__DEV__) {
  162. warn(`Cannot unmount an app that is not mounted.`)
  163. }
  164. },
  165. provide(key, value) {
  166. if (__DEV__ && (key as string | symbol) in context.provides) {
  167. warn(
  168. `App already provides property with key "${String(key)}". ` +
  169. `It will be overwritten with the new value.`
  170. )
  171. }
  172. context.provides[key as string | symbol] = value
  173. return app
  174. },
  175. runWithContext(fn) {
  176. currentApp = app
  177. try {
  178. return fn()
  179. } finally {
  180. currentApp = null
  181. }
  182. }
  183. })
  184. if (__COMPAT__) {
  185. installAppCompatProperties(app, context, render)
  186. }
  187. return app
  188. }
  189. }

可以发现createApp 的第一个参数是rootComponent

需要传递的是一个组件,作为根组件

第二个参数rootProps是这个给这个组件传递的参数

通过走查 文件可以发现一些常用的api 也是出现在这里

例如 use、mixin、component、directive、mount、unmount、provide

我们要找的mount 也是对这里mount的调用

mount

可以看到 mount主要是参数是rootContainer 另外两个是可选参数

在通过createVNode 创建一个vnode 之后

调用getExposeProxy

返回当前刚才创建的vnode的代理

  1. export function getExposeProxy(instance: ComponentInternalInstance) {
  2. if (instance.exposed) {
  3. return (
  4. instance.exposeProxy ||
  5. (instance.exposeProxy = new Proxy(proxyRefs(markRaw(instance.exposed)), {
  6. get(target, key: string) {
  7. if (key in target) {
  8. return target[key]
  9. } else if (key in publicPropertiesMap) {
  10. return publicPropertiesMap[key](instance)
  11. }
  12. },
  13. has(target, key: string) {
  14. return key in target || key in publicPropertiesMap
  15. }
  16. }))
  17. )
  18. }
  19. }

代码中实际调用的mount

依然在createAppAPI 里面 这里的传参更友好 了可以传入Selector 方便选择dom节点

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

vue3源码学习api-createApp-amount的更多相关文章

  1. Vue3全局APi解析-源码学习

    本文章共5314字,预计阅读时间5-15分钟. 前言 不知不觉Vue-next的版本已经来到了3.1.2,最近对照着源码学习Vue3的全局Api,边学习边整理了下来,希望可以和大家一起进步. 我们以官 ...

  2. 框架源码系列十一:事务管理(Spring事务管理的特点、事务概念学习、Spring事务使用学习、Spring事务管理API学习、Spring事务源码学习)

    一.Spring事务管理的特点 Spring框架为事务管理提供一套统一的抽象,带来的好处有:1. 跨不同事务API的统一的编程模型,无论你使用的是jdbc.jta.jpa.hibernate.2. 支 ...

  3. vue3源码难学,先从petite-vue开始吧

    如今这个世道,作为一个有几年工作经验的前端,不学点框架源码都感觉要被抛弃了,react或vue要能吹吹牛吧,最好能造个轮子,听说vue3源码好学点,那么学学vue3,但是学起来还是那么费劲,感觉快放弃 ...

  4. [算法1-排序](.NET源码学习)& LINQ & Lambda

    [算法1-排序](.NET源码学习)& LINQ & Lambda 说起排序算法,在日常实际开发中我们基本不在意这些事情,有API不用不是没事找事嘛.但必要的基础还是需要了解掌握. 排 ...

  5. 【iScroll源码学习03】iScroll事件机制与滚动条的实现

    前言 想不到又到周末了,周末的时间要抓紧学习才行,前几天我们学习了iScroll几点基础知识: 1. [iScroll源码学习02]分解iScroll三个核心事件点 2. [iScroll源码学习01 ...

  6. 源码学习之ASP.NET MVC Application Using Entity Framework

    源码学习的重要性,再一次让人信服. ASP.NET MVC Application Using Entity Framework Code First 做MVC已经有段时间了,但看了一些CodePle ...

  7. 【 js 基础 】【 源码学习 】源码设计 (持续更新)

    学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析第二部分:undersc ...

  8. Redis源码学习:字符串

    Redis源码学习:字符串 1.初识SDS 1.1 SDS定义 Redis定义了一个叫做sdshdr(SDS or simple dynamic string)的数据结构.SDS不仅用于 保存字符串, ...

  9. Underscore.js 源码学习笔记(下)

    上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...

  10. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

随机推荐

  1. 缕析条分Scroll属性

    最近有项目需要使用js原生开发滑动组件,频繁要用到dom元素的各种属性,其中以各种类型的height和top属性居多,名字相近,含义也很容易搞混.因此特地总结归纳了一下常用的知识点,在文末我们来挑战实 ...

  2. 「学习笔记」FHQ-treap

    FHQ-treap,即无旋 treap,又称分裂合并 treap,支持维护序列,可持久化等特性. FHQ-treap 有两个核心操作,分裂 与 合并.通过这两个操作,在很多情况下可以比旋转 treap ...

  3. 重学JavaScript Promise API

    在这篇教程中,我们将掌握如何在JavaScript中创建并使用Promise.我们将了解Promise链式调用.错误处理以及最近添加到语言中的一些Promise静态方法. 什么是Promise? 在J ...

  4. 2023牛客暑期多校训练营7 CGILM

    比赛链接 C 题解 知识点:位运算,贪心. 我们用分段的思想考虑大小关系,若在同一段则大小不能确定,一开始为 \([1,n]\) . 我们按位从高到低考虑,某位如果 \(b_i\) 产生了 \(1\) ...

  5. Three.js中实现碰撞检测

    1. 引言 碰撞检测是三维场景中常见的需求,Three.js是常用的前端三维JavaScript库,本文就如何在Three.js中进行碰撞检测进行记述 主要使用到的方法有: 射线法Raycaster ...

  6. cockpit--一款开源的适用于单主机的Linux监控面板

    在搜索Linux监控时,偶然发现一款还不错的监控面板,该面板为red hat开发,适用于各种Linux发行版,部署也非常方便,官方文档Running Cockpit - Cockpit Project ...

  7. [信友队图灵杯中级组-D]基础循环结构练习题

    2023-5-13 题目 题目传送门 难度&重要性(1~10):6.5 题目来源 信友队图灵杯 题目算法 构造 解题思路 我们可以知道,在一开始我们得到的 \(a\) 数组是 \(1,2,3, ...

  8. QA|conftest使用了fixture但是没生效的原因|Pytest

    conftest.py中使用了fixture但是没生效,后面发现是因为autouse默认False导致,修改后代码如下 # conftest.py @pytest.fixture(scope='ses ...

  9. 如何使用Vite创建Vue3的uniapp项目

    项目结构 my-vue3-project ├─ .env //默认环境变量 ├─ .env.development //开发环境变量 ├─ .eslintrc-auto-import.json //( ...

  10. 3-MySQL基本数据类型介绍

    数据类型的介绍: 数据类型(data_type)是指系统中所允许的数据的类型.数据库中的每个列都应有适当的数据类型,用于限制或允许该列中存储的数据.例如,列中存储的为数字,则相应的数据类型应该为数值类 ...