值得注意的新特性
- Composition API
- Teleport
- Fragments
- Emits Component Option
Teleport
Vue鼓励我们将UI和UI的行为封装到组件中,通过嵌套组件来构建我们的App。但是存在这样的一种情景,有多个子组件从逻辑上看是属于同一个父组件的,但是从技术实现的角度来看,多个子组件可能应挂载在DOM的不同位置,比较常见的情景是Modal。在Vue3之前,我们可以参考下Element UI 中Poper的实现。
if (!popper || !reference) return;
if (this.visibleArrow) this.appendArrow(popper);
if (this.appendToBody) document.body.appendChild(this.popperElm);
if (this.popperJS && this.popperJS.destroy) {
this.popperJS.destroy();
}
我们可以发现,是通过document.body.appendChild方法将元素挂载到body上的。而在Vue3中我们可以通过Teleport来实现这一操作。img将会挂载至body下。
<template>
<teleport to="body">
<img alt="Vue logo" src="./assets/logo.png" />
</teleport>
<HelloWorld msg="Welcome to Your Vue.js App" />
</template>
Teleport传送的元素依旧还会受Vue控制,这能很好的利用Vue的特性,可以说Teleport出现的大大增强了组件的可复用性和封装性。
最后多嘴一句,这里的名称或许叫Portal会让人更好理解,毕竟V社的传送门大家应该都玩过吧。好像是为了避免与可能出现的<portal></portal>标签冲突才换了个动词。
Fragments
简单来说就是,在vue3中组件官方支持声明多个根节点了。也就是说,下面这样的写法是可行的。同时需要我们显示的声明在何处分发attributes。
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
Emits Component Option
验证自定义事件
如果自定义事件是通过对象语法声明(Object syntax)而不是数组语法声明(Array Syntax)的,那么这个自定义事件可以像prop校验一样完成校验。
app.component('custom-form', {
emits: {
// No validation
click: null,
// Validate submit event
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
methods: {
submitForm() {
this.$emit('submit', { email, password })
}
}
})
v-modal
- 当我们在自定义组件上使用v-modal时,默认的prop和事件发生变化,
- prop:
value->modalValue - event:
input->update:modalValue
v-bind.sync以及modal参数被移除,并以v-modal arguments的形式替换。vue3中v-modal语法糖的形式变更,在vue3中的v-modal等价形式变更为如下形式。
<ChildComponent v-model="pageTitle" />
<!-- would be shorthand for: -->
<ChildComponent
:modelValue="pageTitle"
@update:modelValue="pageTitle = $event"
/>
可以通过v-modal arguments改变modal的名字
<ChildComponent v-model:title="pageTitle" />
<!-- would be shorthand for: -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
- 支持多个v-modal绑定
<user-name
v-model:first-name="firstName"
v-model:last-name="lastName"
></user-name>
- 支持创建自定义v-modal修饰符
<my-component v-model.capitalize="bar"></my-component>
app.component('my-component', {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
template: `
<input type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)">
`,
created() {
console.log(this.modelModifiers) // { capitalize: true }
}
})
重大变化
- Global Vue API is changed to use an application instance
- Global and internal APIs have been restructured to be tree-shakable
其他较小的变化
destroyed生命周期重命名为unmountedbeforeDestroy生命周期重命名为beforeUnmount- Props
default工厂函数不再能获取this上下文 data属性现在必须声明为函数- Attributes coercion strategy changed
- 重命名了一些transition类名
- watch数组时,如果没有
deep属性,那么只有在整个数组被替换时才会监听到变化