Vue 3
这里总结了关于 vue 新版本中新增替代的一些知识点
Vue 3 新特性
组合式 API(composition API)
what is composition API ?
组合式 API (Composition API) 是一系列 API 的集合,使我们可以使用函数而不是声明选项的方式书写 Vue 组件。
- 响应式 API:例如 ref() 和 reactive(),使我们可以直接创建响应式状态、计算属性和侦听器。
- 生命周期钩子:例如 onMounted() 和 onUnmounted(),使我们可以在组件各个生命周期阶段添加逻辑。
- 依赖注入:例如 provide() 和 inject(),使我们可以在使用响应式 API 时,利用 Vue 的依赖注入系统。
why?
- options API 的组件,比如在 A 组件中定义了 B/C 组件的 data,methods,生命周期方法,computed,各个逻辑分散在组件的不同区域,代码难以复用,使用 composition API 解决了这个问题,可以做到高内聚、低耦合,代码可复用性和可维护性更好
- vue2 逻辑复用使用的是 mixins,
- 当一个组件引用多个 mixin 时, 想知道 query 来源于哪个 mixin,需要在每个引用的 mixin 中寻找一遍方法,即数据来源不清晰;
- 但是也并不是特别好维护;
- 且多个 mixin 中定义的属性和方法会存在命名冲突问题;
- composition API 解决了上面的问题
- 更好的类型推断,对 Typescript 更友好
- composition API 看不到 this 的使用,解决了 this 指向不明的问题
生命周期变更
Vue 2中的生命周期钩子 | Vue 3选项式API的生命周期选项 | Vue 3 组合API中生命周期钩子 | 描述 |
---|---|---|---|
beforeCreate | beforeCreate | setup() | 创建前,此时data 和 methods 的数据都还没有初始化 |
created | created | setup() | 创建后,data 中有值,尚未挂载,可以进行一些Ajax 请求 |
beforeMount | beforeMount | onBeforeMount | 挂载前,会找到虚拟DOM ,编译成Render |
mounted | mounted | onMounted | 挂载后,DOM 已创建,可用于获取访问数据和DOM 元素 |
beforeUpdate | beforeUpdate | onBeforeUpdate | 更新前,可用于获取更新前各种状态 |
updated | updated | onUpdated | 更新后,所有状态已是最新 |
beforeDestroy | beforeUnmount | onBeforeUnmount | 销毁前,可用于一些定时器或订阅的取消 |
destroyed | unmounted | onUnmounted | 销毁后,可用于一些定时器或订阅的取消 |
activated | activated | onActivated | keep-alive 缓存的组件激活时 |
deactivated | deactivated | onDeactivated | keep-alive 缓存的组件停用时 |
errorCaptured | errorCaptured | onErrorCaptured | 捕获一个来自子孙组件的错误时调用 |
— | renderTracked | onRenderTracked | 调试钩子,响应式依赖被收集时调用 |
— | renderTriggered | onRenderTriggered | 调试钩子,响应式依赖被触发时调用 |
— | serverPrefetch | onServerPrefetch | 组件实例在服务器上被渲染前调用 |
setup
函数
setup
语法糖(script setup
)
vue3 性能提升
Vue 3 除了响应式系统升级之外,还做了哪些性能提升?
编译优化
-
diff 算法优化
- vue3 相比 vue2 增加了静态标记,静态标记的作用是会标志为一个 flag,下次发生变化的时候直接找该处进行比较;
- 已经标记为静态节点的元素不会参与 diff 比较
-
静态提升、树结构打平
- vue3 对不参与更新的元素做静态提升,只会被创建一次,在渲染时直接复用。
- 作用:减少重复节点的创建,节省内存开销
-
事件监听缓存
-
SSR 优化
源码体积优化
-
源码优化
- vue2 的源码是托管 src 目录 下 根据功能才分了 compiler core platforms server sfc shared
- vue3 的源码 整体通过 monorepo 维护 不同的模块拆分到 packages 目录下 拆分到颗粒度更细 指责划分更明确 依赖关系也更明显 便于 开发人员 阅读和维护 提高了可维护性
- vue2 是用的 flow 进行 类型检查的 flow 在复杂场景下的支持不好
- vue3 是用的 typscript 重构的
-
Vue 3 中移除了一些不常用的 API
-
再就是 tree shaking,
- 任何一个函数,比如 ref、reactive,只有在用 到的时候才进行打包,无用模块都被摇树优化,减少了打包代码体积
Fragment
Vue2 在组件中只有一个根节点。Vue3 在组件可以拥有多个根节点。 Fragment 组件支持多个根节点。 作用:减少标签层级,减少内存占用
Teleport
Teleport 类似于 React 中的 Portal, 可以将组件挂载在任何 DOM 节点上
<button @click="openToast">打开toast</button>
<!--挂载在id为dialog的节点上-->
<teleport to="#dialog">
<div v-if="visible" class="toast-container">
<div class="toast-msg">我是一个toast</div>
</div>
</teleport>
Teleport 的原理就是利用 document.querySelector 实现的,所以 to 中的 dom 元素必须是存在的。
Suspense
<Suspense>
是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。
这个和 React 中的 <Suspense>
是类似的, 不同的是在内部使用上有一些区别:
-
react 在使用 lazy 懒加载组件的时候是需要用到
<Suspense>
-
vue 中 在使用
defineAsyncComponent
异步组件时候需要搭配<Suspense>
, 还有就是 带有异步setup()
钩子的组件。这也包含了使用<script setup>
时有顶层await
表达式的组件。export default {
async setup() {
const res = await fetch(...)
const posts = await res.json()
return {
posts
}
}
}
<script setup>
const res = await fetch(...)
const posts = await res.json()
</script>
<template>
{{ posts }}
</template> -
在 vue3 中使用
<Suspense>
时,组件有两个插槽:#default 和 #fallback。两个插槽都只允许一个直接子节点。在可能的时候都将显示默认槽中的节点。否则将显示后备槽中的节点。<Suspense>
<!-- 具有深层异步依赖的组件 -->
<Dashboard />
<!-- 在 #fallback 插槽中显示 “正在加载中” -->
<template #fallback>
Loading...
</template>
</Suspense>
异步组件
上面提到了 异步组件,这里就详细描述下,异步组件的出现就是在需要的时候在加载组件
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() => {
return new Promise((resolve, reject) => {
// ...从服务器获取组件
resolve(/* 获取到的组件 */)
})
})
// es 模块导入
<script setup>
import { defineAsyncComponent } from 'vue'
const AdminPage = defineAsyncComponent(() =>
import('./components/AdminPageComponent.vue')
)
</script>
<template>
<AdminPage />
</template>
// 还可以设置加载中组件,和错误组件,延迟,以及加载时间限制
const AsyncComp = defineAsyncComponent({
// 加载函数
loader: () => import('./Foo.vue'),
// 加载异步组件时使用的组件
loadingComponent: LoadingComponent,
// 展示加载组件前的延迟时间,默认为 200ms
delay: 200,
// 加载失败后展示的组件
errorComponent: ErrorComponent,
// 如果提供了一个 timeout 时间限制,并超时了
// 也会显示这里配置的报错组件,默认值是:Infinity
timeout: 3000
})
虚拟 DOM
diff 算法
vue 3 中的 diff 算法升级为了最长递增子序列
- 相同前置和后置的元素预处理
- 剩下就是最长递增子序列
依赖收集与响应式原理
响应式
Vue2 的响应式是通过 Object.defineProperty 实现的,有以下几个问题:
- 不能深层监听对象的变化
- 不能获取数组下标和 length
vue3 使用 ES6 的 proxy 实现响应式,proxy 是支持数组的,因此解决了无法获取数组下标和 length 的问题;对于深层监听也不需要使用递归解决,当 get 判断值为对象时,将对象响应式处理即可.
- Vue3 中使用了 ES6 的 ProxyAPI 对数据代理,监测的是整个对象,而不再是某个属性。
- 消除了 Vue 2 当中基于 Object.defineProperty 的实现所存在的很多限制
- Vue3 可以监测到对象属性的添加和删除,可以监听数组的变化;
- Vue3 支持 Map、Set、WeakMap 和 WeakSet。