# Vue 3.0 重要变更
Vue 3.0 相对与之前的版本,有 6 个方面的重要变更:
- Performance (性能)
- Tree-shaking support (支持 Tree-shaking)
- Composition API
- Fragment, Teleport, Suspense
- Better TypeScript support (更好的 TypeScript 支持度)
- Custom Renderer API (自定义的 Renderer API)
# Performance
性能上,主要有以下这五个方面:
- Rewritten virtual dom implementation (重写了虚拟 DOM)
- Compiler-informed fast paths (优化编译)
- More efficient component initialization (更高效的组件初始化)
- 1.3-2x better update performance (1.3~2 倍的更新性能)
- 2-3x faster SSR (2~3 倍的 SSR 速度)
性能上,主要是优化了虚拟 DOM,所以也就有了更加优化的编译,同时实现了更加高效的组件初始化。
# Tree-shaking support
- Most optional features (e.g. v-model,
<transition>
)are now tree-shakable (大多数可选功能(如 v-model、<transition>
)现在都是支持 Tree-shaking 的。) - Bare-bone HelloWorld size: 13.5kb. 11.75kb with only Composition API support
- All runtime features included: 22.5kb. More features but still lighter than Vue 2
在大部分情况下,我们并不需要 vue 中的所有功能,但是在之前的 vue 版本中,我们没有一个合适的办法用来除去不需要的功能,而 Vue3 中,为了满足体积更小的需求,支持 Tree-shaking,也就意味着我们可以按需求引用的内置的指令和方法。
# Composition API
- Usable alongside existing Options API (可与现有选项 API 一起使用)
- Flexible logic composition and reuse (灵活的逻辑组成和重用)
- Reactivity module can be used as a standalone library (Reactivity 模块可以作为独立的库使用)
Composition API 主要是提高了代码逻辑的可复用性,并且将 Reactivity 模块独立出来,这也使得 vue 3 变得更加灵活地与其他框架组合使用。
# Fragment, Teleport, Suspense
- Fragment
- No longer limited to a single root node in templates (
<template>
中不再局限于单一的根节点) - Manual render functions can simply return Arrays (render 函数可以返回数组)
- “Just works”
- No longer limited to a single root node in templates (
- Teleport
- Previously known as
<Portal>
(原名为<Portal>
) - More details to be shared by @Linusborg
- Previously known as
- Suspense
- Wait on nested async dependencies in a nested tree
- Works with async
setup()
(与 async 函数setup()
配合使用) - Works with Async Components (与 Async 组件配合使用)
# Better TypeScript support
- Codebase written in TS w/ auto-generated type definitions
- API is the same in JS and TS
- In fact, code will also be largely the same
- TSX support
- Class component is still supported (vue-class-component@next is currently in alpha)
vue3.0 对 TS 的支持度更高了,同时也支持 TSX 的使用;API 在 JS 与 TS 中的使用相同;类组件仍然可用,但是需要我们引入 vue-class-component@next,该模块目前还处于 alpha 测试阶段。
# 使用方式
三种使用方式:
<script>
标签引入、脚手架工具创建、从仓库克隆
# 通过标签引入
标签引入有两种方式:
- 直接下载用
<script>
标签引入; - 通过CDN引用;
<!--vue版本为3.0.0-beta.14 -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.0.0-beta.14/dist/vue.global.js"></script>
2
# 脚手架工具创建
可以使用脚手架工具 vue-cli 来初始化项目
# 安装脚手架工具
npm install -g @vue/cli
# 查看脚手架安装是否成功
vue -V
# 创建项目,之后进行命令行交互
vue create vue-next-test
2
3
4
5
6
# 改动缘由
Vue团队为什么重新设计了
APP
的引导以及全局API
?
这是因为 Vue 2.x 版本中的一些全局 API 和配置会永久地改变全局状态,而这些改变会导致如下问题(参考Global API change RFC):
- 全局配置很容易在测试过程中意外污染其他测试用例。用户需要谨慎地存储原始的全局配置,并在每次测试后恢复(例如重置
Vue.config.errorHandler
)。但是其中一些 API(如Vue.use
、Vue.mixin
)没有办法恢复其效果,这使得涉及插件的测试特别棘手。 - 这使同一页面上的多个有着不同全局配置的 "app" 之间很难共享同一副本的 Vue,如下代码:
# 基础API
- Vue 3.0 使用了
createApp()
代替了new Vue({})
; - Vue 3.0 使用
setup()
代替了data()
以及computed()
; - Vue 3.0 使用了
ref()
方法;
# createApp()
方法
调用 createApp 会返回一个新的 app 实例,该实例不会被应用到其他实例的任何全局配置污染。
从技术上来说,Vue 2 并没有 "app" 的概念,Vue 2 中所定义的 app 只是通过new Vue()
创建的根 Vue 实例,每个从同一个 Vue 构造函数创建的根实例都共享同一个全局配置,但当我们添加插件、mixins、全局配置等时,它们都会永久使全局状态突变,也就是上面提到的第二个问题。
针对此问题,在 Vue 3.0 中,引入了新的全局方法:createApp()
调用这个方法,传递 Vue 实例定义对象,并将返回对象分配给一个变量 app。调用 createApp 会返回一个 app 实例, 每个 app 实例都会提供了一个 app context(上下文),由 app 实例挂载的整个组件树共享同一个 app context,这个 app context(上下文) 在 Vue 2.x 中提供了 "全局" 的配置。在新的 API 下,调用 createApp 会返回一个新的 app 实例,该实例不会被应用到其他实例的任何全局配置污染。
挂载
就像在Vue 2
中的$mount
实例方法一样,我们将调用app
上的 mount
方法,并通过传递一个CSS
选择器来表示挂载元素。
createApp(App).mount('#app');
# ref()
方法
ref 函数传入一个值作为参数,返回一个基于该值的响应式 Ref
对象,这个对象只包含一个 .value
属性,该对象中的值一旦被改变和访问,都会被跟踪到,通过修改 number.value
的值,可以触发模板的重新渲染,显示最新的值。
想要判断一个某个值是否为 ref()
创建出来的对象,我们可以使用 isRsf()
函数。
const { createApp, ref, isRef } = Vue;
...
const n = isRef(number) ? number.value : number
...
2
3
4
# reactive()
方法
reactive()
函数可以创建响应式对象,它主要是处理你的对象让它经过 Proxy 的加工变为一个响应式的对象。
可以使用 toRefs()
函数来将 reactive()
创建出来的响应式对象,转为普通对象,但是这个对象上的属性节点都是以 ref()
类型的像是数据。
与 toRefs()
相似,还可以使用 toRef()
函数,它们之间的区别是 toRef()
可以将 reactive()
创建出来的响应式对象的其中一个属性转换为 ref()
类型。
# ref()
和 reactive()
区别
ref()
只为某一个数据提供响应式能力,而 reactive()
是为整个对象赋予响应式能力。
reactive()
包装的对象会有一个较为麻烦的点:在 return 的时候必须把整个 reactive()
对象返回出去,同时在引用的时候也必须对整个对象进行引用而无法解构,否则这个对象内容的响应式能力将会丢失。所以官方提供了 toRefs()
函数来为我们减少麻烦。只要使用 toRefs()
把 reactive()
对象包装一下,就能够通过解构单独使用它里面的内容了,而此时的内容也依然维持着响应式的特性。
# setup()
方法
Vue 3.0 的标志功能就是 Composition API
,其中 setup()
是一个新的组件选项,为我们使用 Vue3 的 Composition API
新特性提供了统一的入口。
创建组件实例时,setup()
在初始 props
解析后立即调用,setup()
代替了 Vue 2.x 的生命周期函数 beforeCreate()
与 created()
。
创建组件实例时,setup() 在初始 props 解析后立即调用;在生命周期方面,它在 beforeCreate() 挂载之后,created()之前被执行调用。
在 setup() 里的方法不能通过 this 来访问实例上的数据,而是通过直接读取 data 来访问。
setup()
返回一个对象,对象中的属性将直接暴露给模板渲染的上下文。而在 Vue2.x 中,定义的属性都会被 Vue 内部无条件暴露给模板渲染上下文。
另外 setup 方法不仅可以代替 data 和计算属性 computed,还可以代替 method 方法。
setup()
方法接受两个参数:
props
setup() 函数接收的第一个参数是 props,等同于 vue2 的 props,
注意:解构参数会使参数失去响应性。
context
第二个参数是上下文对象,他暴露了一个有选择的属性列表。
# computed()
方法
computed()
用来创建计算属性,computed()
函数的返回值是一个 ref
的实例,主要注意使用 computed()
之前需要按需导入:
const { computed } = Vue;
computed()
既可以创建只读的计算属性,还可以创建可读可写的计算属性。
// 创建只读计算属性
const plusCount = computed(() => count.value + 1);
// 创建可读可写的计算属性
// 创建一个 ref 响应式数据
const count = ref(1);
// 创建一个 computed 计算属性
const plusCount = computed({
// 取值函数
get: () => count.value,
// 赋值函数
set: (val) => {
count.value = val + 2;
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
# readonly
方法
这个函数可以把普通 object 对象、reactive 对象、ref 对象返回一个只读对象。