阅读 442

Vue3 新特性理解

前言

vue3 已经出来了有一段时间了,作为前端开发人员还是得紧跟时事,抓紧学习,了解新的技术,才不会被这个时代所淘汰。而且vue3 针对 vue2 来说,在性能上肯定是有所提高的,这就说明在后面的技术革新中,vue2可能会被vue3 所取代,当然也不是一时半会的事。所以现在趁热,只要学不死就往死里学吧。

下面就来总结一下我在学习Vue3 的过程中了解的一些特写,写下来加以理解。

Reactive

作用:用来给 引用类型 做响应式处理,注意这个属性只是给引用类型做响应式处理,而不是给引用类型的属性做响应式处理,所以reactive 用于包裹一个对象:

const user = reactive({name:'zhangsan', age:18})
复制代码

然后只是user这个对象有响应,并不代表user.nameuser.age 有响应式。所以在setup中返回的时候需要返回整个对象:

const user = reactive({
  name: 'zhangsan',
  age: 18
})
return {
  user
}
// 无法直接解构 在 template 中使用
// 因为reactive 响应化的是 user ,而不是 user 中的每个属性。 如果要响应user对象里面的每个值 就得使用 toRefs
// return {
//   ...user
// }
复制代码

在模板中就是这样使用的:

<p>reactive : {{ user.name }} - {{ user.age }}</p>
复制代码

另外关于对象的值的获取和设置,特别说明一下,如下注释解释:

// 设置值
setTimeout(() => {
  // 注意:修改 reactive 的值 不需要带.value
  // 只有是 reactive 和 template 使用的时候不需要带.value
  user.age = 21
  // 获取值
  // console.log(user.age)
}, 1500)
复制代码

至于原理:来自于vue3 用 proxy 实现,有兴趣的同学可以去了解一下。

ref

上面讲述了reactive 是用来做引用类型的响应式的,那么值类型的响应式就需要ref,用法也很简单:

<template>
  <div>
    <p>ref,{{ age }}</p>
  </div>
</template>

...
const age = ref<number>(10)
return {
  age
}
复制代码

关于ref 值的设置和获取,下面代码注释也有详细解释(这个时候就需要用到.value):

setTimeout(() => {
  // 这里修改 相当于对引用类型的值的进行修改,修改后 能响应到到原来的对象
  // 类似:
  // const a = { age:11 }
  // const b = a
  // b.age = 12
  // console.log(a.age)  // 12

  // 注意: 修改 ref 的值 需要带 value
  age.value = 13
}, 1500)

// 这样直接修改 age 是无法做到响应
// let age = 10
// setTimeout(() => {
//   age = 15
// }, 1500);
复制代码

所以ref 和 reactive 两者的使用就可以包含所有类型的响应式的处理。用于双向绑定 这也是vue 一直以来引以为傲的特性。

toRef

作用是将引用类型的某个属性变成响应式,举个栗子:

const user = reactive({ name: 'lisi', age: 16 }) // 首先将对象 变成响应式
// 然后把 对象的某个属性变成响应式
const ageToRef = toRef(user, 'age') // 相当于 把这个对象 中的 age 处理成了响应式
return {
  user,
  ageToRef
}
复制代码

这就是为什么我在介绍reactive 的时候一再强调,reactive只是正对引用类型本身做出的响应式,并不包含它本身属性的响应式。有了toRef的加持,现在就可以实现对象属性值的响应式了。

关于 toRef的值的设置与获取:

// 修改值
setTimeout(() => {
  ageToRef.value = 18
  // console.log(ageToRef.value)
}, 1500)
复制代码

toRefs

类型与 toRef,但显而易见,toRefs明显是个复数,所以它的作用就是将引用类型的属性都变成响应式:

setup() {
    const user = reactive({ name: 'jojo', age: 19 }) // 先将整个对象变成响应式
    const userToRefs = toRefs(user) // 再拆分该对象的每个属性 使之也成为响应式
    const { name, age } = userToRefs
    // 修改值
    setTimeout(() => {
      age.value = 21
    }, 1500)

    return {
      name,
      age
    }
}
复制代码

