Vue3新增特性总结

307 阅读5分钟

特性概括思维导图

以类别划分 (6).png

响应式系统升级

响应式原理之defineProperty和Proxy

二者区别 github.com/mqyqingfeng…

1.对对象的属性进行代理,在vue2.0中,收集依赖是通过遍历data对象里的属性方式,一个个添加defineProperty代理的, 而proxy的代理对象是整个对象,并且有很多handle方法,可以监听对象的增减等

2.defineProperty能生成的属性大概5、6个,而proxy可生成的属性相对较多

3.defineProperty不支持监听任意属性,而proxy不受影响。为什么definePrototype不能坚听数组呢?

  • 数组的长度是可以被重写的,但是并不是每个浏览器都接受这种做法。
    

image.png

  • 由于数组的长度可被重写,这就导致当一个长度为3的数组,不一定有索引为2的元素
    
image.png

4.defineProperty 兼容更好,IE8以上 , Proxy 需要支持ES6的浏览器,比如IE11.

definePropertyproxy造成的影响
代理对象是对象属性代理对象是整个对象1.不能监听属性的添加和删除添加。2.代理的时候,defineProperty更加耗费性能
能生成的属性少能生成的属性多
不能监听数组变化(下标、length,vue2.0对这部分做了处理,使得vue能监听到部分数组操作)能监听数组变化,而且对 Map、Set、WeakMap 和 WeakSet 的支持

响应式系统

整体概括【官方图】

image.png

reactive

接收一个普通对象,然后返回该普通对象的响应式代理。返回的代理对象并不等于原始对象,所以官方建议尽量操作代理对象,而不要直接操作原始对象。

如果想把响应式对象转换为原始对象可以使用toRow进行转换

可是使用isReactive判断一个对象是否由reactive创建

ref

接收一个参数,返回响应式并且可改变的对象。ref对象拥有一个指向内部值的单一属性value

如果接受的是一个对象,则会在内部使用reactive进行深层次代理后,返回一个响应式对象。

可以使用unrefisRef判断是否由ref创建 可以使用toRefs将一个ref数据转换为普通数据

toRef可以为一个reactive对象创建一个ref

watchEffect

  1. 调用stop()可以取消监听
  2. watchEffect初始化是在mounted之前,如果希望访问dom节点,需要将watchEffect放到onMounted里
  3. flush属性可以决定副作用执行的时机, 默认是“post”,你可以选择“sync”同步执行,或者“pre”在组件更新之前执行
  4. onTrack将在reactive或者ref被追踪时调用
  5. onTrigger会在依赖变更导致副作用触发时被调用,这两个有点类似于watch的set和get

watch

这个跟vue2.x的等效,而且跟watchEffect共享行为,还需要传入参数,我觉得不如都用watchEffect好了。如果你是vue2.x生vue3.x的,那也建议能用vue3的语法尽量用vue3的语法,虽然vue3做了兼融,但是混合模式的开发,个人感觉还是很乱的,没有充分发挥vue3的优点。

computed

这个跟vue2.x的computed有点像,有两种使用方式,一是自动派发计算属性,即传入一个ref,自动计算派发新值,二是传入set和get,让其变为一个可修改的计算属性。

生命钩子函数

生命周期的变化,主要是将beforeCreated和created去掉了,setup就可以取代他们的效果。 destory周期函数替换成了unmount

vue2.xvue3.x
beforeCreatesetup()
createdsetup()
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted
errorCapturedonErrorCaptured

自定义Hooks

学到这里,真的就觉得vue3.x跟react是越来越像了。一张图告诉你自定义hooks是做什么的。

未命名文件.png

我们把模块单独抽取出来,封装成use开头的一个个独立函数,如useAdd, useDelete等,自定义hook我觉得相当于是一个封装箱,把同一个功能作用的相关数据和action都装到一个函数里,要到使用的时候单独引入,这样能使页面的代码更加简洁明了。

不过如果有的人就是觉得以类别划分会比较舒服,那也没问题,按你的习惯来就行,我使用vue2.x已经很久了,突然转到vue3.x确实也有点不适应。

Teleport

Teleport 我觉得像是一个插槽,不过以前是<slot name="xxx"/>的形式插入template,现在是在页面某个元素上定义一个id="putHere",然后<Teleport to="putHere">我是子组件</Telport>, 子组件就会被插入到id为putHere的元素里

<template>
  <div class="about" id="putHere">
    <!-- <h1>This is an about page</h1> -->
  </div>
  <div>模块2</div>
  <Teleport to="#putHere">
    <h1>我是Teleport</h1>
  </Teleport>
</template>

表现

image.png

Suspense

很多时候我们需要按需加载组件,尤其是当数据是异步返回的时候,等待数据的过程中会有一个空白期,这个时候我们就需要设置一个默认态,以前我们是通过if else自己设置默认态来展示的,vue3.x中的Suspense就是处理这种情况的。 Suspense 是一个带有default和fallback两种状态的插槽组件,免去了我们需要额外定义一种空白状态的麻烦。

<template>
  <Suspense>
    <template #default>
      <my-component>
        <div v-if="isShow"></div>
        <div v-else></div>
      </my-component>
    </template>
    <template #fallback>
      <div>Loading</div>
    </template>
  </Suspense>
</template>

Tree-shaking

在以前vue2.x中,有些函数是挂载在vue实例上的,Vue3.x 在考虑到 tree-shaking的基础上重构了全局和内部 API, 表现结果就是现在的全局 API 需要通过 ES Module的引用方式进行具名引用。

  • Vue.nextTick
  • Vue.observable(用 Vue.reactive 替换)
  • Vue.version
  • Vue.compile(仅限完整版本时可用)
  • Vue.set(仅在 2.x 兼容版本中可用)
  • Vue.delete(与上同)

Fragment

vue3.x允许组件template底下同事存在多个节点,而不再是vue2.x那般只允许存在一个根结点,如Teleport示例代码中存在多个代码片段。

看完觉得有用记得点个赞让我升一下级哦O.O