vue3的一些新特性

vue3的一些新特性

  • 编译
    • diff方法优化
    • hoistStatic 静态提升
    • cacheHandlers 事件侦听器缓存
    • ssr渲染
  • Composition API
    • 核心api
    • 逻辑提取与复用
  • 变化侦测

编译

diff方法优化

以下图为例,vue2中的虚拟dom通过模板创建虚拟节点(js对象),然后使用虚拟节点跟上一次缓存的虚拟节点进行全量的对比。

在vue3中做出了改进,可以看到图中左侧动态绑定msg的span有一处注释,官方叫它patch flag,在与上次虚拟节点进行对比时候,只对比带有patch flag的节点,并且可以通过flag的信息得知当前节点要对比的具体内容,以图中为例,要对比的就是text和props中的id。
vue3的一些新特性_第1张图片

hoistStatic 静态提升

把静态的节点进行提升,以下图为例,可以看到所有的静态span都被拿到了渲染函数体外面,也就是说在应用第一次的启动被创建了一次后,之后这些虚拟节点会在每次渲染时候被不停的复用,这样就免去了重复的创建节点,大型应用会受益于这个改动,免去了重复的创建操作,优化了运行时候的内存占用。
vue3的一些新特性_第2张图片

cacheHandlers 事件侦听器缓存

下面图中上面部分是不使用cacheHandlers,onClick需要看成是一个动态的绑定,因为绑定的函数可能会被改变,例如fn本来是data中返回的,之后如果把它替换掉了,这在实际中是需要进行一次更新的。

下面图中下面部分是使用cacheHandlers,在第一次渲染时会自动生成一个内联的函数,在内联函数里面引用当前的fn,然后把内联函数cache起来,后续的更新会从缓存中读同一个函数,因为是同一个函数,也就没有追踪变化的必要,这样就神奇的把这个span变成了静态的。手写的内联函数也会被cache起来,这样就会避免一些没必要的更新。

当我们在组件上使用内联函数,会受益于这个改动。
vue3的一些新特性_第3张图片
vue3的一些新特性_第4张图片

ssr渲染

当有大量静态的内容时候,这些内容会被当做纯字符串推进一个buffer里面,即使存在动态的绑定,例如图中,会通过模板插值嵌入进去。这样会比通过虚拟dmo来渲染的快上很多很多。

当静态内容大到一定量级时候,会用_createStaticVNode方法在客户端去生成一个static node,这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。
vue3的一些新特性_第5张图片

Composition API

官网介绍:在此我们将为您介绍组合式 API: 一组低侵入式的、函数式的 API,使得我们能够更灵活地「组合」组件的逻辑。

地址:https://composition-api.vuejs.org/zh/

核心api

  • reactive:接收一个普通对象然后返回该普通对象的响应式代理。
  • ref:接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value。
  • computed:传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象。
  • readonly:传入一个对象(响应式或普通)或 ref,返回一个原始对象的只读代理。一个只读的代理是“深层的”,对象内部任何嵌套的属性也都是只读的。
  • watchEffect:立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数。可显式的调用返回值以停止侦听。
  • watch:全等效于 2.x this.$watch (以及 watch 中相应的选项)。

逻辑提取与复用

例如下面是一个记录鼠标位置的组件,我们可以把它想象成一个react中的hook

import {
      ref, onMounted, onUnmounted } from 'vue'

export function useMousePosition() {
     
  const x = ref(0)
  const y = ref(0)

  function update(e) {
     
    x.value = e.pageX
    y.value = e.pageY
  }

  onMounted(() => {
     
    window.addEventListener('mousemove', update)
  })

  onUnmounted(() => {
     
    window.removeEventListener('mousemove', update)
  })

  return {
      x, y }
}

以下是一个组件如何利用该函数的展示:

import {
      useMousePosition } from './mouse'

export default {
     
  setup() {
     
    const {
      x, y } = useMousePosition()
    // 其他逻辑...
    return {
      x, y }
  },
}

变化侦测

ES6之前,js是没有提供**元编程**的能力的,也就是没有提供可以拦截原型方法的能力,vue通过覆盖Array原型的方法,来达到做一些自定义操作的目的,比如说发送变化通知。

vue2中覆盖了Array原型中的7个方法,分别是:push、pop、shift、unshift、splice、sort、reverse,所以当直接通过索引改变数组时,vue是追踪不到变化的。

所以在vue2中实现数据双向绑定,是通过Object.definePropertyd劫持各个属性的getter、setter,在读取数据时触发getter,修改数据时候触发setter。

在getter中收集哪些依赖使用了数据,当setter被触发时候,通知getter中收集的依赖数据变化了。

在vue3中改为用Proxy,但是Proxy只能代理一层,对于深层的无法代理。vue3中利用每次set被拦截之前都会拦截到get操作,所以vue3在get中直接对数据进行reactive,这样就大大减少了递归reactive带来的性能消耗。

与Object.definePropertyd对比优势:

1. 可以直接监听对象而非属性
2. 可以直接监听数组的变化
3. Proxy有多达13种拦截方式,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具备的
4. Proxy返回的是一个新对象,可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改 

你可能感兴趣的:(vue,vue3,js)