Vue3源码之createApp

前言

Vue3版本源码架构与Vue2版本存在非常大的不同,从使用方式的角度来讲,对它们可以简单概括为:

  • Vue2版本是命令方式使用,通过new Vue去创建Vue实例,组件中使用选项组合代码逻辑
  • Vue3版本将命令和功能API函数化,通过createApp去创建应用实例,组件中通过组合式API和选项组合代码

这里需要区分与Vue2中的一些概念,Vue2中Vue实例实际上就是组件实例,而Vue3中createApp则是创建一个上下文,称之为应用实例。组件实例是通过其他方式来获得的,例如Vue3中mount挂载后就会返回组件实例。(Vue 3.1.1版本)

createApp执行逻辑

在具体梳理createApp之前,聊聊Vue3构建输出的文件结构,不同于Vue2构建输出的UMD规范的文件,Vue3输出的文件主体就是一个IIFE函数:

var Vue = (function(exports) {
 ...
 exports.createApp = createApp;
 ...
})({});

实际上就是输出一个名为Vue的对象,该对象提供createApp函数等。

Vue.createApp的执行实际上就是调用一个createApp函数,该函数的逻辑比较清晰,这里直接贴出代码:

const createApp = ((...args) => {
	const app = ensureRenderer().createApp(...args);
 	{
   		injectNativeTagCheck(app);
   		injectCompilerOptionsCheck(app);
 	}
 	const { mount } = app;
 	app.mount = (containerOrSelector) => {
 		// 相关处理
 	}
 	return app;
});

从上面逻辑可知,createApp函数的功能是返回一个app对象,并且会重写mount函数。而创建app对象又会调用其他函数来完成,相关逻辑在后面会详细梳理。

创建Renderer对象

在Vue3中存在Renderer对象的概念,实际上就是渲染器,顾名思义渲染器就是负责节点渲染。

渲染器是延迟创建的,只有在调用ensureRenderer或ensureHydrationRenderer函数才会创建,而且是单例模式。当调用Vue.createApp就会调用ensureRenderer函数,其逻辑具体如下:

function ensureRenderer() {
	return renderer ||
		(renderer = createRenderer(rendererOptions));
}

function createRenderer(options) {
  return baseCreateRenderer(options);
}

其中rendererOptions是渲染器相关的参数,具体内容是分为两类:

  • patchProp相关:实际上是组件相关属性、事件等更新相关操作,即patch阶段的处理class、style、on事件绑定等
  • node操作相关的:节点对象的操作,例如插入、移除等

实际上Vue3允许自定义渲染器,对外暴露了createRenderer,在官网文档中有对其的定义描述:

createRenderer 函数接受两个泛型参数: HostNode 和 HostElement,对应于宿主环境中的 Node 和 Element 类型。例如,对于 runtime-dom,HostNode 将是 DOM Node 接口,HostElement 将是 DOM Element 接口。

createRenderer函数背后是调用baseCreateRenderer。

baseCreateRenderer函数

该函数的逻辑简单来说就是返回一个对象,该对象被称为渲染器对象,该对象就3个方法:

function baseCreateRenderer(options, createHydrationFns) {
	// 相关逻辑,其中包含相关patch阶段相关处理的函数定义
	return {
		render,
        hydrate,
        createApp: createAppAPI(render, hydrate)
    };
}

结合Vue2版本的逻辑可以知道,渲染器一部分承担了patch阶段的diff算法的功能和VNode到真实DOM的处理操作。这里先暂时不管这部分的功能,主要看createAppAPI的具体处理逻辑。createAppAPI就是返回一个createApp函数而已:

function createAppAPI(render, hydrate) {
	return function createApp(rootComponent, rootProps = null) {
		// 相关逻辑
	}
}
渲染器的createApp处理

Vue.createApp最后就是调用渲染器对象Renderer的createApp函数,其逻辑代码具体如下:

function createApp(rootComponent, rootProps = null) {
   // rootProps必须是对象或null
   if (rootProps != null && !isObject(rootProps)) {
   	warn(`root props passed to app.mount() must be an object.`);
    rootProps = null;
   }
   // 创建应用上下文
   const context = createAppContext();
   const installedPlugins = new Set();
   let isMounted = false;
   // 生成具体对象,该对象提供具体的应用API和相关属性
   const app = (context.app = {})
   return app;
}

