Vue3 新特性浅析

6,717 阅读2分钟

值得注意的新特性

  • 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>

0RfiRA.png

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和事件发生变化,
  1. prop:value->modalValue
  2. 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 }
  }
})

重大变化

其他较小的变化