Vue3上手指南
wen 2022/8/31  Vue
# 一、前言
本文主要聊的一些东西:
- Vue3 的全新特性;
 - Vue2 和 Vue3 的一些区别;
 - Vue2 开发者如何快速上手 Vue3。
 
# 二、Vue2 vs Vue3
# 1. 新特征概括
- RFC 机制;
 - 全新的响应式系统;
 - Composition API;
 - 全部模块使用 TypeScript 重构;
 - 新的组件;
 - 源码管理。
 
# 2. RFC 机制
- RFC 是什么:和代码无关,是 Vue 团队开发的工作方式。关于 Vue 的新语法或者新功能的讨论,都会先在 GitHub 上公开征求意见,邀请社区所有的人一起讨论。
 - GitHub 链接:https://github.com/vuejs/rfcs (opens new window)。
 - 这个改变让 Vue 社区更加有活力。
 
# 3. 全新的响应式系统
- 总的来说就是使用 Proxy 代替 Object.defineProperty。
 
# 3.1 Object.defineProperty
- 使用 get、set 来进行数据劫持,修改,从而实现响应式。
 - 由于 get、set 方式,所以只能捕获到属性读取和修改操作,当新增、删除属性时,捕获不到,导致界面也不会更新。
 - 直接通过下标修改数组,界面也不会自动更新。
 
# 3.2 Proxy
- Proxy 是什么,是代理,同时还有个 Window 上的内置对象 Reflect(反射)。
 - 通过 Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、属性的删除等。
 - 通过 Reflect(反射):对源对象的属性进行操作。
 
const p = new Proxy(data, {
  // 读取属性时调用
  get(target, propName) {
    return Reflect.get(target, propName);
  },
  // 修改属性或添加属性时调用
  set(target, propName, value) {
    return Reflect.set(target, propName, value);
  },
  // 删除属性时调用
  deleteProperty(target, propName) {
    return Reflect.deleteProperty(target, propName);
  }
});
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 4. Composition API
- Vue3 的组件可以按两种不同的风格书写:选项式 API (Options API) 和组合式 API (Composition API)。
 - 什么是组合式 API?- Vue 官方 (opens new window)。
 
# 4.1 简单来说
- 不会再看见满屏的 this 了;
 - 解决了过去组件过长时,Options Api 带来的难以维护的问题;
 - 逻辑可以整块复用;
 - 所有 API 都是 import 引入的,对 Tree- shaking 很友好,没用到功能,打包的时候会被清理掉,减小包的大小。
 
# 4.2 setup
- 新的 setup 选项在组件被创建之前执行,一旦 props 被解析完成,它就将被作为组合式 API 的入口。
 - 可以当做 Vue2 的 beforeCreate 和 created 生命周期用。
 - 可直接写 await 语法。
 - SFC 单文件组件中直接使用 