实际上主要逻辑关注点就两处:

  • createAppContext函数调用创建应用上下文对象
  • 应用对象app的具体内容
调用createAppContext函数创建应用上下文对象

createAppContext函数的具体逻辑如下:

function createAppContext() {
	return {
		// 应用实例
     	app: null,
     	// 应用配置项
        config: {
        	isNativeTag: NO,
            performance: false,
            globalProperties: {},
            optionMergeStrategies: {},
            errorHandler: undefined,
            warnHandler: undefined,
            compilerOptions: {}
         },
         // 混入相关
         mixins: [],
         // 全局组件
         components: {},
         // 指令
         directives: {},
         provides: Object.create(null),
         optionsCache: new WeakMap(),
         propsCache: new WeakMap(),
         emitsCache: new WeakMap()
    };
}
应用实例对象app属性

Vue.createApp函数功能就是返回应用实例对象的,该对象处理提供应用API外,还存在一些内部属性:

 const app = (context.app = {
 	_uid: uid$1++,
    _component: rootComponent,
    _props: rootProps,
    _container: null,
    _context: context,
    _instance: null,
    version,
    get config() { return context.config; },
   	set config(v) {
    	{
          warn(`app.config cannot be replaced. Modify individual options instead.`);
       	}
     },
     // 应用API
     use(plugin, ...options) {},
     mixin(mixin) {},
     component(name, component) {},
     directive(name, directive) {},
     mount(rootContainer, isHydrate, isSVG) {},
     unmount() {},
     provide(key, value) {}
});

相关应用API的说明可以具体看Vue3官方文档,而相关内部属性实际上也比较清晰,例如:

  • _context:表示应用上下文实例
  • _component:根组件
  • _container:挂载点容器Node
  • _instance:不出意外应该就是根组件实例对象了
config的额外处理

当Vue.createApp生成应用实例对象后,会针对上下文中config配置对象做额外的处理,具体代码如下:

injectNativeTagCheck(app);
injectCompilerOptionsCheck(app);

函数的定义名称是非常清晰的,上面2个函数的具体逻辑实际上就是向config对象中增加:

  • isNativeTag的检查函数:判断是否是HTML标签或SVG标签
  • isCustomElement 和 compilerOptions属性,具体是用来做什么这里暂不关心

总结

Vue.createApp是用来创建应用实例的,该应用实例提供相关的应用API和维护相关的状态。在应用实例创建过程中,会创建一个渲染器对象Renderer,针对渲染器对象有如下几点说明:

  • 渲染器对象的创建是惰性的,并且是单例模式
  • Vue3对外暴露了createRenderer API,允许开发者自定义渲染器
  • 渲染器承担Vue3视图渲染相关的功能,其中包含patch阶段的相关处理(diff算法的实现 和 DOM替换等)、应用实例的创建

对比Vue2根组件的处理逻辑(new Vue实际上就是组件实例生成的过程)中data、props、computed等相关处理逻辑,Vue3中相关处理延后到mount挂载阶段。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【资源说明】 毕业设计基于Vue+JavaScript的生鲜后台管理系统源码.zip 1、该资源内项目代码都是经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果有一点儿基础,亦可在此代码基础上进行修改,以实现其他功能。 【部署教程】 项目创建: 1、vue create vue-project 2、vue add element npm install babel-plugin-component -D 在根目录下的 babel.config.js 中添加 ``` "plugins": [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] ``` 3、npm i axios -S / yarn add axioa -S 4、npm i querystring -S / yarn add querystring -S 5、npm i normalize.css -S / yarm add normalize.css -S 6、npm i echarts -S / yarn add echarts -S 项目初始化 main.js 中引入 normalize.css 去除默认属性 assets/css/bsaa.css 引入 icon 配置路由: 创建 views 文件夹创建 login 登录页面 在 router/index.js 中引入 在 router[]里面配置 { path: "/", component: Layout, }, { path: "/login", name: "login", component: Login, }, 在app.vue用router-view标签引入 后台项目: nodejs+myaql+express 启动 xampp 软件-- 创建数据库 创建数据库:导入 sql 文件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值