Fork me on GitHub

Vue3的几个新特性

Composition API

Composition API 也叫组合式 API,它主要就是为了解决 Vue2 中 Options API 的问题。

vue2中,我们在methods、computed、watch、data中定义属性和方法,共同处理页面逻辑,我们称这种方式为Options API。
这种代码模式下存在几个问题:

  • 随着功能的增长,复杂组件的代码变得越来越难以维护。 尤其去新接手别人的代码时。 根本原因是 Vue 的现有 API 通过「选项」组织代码,但是在大部分情况下,通过逻辑考虑来组织代码更有意义。
  • 缺少一种比较「干净」的在多个组件之间提取和复用逻辑的机制。
  • 类型推断不够友好。

Composition API顾名思义就是不再传入data、mounted等参数,通过引入的ref、onMounted等方法实现数据的双向绑定、生命周期函数的执行。Composition API目的是通过一组低侵入式的、函数式的 API,使得我们能够更灵活地「组合」组件的逻辑,因此其中的代码是根据逻辑功能来组织的,同一功能所定义的所有api会放在一起。

setup

vue3中使用setup代替了beforeCreatecreated这两个生命周期,setup()是在创建vue组件实例并完成props的初始化之后执行(在 created() 生命周期函数之前执行)。同时setup返回的值,可以在模板和其他option中使用。

1
2
3
4
5
setup(props, context){
return {
text: 'test'
}
}

与Vue2区别:

不能使用this,而是通过 context 对象来代替当前执行上下文绑定的对象,context 对象有四个属性:attrs、slots、emit、expose。

ref、reactive

reactive 和 ref 都是用来定义响应式数据的。一般来说,ref用于基础赋值类型的数据,而reactive用于引用类型的数据。ref 的底层就是 reactive。

ref

ref函数传入一个值作为参数,一般传入基本数据类型(原始数据),ref的返回值是一个对象,这个对象上只包含一个.value属性。(可以理解为ref是在reactive上的封装)

  • 基本类型数据:响应式依然是通过Object.defineProperty()。
  • 引用类型数据:响应式是通过调用内部方法reactive函数(通过Proxy)

reactive

reactive是用来定义更加复杂的数据类型,但是解构就不具备响应式了(相当于跳过了代理重新赋新值了)。

toRef 和 toRefs

toRef是将对象中的某个值转化为响应式数据 toRef(obj, key)。

toRefs函数可以将reactive创建出来的响应式对象转换为普通的对象,这个对象上的每个属性都是Ref类型的响应式数据。

toRef和toRefs是对原始数据的引用,修改响应式数据时,原始数据也会发生改变,但是视图并不会更新。toRef修改的是对象的某个属性,toRefs修改的是整个对象

isRef

判断是否是ref对象。

unref

返回ref的.value值,或返回原值。

watch、watchEffect

watchEffect立即运行一个函数,然后被动的追踪它的依赖,当依赖重新改变时执行该函数。watch监测一个或多个响应式数据,并在变化时调用一个回调函数。

watchEffect是特殊的watch,传入的函数既是数据源又是回调。如果不关心数据变化前后值,只想监听拿到数据执行事件就可以用这个。watch更底层,可以接受多个数据源,可以获取变化前后的值。

watchEffect会立即执行一次,watch默认不会立即执行,除非传入immdiate。

watchEffect与watch区别:

  • 不需手动传入依赖
  • 初始化时会立即执行
  • 无法获取到原值,只能得到变化后的值

watch

watch 作用是监听传值(和Vue2一致,是惰性的,会返回新值和旧值)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ref 数据
const name = ref('name1')
watch(
name,
(newValue, oldValue) => {},
{ immediate: true, deep: true }
)

// reactive 数据
const user = reactive({ name: 'username' })
watch(
() => user.name,
(newValue, oldValue) => {}
)

// 多个数据
watch(
[name, () => user.name],
(newValue, oldValue) => {}
)

// 立即执行,在变化时追踪
watchEffect(() => console.log('Value: ' + user.name))

与Vue2区别:

  1. 传参不一样,watch需要传监听的响应式变量,回调函数,options配置
  2. 停止监听: 在组件中创建的watch监听,会在组件被销毁时自动停止。如果在组件销毁之前想要停止掉某个监听, 可以调用watch()函数的返回值。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const watchFun = watch(
    name,
    (newValue, oldValue) => {},
    { immediate: true, deep: true }
    )

    setTimeout(()=>{
    // 停止监听
    watchFun()
    }, 3000)

watchEffect

watchEffect用法和watch不一样。watchEffect 是传入一个立即执行函数,所以默认第一次也会执行一次;不需要传入监听内容,会自动收集函数内的数据源作为依赖,在依赖变化的时候又会重新执行该函数,如果没有依赖就不会执行;而且不会返回变化前后的新值和老值。

1
watchEffect(() => {})

生命周期钩子

  • setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
  • onBeforeMount() : 组件挂载到节点上之前执行的函数。
  • onMounted() : 组件挂载完成后执行的函数。
  • onBeforeUpdate(): 组件更新之前执行的函数。
  • onUpdated(): 组件更新完成之后执行的函数。
  • onBeforeUnmount(): 组件卸载之前执行的函数。
  • onUnmounted(): 组件卸载完成后执行的函数
  • onActivated(): 被包含在keep-alive中的组件,会多出两个生命周期钩子函数。被激活时执行。
  • onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行。
  • onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数(以后用到再讲,不好展现)。

Fragment(碎片化节点)

vue3组件的模板结构中出现多个标签时,可以不用根标签。编译时vue会在这些元素节点上添加一个<Fragment></Fragment>标签。并且该标签不会出现在dom树中。

Teleport(传送门)

是一个内置组件,使我们可以将一个组件的一部分模板“传送”到该组件的 DOM 层次结构之外的 DOM 节点中。

使用场景:有时组件模板的一部分逻辑上属于该组件,但元素上最好将模板的这一部分移动到组件之外的其他位置。比如点击按钮出现的弹出框。

1
2
3
4
5
6
// 渲染到body标签下
<teleport to="body">
<div class="modal">
模态框
</div>
</teleport>

Suspense(异步组件)

vue3中提供一个<Suspense></Suspense>组件用于控制异步组件。

作用:等待异步组件时渲染一些额外内容,让应用有更好的用户体验

使用:

1
2
3
4
5
6
7
8
9
<Suspense>
<template #default>
<!-- 异步组件 -->
<async-component />
</template>
<template #fallback>
加载中 ...
</template>
</Suspense>

其他框架层面的优化

  • 更快
    • 虚拟DOM重写:
    • 编译器优化:静态提升、patchFlags.block等
    • 基于Proxy的响应式
  • 更小:Tree-shaking优化
  • 更好维护:Ts + 模块化
  • 更容易扩展
    • 独立的响应化模块
    • 自定义渲染器
-------------完结撒花 -------------