既在模板中就可以直接使用属性了:

<template>
  <div>
    <p>toRefs: {{ name }} - {{ age }}</p>
  </div>
</template>
复制代码

中途总结

  1. 为什么要使用 ref,reactive:

    答:因为 值类型的响应式 需要 ref,引用类型的响应式 需要reactive。

  2. 为什么要使用 toRef ,toRefs:

    答:因为 toRef 显示指定 对象中的值类型 需要变成 响应式,而toRefs 是隐式指定 对象 所有的属性都是响应式。

  3. 使用 toRefs 可以解构对象,使之返回属性单独可以在 template 中 使用。

watch

vue3 中的watch 和vue2 中的watch 在含义上是一直的,无非就是侦听数据的变化,但,vue3 分出了引用类型的响应式(reactive)和值类型的响应式(ref),vue3 中的watch 似乎变得更加不那么一样了,我们先看看用法:

setup() {
    const wNumber = ref<number>(100)
    const user = reactive({ name: 'zhangsan', age: 18 })
    // watch 监听 ref
    watch(wNumber, (newVal, oldVal) => {
      console.log(newVal, oldVal)
    })

    // watch 监听 reactive
    watch(
      () => user.age,
      (newVal, oldVal) => {
        console.log(newVal, oldVal)
      }
    )

    return {
      wNumber,
      user
    }
}
复制代码

从上面的代码可以看出,正对不同的响应式,在写法上稍有不同。

watchEffect

让人没想到的是,vue3 除了在setup 中引用了watch 之外,还引用了watchEffect这个api,其含义无非也是监听的意思。那这有什么不一样呢?

setup() {
    const wNumber = ref<number>(100)
    const user = reactive({ name: 'zhangsan', age: 18 })

    // watchEffect 初始化执行一次 监听回调函数内部所有使用的变量
    watchEffect(() => {
      // 这里自动监听到 wNumber
      console.log(`----${wNumber.value}-----`)
    })
    watchEffect(() => {
      // 这里自动监听到 user.name 、user.age
      console.log(`----${user.name}--${user.age}---`)
    })
    
    setTimeout(() => {
      wNumber.value = 200
    }, 1500)

    setTimeout(() => {
      user.age = 20
    }, 2000)

    return {
      wNumber,
      user
    }
 }
复制代码

如注释写的的样,watchEffect不需要手动监听,而是在setup 初始化的时候,就提前执行了一次,而这提前执行了一次之后,watchEffect 就知道了该回调函数内 那些值是需要被侦听的。所以当我们触发修改的时候就自动监听到改变了。虽然不知道什么时候回用到这个属性,但也不得不说,vue3的团队想的也算是很周到了。

其他特性

Proxy

Proxy 响应式替代了vue2 中的Object.defineProperty,在set新值和delete 值的时候得到了解决,优化了Object.defineProperty中一次性递归监听的问题。Proxy则是根据值的深度来递归,例如:一个对象有5层,获取第三层某个属性的值,则proxy只会递归到第三层的属性。

PatchFlag

给动态节点加上标记,动态节点类似于:{{ msg }},编译解析过程中会给动态节点添加标记。这样做有利于diff 算法在对比dom树的时候,省去对比静态节点,直接对比有标记的动态节点。

hoistStatic

编译过程中,使静态节点的变量提升到父作用域,使之缓存。其次多个静态节点在一起超过一定数量 会合并成dom 字符串直接解析。

cacheHandler

缓存事件,有事件缓存就取,没事件缓存就重新定义。

SSR优化

类似hoistStatic 将多个静态节点合并成dom字符串进行优化便于直接解析成真实的dom树。

tree-sharking

在编译过程中,对于用到的api 才会导入相应的编译模块。类似于按需加载

最后

vue3 无论在性能还是在规范上 对比vue2 还是有了很大的改进,高级特性Composition Api 也是vue 3的亮点。笔者做vue3的理解也只是在使用层面上,后续继续加油挖掘和学习vue3更多的特性。随着技术的迭代更新,vue3 也是大势所趋,加油学习!

文章分类
前端
文章标签