【干货】Vue 3.2 有哪些新变化?
1前言
8.10号凌晨,尤雨溪在微博平台官宣 Vue 3.2 版本正式发布:
此版本包含一系列重要的新功能与性能改进,但并不涉及任何重大变更。本文主要介绍一些相对重要 Vue3.2新特性,如需了解更多请查阅官方文档!
2新的 SFC 功能
关于单文件组件(SFC,即.vue 文件)的两项功能已经由实验状态正式毕业,现提供稳定版本:
<script setup>
是一种编译时语法糖,能够极大改善在 SFC 中使用 Composition API 时的开发者体验。<style> v-bind
用于在 SFC<style>
标签中启用组件状态驱动的动态 CSS 值。
1、<script setup>
在<script setup>
中,我们不必声明export default
和setup
方法,这种写法会自动将所有顶级变量、函数,均会自动暴露给模板(template)使用。我们先来通过一个例子,对比script setup
前后写法的不同,直观感受下setup
带给我们的便利:
// script setup之前的写法
<template>
<div>
<div>浪里行舟</div>
<Card>{{ message }}</Card>
</div>
</template>
<script lang="ts">
import { ref, defineComponent } from "vue";
import Card from "./components/Card.vue";
export default defineComponent({
components: {
Card,
},
setup() {
const message = ref("vue 3.2 新特性 script setup");
return { message };
},
});
</script>
// script setup的写法
<template>
<div>
<div>浪里行舟</div>
<Card>{{message}}</Card>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import Card from "./components/Card.vue";
const message = ref("vue 3.2 新特性 script setup");
</script>
从上面的例子来看,<script setup>
语法省去了组件Card的注册步骤,以及return变量message的语句,使得代码更为精简。关于<script setup>
的使用还有些细节和注意事项,我将会在下一篇文章详细介绍。
2、<style> v-bind
挺有趣的一个新特性,通过这个指令,Vue SFC 的 CSS 灵活性将大大提高。该指令适用于<script setup>
, 并支持 JavaScript 表达式(必须用引号括起来)。
<script setup>
import { ref } from "vue";
const color = ref("pink");
color.value = "green";
const fontSize = ref("18px");
</script>
<template>
<h2>浪里行舟</h2>
<h1>Hello Vue3.2</h1>
<h2>{{ color }}</h2>
<button @click="color = 'red'">color red</button>
<button @click="color = 'yellow'">color yellow</button>
<button @click="color = 'blue'">color blue</button>
<button @click="fontSize = '40px'">fontSize 40px</button>
</template>
<style scoped>
h1 {
color: v-bind(color);
}
h2 {
font-size: v-bind(fontSize);
}
</style>
点击按钮更改color
或者 fontSize
的数值,可以看到页面样式也会响应式变化。其原理就是自定义属性将通过内联样式应用于组件的根元素,并在数值更改时进行响应更新。
3v-memo
3.2 版本为 Vue 的响应式系统带来了一系列重大性能改进,具体包括:
- 更高效的 ref 实现(读取速度提高约 260%,写入速度提高约 50%)
- 依赖项跟踪速度提高约 40%
- 内存使用量减少约 17%
新版本还提供新的 v-memo
指令,可实现对部分模板树的记忆功能。当v-memo
命中时,不仅允许 Vue 跳过虚拟 DOM 差异、甚至可以完全跳过新 VNode 的创建步骤。虽然这个指令使用频率不高,但它提供了一个逃生舱来在某些情况下(例如处理大型 v-for
列表)获取最大性能。
<div v-for="user of users" :key="user.id" v-memo="[user.name]">
{{ user.name }}
</div>
这个例子使用v-memo
,不会重新创建虚拟元素,并且会重新使用前一个元素,除非v-memo
(此处为用户名)的条件发生变化。这可能看起来是一个很小的改进,但如果您渲染大量元素,它实际上是性能的巨大改进。
其实v-memo
可以接受一组条件,请看下面的例子:
<div v-for="user of users" :key="user.id" v-memo="[user.name, selectedUserId === user.id]">
<p :class="{ red: selectedUserId === user.id }">{{ user.name }}</p>
</div>
此时如果user.name
或selectedUserId
发生变化,div
则将更新。
4新 ref 语法糖(实验性)
$ref()
避免在更新 ref 值时需要使用.value
,可以让代码更加精简!请看下面例子:
<template>
<input type="number" v-model="count"> * 5€
<h1>{{ total }}</h1>
</template>
<script setup>
let count = $ref(0)
let total = $computed(() => count * 5)
</script>
⚠️注意:这还是一个实验性特性,所以请谨慎使用,因为它将来可能会发生变化。该提案还引入了其他新的语法糖,包括$computed()
、$fromRefs()
和$raw()
。
5Expose API
Vue 3.2 添加了一个新的 Expose API
来定义组件公开的内容。Expose API
的设想是提供一个像 expose({ ...publicMembers })
这样的组合式 API,这样组件的作者就可以在 setup()
中使用该 API 来精细设定公开暴露给其他组件的内容。
下例中,该组件只能公开其toggle
函数,而不能公开其collapsed
变量。
export default defineComponent({
setup(props, { expose }) {
const collapsed = ref(true)
const toggle = () => {
collapsed.value = !collapsed.value;
}
// only expose `toggle` to the parent component
expose({ toggle })
return { collapsed, toggle }
}
})
请注意,所有$
实例属性都会自动公开,因此使用Collapse
的组件可以访问$props
,$slots
以及其他。<script setup>
通过调用defineExpose()
函数使用时也可以这样做。
当你在封装组件时,如果嫌ref
中暴露的内容过多,不妨用 Expose API
来约束一下输出吧!
6Effect Scope API
Vue 3.2版本引入了新的 Effect scope API
,用于创建一个effect Scope
对象,该对象可以捕获在其中创建的反应性效果(例如computed
或 watchers
),以便可以将这些效果放在一起并轻松处理它们。它可以更轻松地在组件上下文之外使用 Vue 的响应式 API,同时也在组件之内解锁了多种高级用例。Effect scope
是一种高级 API,主要供库作者使用。
我们知道watch
, watchEffect
,computed
等都是绑定到一个特定的组件实例上的,在组件销毁的时候会被 Vue 自动销毁。这可确保应用程序没有内存泄漏。但是如果你想在组件之外使用这些函数,例如在你正在编写的库中,你需要手动处理它们,请看下例:
import { ref, computed, stop, watchEffect } from 'vue';
const quantity = ref(0);
const price = ref(10);
const total = computed(() => quantity.value * price.value);
const stopWatch = watchEffect(() => console.log(`total changed to ${total.value}`));
let effectsToStop = [];
effectsToStop.push(() => stop(total));
effectsToStop.push(stopWatch);
const stopAll = () => {
effectsToStop.forEach(f => f())
effectsToStop = []
};
// calling `stopAll()` disposes of all effects
7.prop 和 .attr 修饰符
.prop
: 被用于强制绑定 DOM 属性 (property).attr
: 被用于强制绑定 DOM 属性 (attribute)
v-bind 默认绑定到 DOM 节点的 attribute 上,使用.prop
修饰符后,设置的自定义属性不会在渲染后的 HTML 标签里显示,而.attr
修饰符则刚好相反!
.prop
修饰符用途:
- 通过自定义属性存储变量,避免暴露数据
- 防止污染 HTML 结构
<input id="input" type="foo" value="11" :data.prop="inputData"></input>
// 渲染后HTML标签结构
<input id="input" type="foo" value="11"></input>
看了它的用途就知道,如果你不想你的属性显示在html标签里面,就用.prop
修饰符吧!
另外这两个修饰符有简写的语法:
<a :title.prop="firstTabTooltip" :aria-selected.attr="isFirstTabSelected">First tab</a>
<!-- 简写 -->
<a .title="firstTabTooltip" ^aria-selected="isFirstTabSelected">First tab</a>
8Web 组件
Vue 3.2 引入了新的 defineCustomElement
方法,可以使用 Vue 组件 API 轻松创建原生自定义元素:
import { defineCustomElement } from 'vue'
const MyVueElement = defineCustomElement({
// 常规 Vue 组件选项
})
// 注册自定义元素。
// 注册完成后,此页面上的所有 `<my-vue-element>` 标签
// 都将将升级。
customElements.define('my-vue-element', MyVueElement)
此 API 允许开发者们创建由 Vue 驱动的 UI 组件库。这些库可以支持任何框架选项,甚至能够在无框架情况下正常使用。
9总结
以上诸多特性,最让我感兴趣的是setup script
,此语法使单个文件组件更简单!只需要给 script
标签添加一个 setup
属性,那么整个 script
就直接会变成setup
函数,所有顶级变量、函数,均会自动暴露给模板使用(无需再一个个 return了),开发效率将大大的提高!
以至于连尤大也在微博上呼吁大家:“如果你能用Vue3却还在用 Options API,现在有了< script setup>没有理由不换 Composition API了”
欢迎正在学习、使用Vue3/TS的前端朋友入群,谢绝公众号主和广告商,群满200人可加我的微信(frontJS),拉你入群!
10参考资料
- Vue 3.2 Released!
- Vue 3.2 Released!
- What's new in Vue 3.2?
- v-bind 指令常用修饰符
- Vue3 官方文档
- Vue 3.2正式发布,script setup + TS + Volar = 真香