新特性
1. 组合Api
2. Teleport
设置组件挂在的body的位置
3. 片段
template内可以设置多个元素,不再局限于一个根节点
4. Emits 组件选项
-
Html
attribute 名不区分大小写,浏览器会将所有大写字符解释为小写字符,故在dom模板使用时,驼峰需要使用横向-分割的等效值。 -
事件名
与组件和 prop 一样,事件名提供了自动的大小写转换。如果在子组件中触发一个以 camelCase (驼峰式命名) 命名的事件,你将可以在父组件中添加一个 kebab-case (短横线分隔命名) 的监听器。
javascript this.$emit('myEvent')
html <my-component @my-event="doSomething"></my-component>
-
定义自定义事件
可以在emits
选项在组件上定义发出的事件,当在 emits 选项中定义了原生事件 (如 click) 时,将使用组件中的事件替代原生事件侦听器。 -
v-model参数
组件上的 v-model 使用 modelValue 作为 prop 和 update:modelValue 作为事件。我们可以通过向 v-model 传递参数来修改这些名称:
<my-component v-model:title="bookTitle"></my-component>
- 多个model参数
单个组件示例上可以创造多个v-model绑定,v-mode绑定的值将同步到prop - model修饰符,可以自定义
5. createRenderer 全局API 自定义渲染器
6. 单文件组件 <script setup>
<script setup>
是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的 <script>
语法,它具有更多优势:
- 更少的样板内容,更简洁的代码。
- 能够使用纯 TypeScript 声明 props 和抛出事件。
- 更好的运行时性能
其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理 - 更好的 IDE 类型推断性能
减少语言服务器从代码中抽离类型的工作
注:-
setup 中的代码会在每次组件实例被创建时执行
-
顶层的绑定会暴露给模板。变量,函数声明,以及 import 引入的方法,组件, 都能在模板中直接使用
-
响应式(响应式api)
-
动态组件使用动态的
:is
来绑定<script setup> import Foo from './Foo.vue' import Bar from './Bar.vue' </script> <template> <component :is="Foo" /> <component :is="someCondition ? Foo : Bar" /> </template>
-
递归组件
相比于import导入文档组件,优先级更低 -
命名空间组件
使用*
引入,在模板内可以使用带点的组件标记。<script setup> import * as Form from './form-components' </script> <template> <Form.Input> <Form.Label>label</Form.Label> </Form.Input> </template>
-
自定义指令
必须为vNameOfDirective
来命名本地自定义指令例1: <script setup> const vMyDirective = { beforeMount: (el) => { // 在元素上做些操作 } } </script> <template> <h1 v-my-directive>This is a Heading</h1> </template> 例2: <script setup> // 导入的指令同样能够工作,并且能够通过重命名来使其符合命名规范 import { myDirective as vMyDirective } from './MyDirective.js' </script>
-
defineProps 和 defineEmits
在<script setup>
中必须使用defineProps
和defineEmits API
来声明props
和emits
。
传入到defineProps
和defineEmits
的选项会从setup
中提升到模块的范围。因此,传入的选项不能引用在setup
范围中声明的局部变量。这样做会引起编译错误。但是,它可以引用导入的绑定,因为它们也在模块范围内。 -
defineExpose
使用<script setup>
的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在<script setup>
中声明的绑定。为了在<script setup>
组件中明确要暴露出去的属性,使用defineExpose
编译器宏。<script setup> import { ref } from 'vue' const a = 1 const b = ref(2) defineExpose({ a, b }) </script>
-
useSlots 和 useAttrs
在<script setup>
使用 slots 和 attrs 的情况应该是很罕见的,因为可以在模板中通过$slots
和$attrs
来访问它们。在你的确需要使用它们的罕见场景中,可以分别用useSlots
和useAttrs
两个辅助函数:<script setup> import { useSlots, useAttrs } from 'vue' const slots = useSlots() const attrs = useAttrs() </script>
-
与普通的
<script>
一起使用
普通的<script>
在有这些需要的情况下或许会被使用到:- 无法在
<script setup>
声明的选项,例如inheritAttrs
或通过插件启用的自定义的选项。 - 声明命名导出。
- 运行副作用或者创建只需要执行一次的对象。
- 无法在
-
顶层 await
结果代码会被编译成async setup()
,需要和Suspense
组合使用<script setup> const post = await fetch(`/api/post/1`).then(r => r.json()) </script>
-
没有src的导入
-
7. 单文件组件状态驱动的 CSS 变量 (<style>
中的 v-bind)
单文件组件的 <style>
标签可以通过 v-bind 这一 CSS 函数将 CSS 的值关联到动态的组件状态上,这个语法同样也适用于 <script setup>
,且支持 JavaScript 表达式 (需要用引号包裹起来):
<style>
.text {
color: v-bind(color);
}
p {
color: v-bind('theme.color');
}
</style>
实际的值会被编译成 hash 的 CSS 自定义 property,CSS 本身仍然是静态的。自定义 property 会通过内联样式的方式应用到组件的根元素上,并且在源值变更的时候响应式更新
SFC <style scoped>
现在可以包含全局规则或只针对插槽内容的规则
<style scoped>
/* deep selectors */
::v-deep(.foo) {}
/* shorthand */
:deep(.foo) {}
/* targeting slot content */
::v-slotted(.foo) {}
/* shorthand */
:slotted(.foo) {}
/* one-off global rule */
::v-global(.foo) {}
/* shorthand */
:global(.foo) {}
</style>