vue3新特性
--
teleport可以指定元素渲染到某一元素下;
如:
<teleport to="body"> <div>父级teleport</div> </teleport>
emits自定义事件
emits: ['inFocus', 'submit'] // 会覆盖原生事件 emits: { // 没有验证 click: null, // 验证 submit 事件 submit: ({ email, password }) => { if (email && password) { return true } else { console.warn('Invalid submit event payload!') return false } } }
v-module可以绑定多个值
<user-name v-model:first-name="firstName" v-model:last-name="lastName" ></user-name>
自定义v-model修饰符:
<div id="app"> <my-component v-model.capitalize="myText"></my-component> {{ myText }} </div> app.component('my-component', { props: { modelValue: String, modelModifiers: { default: () => ({}) } }, emits: ['update:modelValue'], methods: { emitValue(e) { let value = e.target.value if (this.modelModifiers.capitalize) { value = value.charAt(0).toUpperCase() + value.slice(1) } this.$emit('update:modelValue', value) } }, template: `<input type="text" :value="modelValue" @input="emitValue">` })
<script setup>语法糖
声明的方法、变量、组件 可以直接在模板中使用;不用显示return出来
动态组件:
<script setup> import Foo from './Foo.vue' import Bar from './Bar.vue' </script> <template> <component :is="Foo" /> <component :is="someCondition ? Foo : Bar" /> </template>
递归组件、组件别名
例如:名为 FooBar.vue
的组件可以在其模板中用 <FooBar/>
引用它自己。
为了避免组件名和变量冲突,可以使用组件别名
import { FooBar as FooBarChild } from './components'
命名空间组件(引入多个组件时非常方便):
<script setup>
import * as Form from './form-components'
</script>
<template>
<Form.Input>
<Form.Label>label</Form.Label>
</Form.Input>
</template>
使用自定义指令:
这里有一个需要注意的限制:必须以 vNameOfDirective
的形式来命名本地自定义指令,以使得它们可以直接在模板中使用。
<script setup> const vMyDirective = { beforeMount: (el) => { // 在元素上做些操作 } } </script> <template> <h1 v-my-directive>This is a Heading</h1> </template>
<script setup> // 导入的指令同样能够工作,并且能够通过重命名来使其符合命名规范 import { myDirective as vMyDirective } from './MyDirective.js' </script>
defineProps
和 defineEmits
在 <script setup>
中必须使用 defineProps
和 defineEmits
API 来声明 props
和 emits
,它们具备完整的类型推断并且在 <script setup>
中是直接可用的:
<script setup> const props = defineProps({ foo: String }) const emit = defineEmits(['change', 'delete']) // setup code </script>
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>
useSlots
和 useAttrs
是真实的运行时函数,它会返回与 setupContext.slots
和 setupContext.attrs
等价的值,同样也能在普通的组合式 API 中使用
与普通的 <script>
一起使用
...
顶层 await
<script setup>
中可以使用顶层 await
。结果代码会被编译成 async setup()
:
<script setup>
const post = await fetch(`/api/post/1`).then(r => r.json())
</script>
状态驱动的动态 CSS
单文件组件的 <style>
标签可以通过 v-bind
这一 CSS 函数将 CSS 的值关联到动态的组件状态上:
<template> <div class="color1">父级teleport</div> </template> <script setup> import { ref } from 'vue' const theme = ref({ color: 'red' }) setInterval(() => { if(theme.value.color == 'red') { theme.value.color = 'green' } else { theme.value.color = 'red' } }, 500) </script> <style> .color1{ color: v-bind('theme.color'); } </style>
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>
.sync修饰符的替换:
<ChildComponent :title.sync="pageTitle" /> <!-- 替换为 --> <ChildComponent v-model:title="pageTitle" />
<template v-for> 的key用该设置在template标签上
vue3中的v-if比v-for的优先级高,与vue2相反
v-bind="object"
和一个相同的独立 attribute覆盖可以控制,写在后面的覆盖前面的
$listeners 被移除或整合到 $attrs
$attrs 现在包含 class 和 style attribute
...
--