vue3源码学习api-createApp-amount
vue3 地址 https://github.com/vuejs/core
首先看看vue文档什么是 Vue?
Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。
下面是一个最基本的示例:
import { createApp, ref } from 'vue'createApp({setup() {return {count: ref(0)}}}).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
export { compileToFunction as compile }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
export const createApp = ((...args) => {const app = ensureRenderer().createApp(...args)if (__DEV__) {injectNativeTagCheck(app)injectCompilerOptionsCheck(app)}const { mount } = appapp.mount = (containerOrSelector: Element | ShadowRoot | string): any => {const container = normalizeContainer(containerOrSelector)if (!container) returnconst component = app._componentif (!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 checkif (__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 mountingcontainer.innerHTML = ''const proxy = mount(container, false, container instanceof SVGElement)if (container instanceof Element) {container.removeAttribute('v-cloak')container.setAttribute('data-v-app', '')}return proxy}return app}) as CreateAppFunction<Element>function ensureRenderer() {return (renderer ||(renderer = createRenderer<Node, Element | ShadowRoot>(rendererOptions)))}
走查代码可以发现 选是创建了一个渲染器Renderer
然后调用了渲染器的方法 createApp
查看具体方法
地址 https://github.com/vuejs/core/blob/main/packages/runtime-core/src/renderer.ts
创建渲染器的方法是一个比较长的方法
里面的很多方法看名称,更多的设计对dom的操作,不过我们还是先关注createApp 干了些什么
function baseCreateRenderer(options: RendererOptions,createHydrationFns?: typeof createHydrationFunctions): any {......return {render,hydrate,createApp: createAppAPI(render, hydrate)}}
发现createAppAPI 来自apiCreateApp 文件
地址 https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiCreateApp.ts
import { createAppAPI, CreateAppFunction } from './apiCreateApp'
代码如下
export function createAppAPI<HostElement>(render: RootRenderFunction<HostElement>,hydrate?: RootHydrateFunction): CreateAppFunction<HostElement> {return function createApp(rootComponent, rootProps = null) {if (!isFunction(rootComponent)) {rootComponent = extend({}, rootComponent)}if (rootProps != null && !isObject(rootProps)) {__DEV__ && warn(`root props passed to app.mount() must be an object.`)rootProps = null}const context = createAppContext()// TODO remove in 3.4if (__DEV__) {Object.defineProperty(context.config, 'unwrapInjectedRef', {get() {return true},set() {warn(`app.config.unwrapInjectedRef has been deprecated. ` +`3.3 now always unwraps injected refs in Options API.`)}})}const installedPlugins = new WeakSet()let isMounted = falseconst app: App = (context.app = {_uid: uid++,_component: rootComponent as ConcreteComponent,_props: rootProps,_container: null,_context: context,_instance: null,version,get config() {return context.config},set config(v) {if (__DEV__) {warn(`app.config cannot be replaced. Modify individual options instead.`)}},use(plugin: Plugin, ...options: any[]) {if (installedPlugins.has(plugin)) {__DEV__ && warn(`Plugin has already been applied to target app.`)} else if (plugin && isFunction(plugin.install)) {installedPlugins.add(plugin)plugin.install(app, ...options)} else if (isFunction(plugin)) {installedPlugins.add(plugin)plugin(app, ...options)} else if (__DEV__) {warn(`A plugin must either be a function or an object with an "install" ` +`function.`)}return app},mixin(mixin: ComponentOptions) {if (__FEATURE_OPTIONS_API__) {if (!context.mixins.includes(mixin)) {context.mixins.push(mixin)} else if (__DEV__) {warn('Mixin has already been applied to target app' +(mixin.name ? `: ${mixin.name}` : ''))}} else if (__DEV__) {warn('Mixins are only available in builds supporting Options API')}return app},component(name: string, component?: Component): any {if (__DEV__) {validateComponentName(name, context.config)}if (!component) {return context.components[name]}if (__DEV__ && context.components[name]) {warn(`Component "${name}" has already been registered in target app.`)}context.components[name] = componentreturn app},directive(name: string, directive?: Directive) {if (__DEV__) {validateDirectiveName(name)}if (!directive) {return context.directives[name] as any}if (__DEV__ && context.directives[name]) {warn(`Directive "${name}" has already been registered in target app.`)}context.directives[name] = directivereturn app},mount(rootContainer: HostElement,isHydrate?: boolean,isSVG?: boolean): any {if (!isMounted) {// #5571if (__DEV__ && (rootContainer as any).__vue_app__) {warn(`There is already an app instance mounted on the host container.\n` +` If you want to mount another app on the same host container,` +` you need to unmount the previous app by calling \`app.unmount()\` first.`)}const vnode = createVNode(rootComponent, rootProps)// store app context on the root VNode.// this will be set on the root instance on initial mount.vnode.appContext = context// HMR root reloadif (__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 = trueapp._container = rootContainer// for devtools and telemetry;(rootContainer as any).__vue_app__ = appif (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {app._instance = vnode.componentdevtoolsInitApp(app, version)}return getExposeProxy(vnode.component!) || 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)\``)}},unmount() {if (isMounted) {render(null, app._container)if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {app._instance = nulldevtoolsUnmountApp(app)}delete app._container.__vue_app__} else if (__DEV__) {warn(`Cannot unmount an app that is not mounted.`)}},provide(key, value) {if (__DEV__ && (key as string | symbol) in context.provides) {warn(`App already provides property with key "${String(key)}". ` +`It will be overwritten with the new value.`)}context.provides[key as string | symbol] = valuereturn app},runWithContext(fn) {currentApp = apptry {return fn()} finally {currentApp = null}}})if (__COMPAT__) {installAppCompatProperties(app, context, render)}return app}}
可以发现createApp 的第一个参数是rootComponent
需要传递的是一个组件,作为根组件
第二个参数rootProps是这个给这个组件传递的参数
通过走查 文件可以发现一些常用的api 也是出现在这里
例如 use、mixin、component、directive、mount、unmount、provide
我们要找的mount 也是对这里mount的调用
mount
可以看到 mount主要是参数是rootContainer 另外两个是可选参数
在通过createVNode 创建一个vnode 之后
调用getExposeProxy
返回当前刚才创建的vnode的代理
export function getExposeProxy(instance: ComponentInternalInstance) {if (instance.exposed) {return (instance.exposeProxy ||(instance.exposeProxy = new Proxy(proxyRefs(markRaw(instance.exposed)), {get(target, key: string) {if (key in target) {return target[key]} else if (key in publicPropertiesMap) {return publicPropertiesMap[key](instance)}},has(target, key: string) {return key in target || key in publicPropertiesMap}})))}}
代码中实际调用的mount
依然在createAppAPI 里面 这里的传参更友好 了可以传入Selector 方便选择dom节点
app.mount = (containerOrSelector: Element | ShadowRoot | string): any => {const container = normalizeContainer(containerOrSelector)if (!container) returnconst component = app._componentif (!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 checkif (__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 mountingcontainer.innerHTML = ''const proxy = mount(container, false, container instanceof SVGElement)if (container instanceof Element) {container.removeAttribute('v-cloak')container.setAttribute('data-v-app', '')}return proxy}
vue3源码学习api-createApp-amount的更多相关文章
- Vue3全局APi解析-源码学习
本文章共5314字,预计阅读时间5-15分钟. 前言 不知不觉Vue-next的版本已经来到了3.1.2,最近对照着源码学习Vue3的全局Api,边学习边整理了下来,希望可以和大家一起进步. 我们以官 ...
- 框架源码系列十一:事务管理(Spring事务管理的特点、事务概念学习、Spring事务使用学习、Spring事务管理API学习、Spring事务源码学习)
一.Spring事务管理的特点 Spring框架为事务管理提供一套统一的抽象,带来的好处有:1. 跨不同事务API的统一的编程模型,无论你使用的是jdbc.jta.jpa.hibernate.2. 支 ...
- vue3源码难学,先从petite-vue开始吧
如今这个世道,作为一个有几年工作经验的前端,不学点框架源码都感觉要被抛弃了,react或vue要能吹吹牛吧,最好能造个轮子,听说vue3源码好学点,那么学学vue3,但是学起来还是那么费劲,感觉快放弃 ...
- [算法1-排序](.NET源码学习)& LINQ & Lambda
[算法1-排序](.NET源码学习)& LINQ & Lambda 说起排序算法,在日常实际开发中我们基本不在意这些事情,有API不用不是没事找事嘛.但必要的基础还是需要了解掌握. 排 ...
- 【iScroll源码学习03】iScroll事件机制与滚动条的实现
前言 想不到又到周末了,周末的时间要抓紧学习才行,前几天我们学习了iScroll几点基础知识: 1. [iScroll源码学习02]分解iScroll三个核心事件点 2. [iScroll源码学习01 ...
- 源码学习之ASP.NET MVC Application Using Entity Framework
源码学习的重要性,再一次让人信服. ASP.NET MVC Application Using Entity Framework Code First 做MVC已经有段时间了,但看了一些CodePle ...
- 【 js 基础 】【 源码学习 】源码设计 (持续更新)
学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析第二部分:undersc ...
- Redis源码学习:字符串
Redis源码学习:字符串 1.初识SDS 1.1 SDS定义 Redis定义了一个叫做sdshdr(SDS or simple dynamic string)的数据结构.SDS不仅用于 保存字符串, ...
- Underscore.js 源码学习笔记(下)
上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...
- 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)
一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...
随机推荐
- 缕析条分Scroll属性
最近有项目需要使用js原生开发滑动组件,频繁要用到dom元素的各种属性,其中以各种类型的height和top属性居多,名字相近,含义也很容易搞混.因此特地总结归纳了一下常用的知识点,在文末我们来挑战实 ...
- 「学习笔记」FHQ-treap
FHQ-treap,即无旋 treap,又称分裂合并 treap,支持维护序列,可持久化等特性. FHQ-treap 有两个核心操作,分裂 与 合并.通过这两个操作,在很多情况下可以比旋转 treap ...
- 重学JavaScript Promise API
在这篇教程中,我们将掌握如何在JavaScript中创建并使用Promise.我们将了解Promise链式调用.错误处理以及最近添加到语言中的一些Promise静态方法. 什么是Promise? 在J ...
- 2023牛客暑期多校训练营7 CGILM
比赛链接 C 题解 知识点:位运算,贪心. 我们用分段的思想考虑大小关系,若在同一段则大小不能确定,一开始为 \([1,n]\) . 我们按位从高到低考虑,某位如果 \(b_i\) 产生了 \(1\) ...
- Three.js中实现碰撞检测
1. 引言 碰撞检测是三维场景中常见的需求,Three.js是常用的前端三维JavaScript库,本文就如何在Three.js中进行碰撞检测进行记述 主要使用到的方法有: 射线法Raycaster ...
- cockpit--一款开源的适用于单主机的Linux监控面板
在搜索Linux监控时,偶然发现一款还不错的监控面板,该面板为red hat开发,适用于各种Linux发行版,部署也非常方便,官方文档Running Cockpit - Cockpit Project ...
- [信友队图灵杯中级组-D]基础循环结构练习题
2023-5-13 题目 题目传送门 难度&重要性(1~10):6.5 题目来源 信友队图灵杯 题目算法 构造 解题思路 我们可以知道,在一开始我们得到的 \(a\) 数组是 \(1,2,3, ...
- QA|conftest使用了fixture但是没生效的原因|Pytest
conftest.py中使用了fixture但是没生效,后面发现是因为autouse默认False导致,修改后代码如下 # conftest.py @pytest.fixture(scope='ses ...
- 如何使用Vite创建Vue3的uniapp项目
项目结构 my-vue3-project ├─ .env //默认环境变量 ├─ .env.development //开发环境变量 ├─ .eslintrc-auto-import.json //( ...
- 3-MySQL基本数据类型介绍
数据类型的介绍: 数据类型(data_type)是指系统中所允许的数据的类型.数据库中的每个列都应有适当的数据类型,用于限制或允许该列中存储的数据.例如,列中存储的为数字,则相应的数据类型应该为数值类 ...