<script lang="ts" setup>即可,或者也可以结合export default使用。 
<script lang="ts" setup>
const result = await Http.get('/getUserInfo')
</script>
// or 
export default {
  setup(props, context) {
    // Attribute (非响应式对象,等同于 $attrs)
    console.log(context.attrs)
    // 插槽 (非响应式对象,等同于 $slots)
    console.log(context.slots)
    // 触发事件 (方法,等同于 $emit)
    console.log(context.emit)
    // 暴露公共 property (函数)
    console.log(context.expose)
  }
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 4.3 ref
- ref 用来创建基本数据类型的响应式数据。
 - template 中默认直接调用响应式数据显示数据,script 中需要使用 
.value调用。 - 和 react ref 差不多,react 是 
.current获取值,vue3 是.value。 - ref 的本质是通过 reactive 创建的,
ref(10) => reactive({ value: 10 })。究其原因,还是基本数据类型无法拦截它的变化。 
# 4.4 reactive
- reactive 用来创建引用数据类型的响应式数据。
 - reactive 的本质是将每一层的数据都解析成 
proxy对象。 - 直接解构,响应性会丢失,需要用 
toRefs包裹。引用类型直接改变引用地址也会导致响应式丢失。 
import { reactive, toRefs } from 'vue'
const book = reactive({
  author: 'Vue Team',
  title: 'Vue 3 Guide',
  description: 'You are reading this book right now ;)',
})
let { author, title } = toRefs(book)
title.value = 'Vue 3 Detailed Guide' // 使用 .value 作为标题,现在是 ref
console.log(book.title) // 'Vue 3 Detailed Guide'
 1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 4.5 生命周期
- 整体区别不大,把 setup 当 created 用,其它的生命周期就当改了个名。
 
<script setup lang="ts">
import { onMounted } from 'vue';
const getUserInfo = () => {
  console.log('the component is now mounted.');
};
onMounted(getUserInfo);
</script>
 1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
| Vue2 | Vue3 | 
|---|---|
| beforeCreate | Not needed* | 
| created | Not needed* | 
| beforeMount | onBeforeMount | 
| mounted | onMounted | 
| beforeUpdate | onBeforeUpdate | 
| updated | onUpdated | 
| beforeUnmount | onBeforeUnmount | 
| unmounted | onUnmounted | 
# 4.6 watch & watchEffect
- watch:功能和 vue2 一致、watch(监听参数,变化回调,配置参数)。
 
import { ref, reactive, watch } from 'vue'
const counter1 = ref(0)
const counter2 = ref(0)
// 监听多个
watch([counter1, counter2], (newValue, oldValue) => {
  console.log('The new counter1 value is: ' + counter1.value)
  console.log('The new counter2 value is: ' + counter2.value)
})
const obj = reactive({
  name: 'Wen',
  age: 23
})
// 深度监听对象
watch(obj, (newValue, oldValue) => {
  console.log('The new obj value is: ' + obj.value)
}, {
   deep: true,
   immediate: true
})
// watch监听单个属性
watch(() => obj.name, (newValue, oldValue) => {
  console.log('The new obj value is: ' + obj.value)
}, {
   deep: true,
   immediate: true
})
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
- watchEffect:类似 React -- useEffect,但是不需要写依赖项,只要我们回调中引用了响应式的属性。
 - watch & watchEffect 的区别:【1】同一个功能的两种不同形态,底层的实现是一样的;【2】watch 可以获取到新值与旧值(更新前的值),而 watchEffect 是拿不到的;【3】watch 显式指定依赖源,watchEffect 自动收集依赖源;【4】可以把 watchEffect 理解为是配置了{ immediate: true } 的 watch。
 - 使用场景:推荐在大部分时候用 watch 显式的指定依赖以避免不必要的重复触发。watchEffect 适用于一些逻辑相对简单,依赖源和逻辑强相关的场景(或者懒惰的场景 )。
 
# 4.7 computed
- 作用和 vue2 无差异;更加灵活,可以在定义响应式变量时声明。
 
import { ref, computed } from 'vue'
const counter = ref(0)
const twiceTheCounter = computed(() => counter.value * 2)
// get set 写法
const plusOne = computed({
  get: () => counter.value + 1,
  set: (val) => {
    counter.value = val - 1
  },
})
// set
plusOne.value = 1
console.log(counter.value) // 0
// get
counter.value++
console.log(counter.value) // 1
console.log(twiceTheCounter.value) // 2
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 5. 全部模块使用 TypeScript 重构
- 原因:从开发维护的角度看,Vue 2 是使用 Flow.js 来做类型校验。但现在 Flow.js 已经停止维护了,整个社区都在全面使用 TypeScript 来构建基础库,Vue 团队也不例外。
 - 好处:类型系统带来了更方便的提示,并且让我们的代码能够更健壮。
 
# 6. 新的组件
# 6.1 Fragment
- 这个更像是一种概念,它的意思就相当于创建页面时,给了一个虚拟根标签 
VNode,因为我们知道在 Vue2 里面,我们是有根标签这个概念的。但是到来 Vue3,它是自动给你创建个虚拟根标签VNode(Fragment),所以可以不要根标签。 - 好处就是减少标签层级,减小内存占用。
 
<template>
  <div>
    Vue2
  </div>
</template>
<template>
  Vue3
</template>
 1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 6.2 Teleport
- Teleport 是一种能够将我们的模板渲染至指定 DOM 节点,不受父级 style、v-show 等属性影响,但 data、props 数据依旧能够共用的技术。
 - 主要解决的问题:其实就是可以不考虑你写在什么位置,Teleport 节点挂载在其他指定的 DOM 节点下,完全不受父级 style 样式影响。
 
// body
<Teleport to="body">
    <Loading />
</Teleport>
// id 定位
<teleport to="#app">
  <Loading />
</teleport>
// class 定位
<teleport to=".app">
  <Loading />
</teleport>
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 6.3 Suspense
- 是异步组件,更方便开发有异步请求的组件。大家都知道在渲染组件之前进行一些异步请求是很常见的事,Suspense 组件提供了一个方案,允许将等待过程提升到组件树中处理,而不是在单个组件中。
 - 通过进行引入 defineAsyncComponent,配合 Suspense 进行更多操作,可用于 loading 和骨架屏相关。
 
// template
<Suspense>
  <template #default>
    <AsyncComponent></AsyncComponent>
  </template>
  <template #fallback>
    <div>loading...</div>
  </template>
</Suspense>
// script
const AsyncComponent = defineAsyncComponent(() => import('./asyncComponent.vue'))
 1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 7. 源码管理
- Vue 2 (opens new window) 内部所有的模块都是揉在一起的,这样做会导致不好扩展的问题;Vue 3 (opens new window) 利用拆包,使用最近流行的 monorepo 管理方式,响应式、编译和运行时全部独立。
 - 在 Vue 3 的组织架构中,响应式独立了出来。而 Vue 2 的响应式只服务于 Vue,Vue 3 的响应式就和 Vue 解耦了,你甚至可以在 Node.js 和 React 中使用响应式。
 
# 三、生态
# 1. Vite
- 官方文档:https://cn.vitejs.dev/ (opens new window)。
 - Vite 是下一代的前端工具链,和 Vue 也不是强绑定,Vite 的竞品是 Webpack。
 - Vite 主要提升的是开发的体验。现代浏览器已经默认支持了 ES6 的 import 语法,Vite 就是基于这个原理来实现的。具体来说,在调试环境下,我们不需要全部预打包,只是把你首页依赖的文件,依次通过网络请求去获取,整个开发体验得到巨大提升,做到了复杂项目的秒级调试和热更新。
 
# 2. 路由
- Vue Router:https://router.vuejs.org/zh/ (opens new window)。(v4.x)
 
# 3. 状态管理
- Vuex:https://vuex.vuejs.org/ (opens new window)(v4.x)
 - pinia:https://pinia.vuejs.org/ (opens new window)(官方推荐)
 
# 4. VSCode 插件
- Volar (Vue Language Features):Vetur 只支持 Vue2,Volar 只支持 Vue3,两者冲突。
 
# 5. hooks 函数
- Vue3 的 hooks 函数相当于 Vue2 的 mixin,不同在与 hooks 是函数。
 - Vue3 的 hooks 函数可以帮助我们提高代码的复用性,让我们能在不同的组件中都利用 hooks 函数。
 - hooks 库:【1】vueuse:https://github.com/vueuse/vueuse (opens new window);【2】ahooks-vue:https://dewfall123.github.io/ahooks-vue/ (opens new window);【3】v3hooks:https://github.com/yanzhandong/v3hooks (opens new window)。
 
# 四、Vue3 的创建
# 1. Vue 官网
npm init vue@latest
 1
# 2. Vite
npm create vite@latest
 1
# 3. Vue CLI
npm install -g @vue/cli
npm update -g @vue/cli
vue create vue-cli-demo
 1
2
3
2
3
