Vue 3.2 的小知识

2021年8月5日发布了Vue3.2.0的版本,目前最新版本是3.2.23版本,3.2.x版本最大的亮点是,提升了响应式性能

新的编译器(compiler),跳过了很多 运行时(runtime) 检查,并且修改并优化了Composition API的响应式,提升了响应式性能:

  • ref API 的读效率提升了 260%,写效率提升了 50%
  • 依赖收集的效率提升了 40%
  • 减少了约 17% 的内存使用。

让我们看一下一些小功能

v-memo

记住一个模板的子树。元素和组件上都可以使用。该指令接收一个固定长度的数组作为依赖值进行记忆比对。如果数组中的每个值都和上次渲染的时候相同,则整个该子树的更新会被跳过。例如:

<ul v-for="member of members" :key="member.id" v-memo="[member.username]">
  <li>{{ member.username }}</li>
</ul>
复制代码

当组件重新渲染的时候,如果 member.username 的值维持不变,那么对这个 <ul> 以及它的所有子节点的更新都将被跳过。事实上,即使是虚拟 DOM 的 VNode 创建也将被跳过,因为子树的记忆副本可以被重用。听起来是不是很酷?

正确地声明记忆数组是很重要的,否则某些事实上需要被应用的更新也可能会被跳过。带有空依赖数组的 v-memo (v-memo="[]") 在功能上等效于 v-once

v-memo 仅供性能敏感场景的针对性优化,会用到的场景应该很少。渲染 v-for 长列表 (长度大于 1000) 可能是它最有用的场景:

<ul v-for="member of members" :key="member.id"
    v-memo="[member.name, member.id == selectedUser]">
  <li>
    <span :class="{ selected: selectedUser == member.id }">{{ user.name }}</span>
  </li>
</ul>
复制代码

v-demo数组中也可以接收 条件判断语句,上面的代码演示中,当组件的 selectedUser 状态发生变化时,即使绝大多数 member 都没有发生任何变化,大量的 VNode 仍将被创建,此处使用的 v-memo 本质上代表着“仅在 member 从未选中变为选中时更新它,反之亦然”

v-for 中使用 v-memo 时,确保它们被用在了同一个元素上。 v-memov-for 内部是无效的。

effectScope API

通常情况,响应式副作用绑定到挂载的 vue 实例,当组件被卸载时,依赖项会自动清理,不需要手动修改。但是,当我们在组件外使用或者编写一个独立的包时,这会变得非常麻烦。当在单独的文件中,我们该如何停止computed & watch的响应式依赖呢?新的API-----Effect Scope API出现了,专门用来解决这个问题

使用effectScope API,创建一个 effect 作用域对象,以捕获在其内部创建的响应式 effect (例如计算属性 computed或侦听器watch,watchEffect),使得这些 effect 可以一起被处理。

effectScope是一个函数,调用effectScope函数会返回一个对象,其中包含了run(一个函数)和stop(一个函数);

import { effectScope, watchEffect, computed, ref, watch } from 'vue'
export default {
  setup () {
    const scope = effectScope()
    const counter = ref(0)

    //2秒修改一次
    setInterval(() => {
      counter.value++
    }, 2000)

    //创建一个 effect 作用域对象
    scope.run(() => {
      const doubled = computed(() => counter.value * 2)

      watch(doubled, () => console.log('doubled:', doubled.value))

      watchEffect(() => console.log('Count: ', counter.value))
    })

    scope.run(() => {
      watchEffect(() => console.log(`counter: ${counter.value}`))
    })

    // 处理该作用域内的所有 effect
    // scope.stop()
  }
}
复制代码

如果没有调用scope.stop(),浏览器一直会输出结果 effectscope.gif

当调用了stop之后,浏览器只会输出一次。

效果: effectscope2.gif

v-bind

缩写:. (当使用 .prop 修饰符时)

修饰符

  • .prop : 将一个绑定强制设置为一个 DOM property
  • .attr:将一个绑定强制设置为一个 DOM attribute,新的快捷方式: ^

动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。

在绑定 classstyle attribute 时,支持其它类型的值,如数组或对象。可以通过下面的教程链接查看详情。

在绑定 prop 时,prop 必须在子组件中声明。可以用修饰符指定不同的绑定类型。

没有参数时,可以绑定到一个包含键值对的对象。注意此时 classstyle 绑定不支持数组和对象。

<!-- 绑定 attribute -->
<img v-bind:src="imageSrc" />

<!-- 动态 attribute 名 -->
<button v-bind:[key]="value"></button>

<!-- 缩写 -->
<img :src="imageSrc" />

<!-- 动态 attribute 名缩写 -->
<button :[key]="value"></button>

<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName" />

<!-- class 绑定 -->
<div :class="{ red: isRed }"></div>
<div :class="[classA, classB]"></div>
<div :class="[classA, { classB: isB, classC: isC }]"></div>

<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>
<div :style="[styleObjectA, styleObjectB]"></div>

<!-- 绑定一个全是 attribute 的对象 -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

<!-- prop 绑定。"prop" 必须在 my-component 声明 -->
<my-component :prop="someThing"></my-component>

<!-- 将父组件的 props 一起传给子组件 -->
<child-component v-bind="$props"></child-component>

<!-- XLink -->
<svg><a :xlink:special="foo"></a></svg>
复制代码

同样,v-bind也可以用到style标签中,看代码:

<script setup>
  import { ref } from 'vue';
  
  const color = ref('blue')
  const changeColorToRed = () => {
    color.value = 'red'
  }
</script>

<template>
  <p class="colored">{{ color }} colored text!</p>
  <button @click="changeColorToRed">
      Change color to red! (once and for all)
  </button>
</template>

<style scoped>
  .colored {
    color: v-bind(color);
  }
</style>
复制代码

Async Setup

重要:vue 3.0中,生命周期钩子不能在await。下面是正确的做法

async setup() {
  onCreated(() => console.log('Server side created, let\'s get data.'));
  const data = await fetchData();
  onMounted(() => console.log(`We have the data -{$data.metaInformation}`)); // can now be called
}
复制代码

Script Setup

<script setup>是一个语法糖

<script setup lang="ts">
  import { ref } from 'vue';
  
  const welcome = ref('Hello Tailiang') as string | undefined;
  const count = ref(0) as number;
  const increaseCount = () => {
    count.value++;
  }
  increaseCount()
</script>

<template>
  {{ welcome }} I have a counter on my website!
  Counter: {{ counter }}
</template>
复制代码

参考文献

Vue3.2 新正式属性 Effect Scope API -- Vue

Vue3.2 change

Vue 3.2 Released!

猜你喜欢

转载自juejin.im/post/7035637759733661733
3.2