Vue3 学习
Vue3 简介
2020 年 9 月 18 日,Vue.js 发布 3.0 版本,代号:One Piece(海贼王)
耗时 2 年多、2600+次提交、30+个 RFC、600+次 PR、99 位贡献者
github 上的 tags 地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.0
Vue3 带来了什么
性能的提升
- 打包大小减少41%
- 初次渲染快 55%, 更新渲染快 133%
- 内存减少 54%
源码的升级
- 使用 Proxy 代替 defineProperty 实现响应式
- 重写虚拟 DOM 的实现和 Tree-Shaking
拥抱 TypeScript
- Vue3 可以更好的支持 TypeScript
新的特性
Composition API(组合 API)
- setup 配置
- ref 与 reactive
- watch 与 watchEffect
- provide 与 inject
- ···
新的内置组件
- Fragment
- Teleport
- Suspense
其他改变
- 新的生命周期钩子
- data 选项应始终被声明为一个函数
- 移除 keyCode 支持作为 v-on 的修饰符
- ···
创建 vue3 项目
1 |
|
Options API 的弊端
在 Vue2 中,我们编写组件的方式是 OptionsAPI:
Options API 的一大特点就是在对应的属性中编写对应的功能模块;
比如 data 定义数据、methods 中定义方法、computed 中定义计算属性、watch 中监听属性改变,也包括生命 周期钩子;
但是这种代码有一个很大的弊端:
当我们实现某一个功能时,这个功能对应的代码逻辑会被拆分到各个属性中;
当我们组件变得更大、更复杂时,逻辑关注点的列表就会增长,那么同一个功能的逻辑就会被拆分的很分散;
尤其对于那些一开始没有编写这些组件的人来说,这个组件的代码是难以阅读和理解的(阅读组件的其他人);
下面我们来看一个非常大的组件,其中的逻辑功能按照颜色进行了划分:
这种碎片化的代码使用理解和维护这个复杂的组件变得异常困难,并且隐藏了潜在的逻辑问题;
并且当我们处理单个逻辑关注点时,需要不断的跳到相应的代码块中;
OptionsAPI | Composition API |
---|---|
![]() |
![]() |
如果我们能将同一个逻辑关注 点相关的代码收集在一起会更好。
这就是Composition API想要做的事情,以及可以帮助我 们完成的事情。
也有人把 Vue Composition API 简称为VCA。
认识 Composition API
那么既然知道 Composition API 想要帮助我们做什么事情,接下来看一下到底是怎么做呢?
为了开始使用 Composition API,我们需要有一个可以实际使用它(编写代码)的地方;
在 Vue 组件中,这个位置就是 setup 函数;
setup其实就是组件的另外一个选项:
只不过这个选项强大到我们可以用它来替代之前所编写的大部分其他选项;
比如 methods、computed、watch、data、生命周期等等;
接下来我们一起学习这个函数的使用:
函数的参数
函数的返回值
setup 函数的参数
我们先来研究一个 setup 函数的参数,它主要有两个参数:
第一个参数:props
第二个参数:context
props 非常好理解,它其实就是父组件传递过来的属性会被放到 props 对象中,我们在setup 中如果需要使用,那么就可以直接通过 props 参数获取:
对于定义 props 的类型,我们还是和之前的规则是一样的,在 props 选项中定义;
并且在 template 中依然是可以正常去使用 props 中的属性,比如 message;
如果我们在 setup 函数中想要使用 props,那么不可以通过 this 去获取(后面我会讲到为什么);
因为 props 有直接作为参数传递到 setup 函数中,所以我们可以直接通过参数来使用即可;
另外一个参数是context,我们也称之为是一个SetupContext,它里面包含三个属性:
- attrs:所有的非 prop 的 attribute;
- slots:父组件传递过来的插槽(这个在以渲染函数返回时会有作用,后面会讲到);
- emit:当我们组件内部需要发出事件时会用到 emit(因为我们不能访问 this,所以不可以通过 this.$emit 发出事件);
setup 函数的返回值
- 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。(重点关注!)
- 若返回一个渲染函数:则可以自定义渲染内容。(了解)
注意点:
尽量不要与 Vue2.x 配置混用
- Vue2.x 配置(data、methos、computed…)中可以访问到 setup 中的属性、方法。
- 但在 setup 中不能访问到 Vue2.x 配置(data、methos、computed…)。
- 如果有重名, setup 优先。
setup 不能是一个 async 函数,因为返回值不再是 return 的对象, 而是 promise, 模板看不到 return 对象中的属性。(后期也可以返回一个 Promise 实例,但需要 Suspense 和异步组件的配合)
另外注意:setup 不可以使用 this
官方关于 this 有这样一段描述
表达的含义是 this 并没有指向当前组件实例;
并且在 setup 被调用之前,data、computed、methods 等都没有被解析;
所以无法在 setup 中获取 this;
其实在之前的这段描述是和源码有出入的:
之前的描述大概含义是不可以使用 this 是因为组件实例还没有被创建出来;
通过阅读源码发现,代码是按照如下顺序执行的:
调用 createComponentInstance 创建组件实 例;
调用 setupComponent 初始化 component 内 部的操作;
调用 setupStatefulComponent 初始化有状态的组件;
在 setupStatefulComponent 取出了 setup 函 数;
通过 callWithErrorHandling 的函数执行 setup;
从上面的代码我们可以看出, 组件的 instance 肯定是在执行 setup 函数之前就创建出来了。
响应式原理
Vue2
1 |
|
Vue3
1 |
|
认识ref全家桶
ref : 接受一个内部值并返回一个响应式且可变的ref对象。ref对象仅有一个.value property,指向该内部值。
isRef : 判断是不是一个ref对象
shallowRef : 创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的
triggerRef : 强制更新页面DOM — 这样也是可以改变值的
customRef : 自定义ref — customRef 是个工厂函数要求我们返回一个对象 并且实现 get 和 set 适合去做防抖之类的
reactive 函数
- 作用: 定义一个对象类型的响应式数据(基本类型不要用它,控制台会报警告,要用 ref 函数)
- 语法:const 代理对象= reactive(源对象)
- 接收一个对象(或数组),返回一个代理对象(Proxy 的实例对象,简称 proxy 对象)
- reactive 定义的响应式数据是“深层次的”。
- 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作。
为什么就可以变成响应式的呢?
这是因为当我们使用 reactive 函数处理我们的数据之后,数据再次被使用时就会进行依赖收集;
当数据发生改变时,所有收集到的依赖都是进行对应的响应式操作(比如更新界面);
事实上,我们编写的 data 选项,也是在内部交给了 reactive 函数将其变成响应式对象的;