前言
- 本笔记基于coderwhy大神新课程-vue3+ts所作,原版课程地址指路—深入Vue3+TypeScript技术栈,请大家尽量支持正版哈
- 本笔记集视频、课件、代码而成,较为详细,建议收藏关注,持续更新中
Vue3带来的变化
1.源码
源码通过monorepo的形式来管理源代码:
- pMono:单个
- pRepo:repository仓库
- 主要是将许多项目的代码存储在同一个repository中;
- 这样做的目的是多个包本身相互独立,可以有自己的功能逻辑、单元测试等,同时又在同一个仓库下方便管理;
- 而且模块划分的更加清晰,可维护性、可扩展性更强;
源码使用TypeScript来进行重写:
- 在Vue2.x的时候,Vue使用Flow来进行类型检测;
- 在Vue3.x的时候,Vue的源码全部使用TypeScript来进行重构,并且Vue本身对TypeScript支持也更好了;
2.性能
使用Proxy进行数据劫持
- 在Vue2.x的时候,Vue2是使用
Object.defineProperty来劫持数据的getter和setter方法的;这种方式一致存在一个缺陷就是当给对象添加或者删除属性时,是无法劫持和监听的,所以在Vue2.x的时候,不得不提供一些特殊的API,比如$set或$delete,事实上都是一些hack方法,也增加了开发者学习新的API的成本,而在Vue3.x开始,Vue使用Proxy来实现数据的劫持
删除了一些不必要的API:
- 移除了实例上的
$on,$off和$once;
移除了一些特性:
- 如filter、内联模板等;
编译方面的优化:
- 生成Block Tree、Slot编译优化、diff算法优化
3.新API
Options API 到 Composition API:
- 在Vue2.x的时候,我们会通过
Options API来描述组件对象;Options API包括data、props、methods、computed、生命周期等等这些选项;存在比较大的问题是多个逻辑可能是在不同的地方: 比如created中会使用某一个method来修改data的数据,代码的内聚性非常差; - Composition API可以将相关联的代码放到同一处进行处理,而不需要在多个Options之间寻找;
Hooks函数增加代码的复用性:
- 在Vue2.x的时候,我们通常通过mixins在多个组件之间共享逻辑;但是有一个很大的缺陷就是mixins也是由一大堆的Options组成的,并且多个mixins会存在命名冲突的问题;在Vue3.x中,我们可以通过Hook函数,来将一部分独立的逻辑抽取出去,并且它们还可以做到是响应式的;
Hello Vue的实现
<body>
<div id="app"></div>
<script src="https://unpkg.com/vue@next"></script>
<script>
// Vue相关的代码
const app = Vue.createApp({
template: '<h2>Hello Vue3</h2>'
});
// 将app挂载到id为app的div上
app.mount("#app");
</script>
</body>
createApp对象参数
在使用createApp的时候,我们传入了一个对象,我们解析一下传入的属性分别代表什么含义
template属性
template表示的是Vue需要帮助我们渲染的模板信息:
目前我们看到它里面有很多的HTML标签,这些标签会替换掉我们挂载到的元素(比如id为app的div)的innerHTML;模板中有一些奇怪的语法,比如{{}},比如 @click,这些都是模板特有的语法,会在后面讲到;但是这个模板的写法有点过于别扭了,并且编辑器可能没有任何提示,阻碍我们变成的效率。
方式一:使用script标签,并且标记它的类型为 x-template;
<script type="x-template" id="my-app">
<div>
<h2>{{counter}}</h2>
<button @click='increment'>+1</button>
<button @click='decrement'>-1</button>
</div>
</script>
方式二:使用任意标签(通常使用template标签,因为不会被浏览器渲染),设置id,template元素是一种用于保存客户端内容的机制,该内容在加载页面时不会被呈现,但随后可以在运行时使用JavaScript实例化;
<template id="my-app">
<div>
<h2>{{counter}}</h2>
<button @click='increment'>+1</button>
<button @click='decrement'>-1</button>
</div>
</template>
这个时候,在createApp的对象中,我们需要传入的template以#开头:如果字符串是以#开始,那么它将被用作querySelector,并且使用匹配元素的innerHTML作为模板字符串;
data属性
data属性是传入一个函数,并且该函数需要返回一个对象:
在Vue2.x的时候,也可以传入一个对象(虽然官方推荐是一个函数);
在Vue3.x的时候,必须传入一个函数,否则就会直接在浏览器中报错;
data中返回的对象会被Vue的响应式系统劫持,之后对该对象的修改或者访问都会在劫持中被处理:
所以我们在template中通过{{counter}}访问counter,可以从对象中获取到数据;我们修改counter的值时,template中的 {{counter}}也会发生改变;
具体这种响应式的原理,后面会有专门的篇幅来讲解。
methods属性
methods属性是一个对象,通常我们会在这个对象中定义很多的方法:
这些方法可以被绑定到 template 模板中;
在该方法中,我们可以使用this关键字来直接访问到data中返回的对象的属性;
其他属性
当然,这里还可以定义很多其他的属性,会在后续进行讲解:props、computed、watch、emits、setup等等,也包括很多的生命周期函数;
如何学习Vue3源码
如果想要学习Vue的源码,比如看createApp的实现过程,应该怎么办呢?
第一步:在GitHub上搜索 vue-next,下载源代码,推荐通过 git clone 的方式下载;
第二步:安装Vue源码项目相关的依赖,执行 yarn install;
第三步:对项目执行打包操作,执行yarn dev(执行前修改脚本)
第四步:通过 packages/vue/dist/vue.global.js 调试代码,packages/vue/examples下新建why文件夹,里面新建demo.html文件,内容如下,打上了debugger
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="../../dist/vue.global.js"></script>
<script>
debugger;
Vue.createApp({
template: `<h2>你好啊</h2>`
}).mount("#app");
</script>
</body>
</html>
刷新浏览器发现,现在是在vue.global.js里面调试的,是一整个代码,有没有办法跳到某个具体的源代码里面?
使用
--sourcemap(代码映射,可以把某个函数映射到具体哪个打包文件里面)
重新运行打包