为了账号安全,请及时绑定邮箱和手机立即绑定

Vue3中令人兴奋的新功能

Vue 3中令人兴奋的新功能

在上一篇文章中,我们了解了Vue 3将带来的性能改进。我们已经知道用新的Vue编写的应用程序性能炸裂(运行非常好),但性能并不是最重要的部分。对我们开发人员而言最重要的是,新版本将如何影响我们编写代码的方式。

如今,Vue 3带来了许多令人兴奋的新功能。 值得庆幸的是,Vue团队主要介绍了对当前API的添加和改进,而不是进行重大更改,因此,已经了解Vue 2的大家应该会非常习惯这些变化。

让我们从大多数人可能听说过的API开始…


合成API(Composition API)

组合API是Vue的下一个主要版本中最常用的讨论和特色语法。这是一种全新的逻辑重用和代码组织方法。

当前,我们使用所谓的Options API构建组件。现在,添加到Vue组件的逻辑通常会采用:如datamethodscomputed等这种方法,最大缺点是这是不JavaScript代码原生方式。您需要确切了解模板中可以访问哪些属性,以及this关键字的行为。在后台,Vue编译器需要将此属性转换为工作代码。因此,我们无法通过从自动建议或类型检查中受益(而大家想一想Typescript,马上就会明白了)。

Composition API旨在,通过将组件属性中当前可用的机制公开为JavaScript函数来解决此问题。Vue核心团队将Composition API描述为“一组基于功能的附加API,可以灵活地组合组件逻辑”。用Composition API编写的代码更具可读性,并且都是原生JS,这使它更易于阅读和学习。

让我们来看一个使用新的Composition API理解其工作原理的组件的简单示例。

<template>
  <button @click="increment">
    Count is: {{ count }}, double is {{ double }}, click to increment.
  </button>
</template>

<script>
import { ref, computed, onMounted } from 'vue'

export default {
  setup() {
    const count = ref(0)
    const double = computed(() => count.value * 2)

    function increment() {
      count.value++
    }

    onMounted(() => console.log('component mounted!'))

    return {
      count,
      double,
      increment
    }
  }
}
</script>

现在,让我们将此代码分解为几部分,以了解发生了什么

import { ref, computed, onMounted } from 'vue'

正如之前提到的,Composition API将组件属性公开为函数,因此第一步是导入所需的函数。当前情况下,我们需要使用创建反应式引用ref,使用计算属性创建computed和使用访问生命周期挂钩onMounted

现在,你可能想知道这种神秘的setup方法是什么?

export default {
  setup() {

简而言之,它只是一个将属性和函数返回到模板的函数,而已。我们在这里声明所有反应性属性、计算属性、观察者和生命周期挂钩,然后将它们返回,以便可以在模板中使用它们。

我们没有从setup函数返回的内容将在模板中不可用。

const count = ref(0)

根据以上内容,我们声明了响应式的countref函数调用,它可以包装任何类型参数或对象,并返回其双向引用,传递的元素的值将保留在value创建的引用的属性中。例如,如果要访问count参考值,则需要明确要求count.value

const double = computed(() => count.value * 2)

function increment() {
  count.value++
}

…这正是我们在声明计算属性double以及increment函数时所做的事情。

onMounted(() => console.log('component mounted!'))

使用onMounted钩子,我们会在安装组件时记录一些消息。

return {
  count,
  double,
  increment
}

最后,我们返回countdouble属性with increment方法,以使它们在模板中可用。

<template>
  <button @click="increment">
    Count is: {{ count }}, double is {{ double }}. Click to increment.
  </button>
</template>

现在,我们可以访问setup模板中方法返回的属性和函数,就像通过旧的Options API声明它们一样。

这是一个简单的示例,也可以通过Options API轻松实现。

新的Composition API的修改了编码方式,加强了在重用我们的代码/逻辑时代码块复用性。

使用Composition API进行代码重用

新的Composition API具有更多优点,比如:代码复用。当前,如果我们要在其他组件之间共享一些代码,则有两个可用选项mixins作用域插槽。两者都有缺点。

假设我们要提取counter功能并将其在其他组件中复用。在下面,您可以看到如何将其与可用的API和新的Composition API结合使用:

让我们从mixins开始:

import CounterMixin from './mixins/counter'

export default {
  mixins: [CounterMixin]
}

mixins的最大缺点是:我们对它实际上添加到我们的组件中一无所知。这不仅使推理变得困难,而且还可能导致名称与现有属性和功能发生冲突。

现在该是作用域插槽了。

<template>
  <Counter v-slot="{ count, increment }">
     {{ count }}
    <button @click="increment">Increment</button> 
  </Counter> 
</template>

使用作用域插槽,我们确切地知道可以通过v-slot属性访问哪些属性,因此更容易理解代码。这种方法的缺点是:我们只能在模板中访问它,并且仅在Counter组件范围内可用。

现在是时候使用Composition API了:

function useCounter() {
  const count = ref(0)
  function increment () { count.value++ }

  return {
    count,
    incrememt
  }
}

export default {
  setup () {
    const { count, increment } = useCounter()
    return {
      count,
      increment
    }
  }
}

是不是更优雅?我们不受模板和组件范围的限制,并且确切地知道可以从计数器访问哪些属性。另外,我们可以从编辑器中可用的代码完成中受益,因为useCounter它只是一个返回某些属性的函数。幕后没有魔力,因此编辑器可以帮助我们进行类型检查和建议。

这也是使用第三方库的一种更优雅的方式。例如,如果我们要使用Vuex,则可以显式使用useStore函数而不是污染Vue原型(this.$store)。这种方法还可以消除Vue插件的幕后魔力。

const { commit, dispatch } = useStore()

如果您想了解有关Composition API及其用例的更多信息,我强烈建议您从Vue团队阅读此文档该文档解释了新API背后的原因并提出了最佳用例。Vue核心团队的ThorstenLünborg 还提供了一个很棒的存储库,其中包含Composition API使用示例。


全局安装/配置API更改

我们可以在实例化和配置应用程序的方式上找到另一个重大变化。让我们看看它现在如何工作:

import Vue from 'vue'
import App from './App.vue'

Vue.config.ignoredElements = [/^app-/]
Vue.use(/* ... */)
Vue.mixin(/* ... */)
Vue.component(/* ... */)
Vue.directive(/* ... */)

new Vue({
  render: h => h(App)
}).$mount('#app')

当前,我们正在使用全局Vue对象提供任何配置并创建新的Vue实例。对Vue对象所做的任何更改都会影响每个Vue实例和组件。

现在,让我们看看它如何在Vue 3中运行:

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

app.config.ignoredElements = [/^app-/]
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

app.mount('#app')

您可能已经注意到,每个配置都限于使用定义的某个Vue应用程序createApp

它可以使您的代码更易于理解,并且不易出现由第三方插件引起的意外问题。当前,如果某些第三方解决方案正在修改Vue对象,则它可能以意想不到的方式(尤其是全局混合)影响您的应用程序,而Vue 3则无法实现。

当前在此RFC 中讨论了此API更改,这意味着将来可能会更改。

碎片(Fragments)

我们可以在Vue 3中期待的另一个激动人心的附加功能是片段。

您可能会问什么碎片?好吧,如果您创建一个Vue组件,则它只能有一个根节点。

这意味着无法创建这样的组件:

<template>
  <div>Hello</div>
  <div>World</div>
</template>

原因是代表任何Vue组件的Vue实例都需要绑定到单个DOM元素中。创建具有多个DOM节点的组件的唯一方法是通过创建不具有基础Vue实例的功能组件。

事实证明,React社区也有同样的问题。他们提出的解决方案是一个名为Fragment的虚拟元素。看起来或多或少是这样的;

class Columns extends React.Component {
  render() {
    return (
      <React.Fragment>
        <td>Hello</td>
        <td>World</td>
      </React.Fragment>
    );
  }
}

即使Fragment看起来像一个普通的DOM元素,它也是虚拟的,根本不会在DOM树中呈现。这样,我们可以将组件功能绑定到单个元素中,而无需创建冗余DOM节点。

当前,您可以在带有vue-fragments库的Vue 2中使用片段,而在Vue 3中,您可以立即使用它!


Suspense组件

React生态系统中另一个将在Vue 3中采用的好主意是Suspense组件。

挂起将挂起组件渲染并渲染回退组件,直到满足条件为止。在Vue London Evan期间,您简短地谈到了这个主题,并向我们展示了我们可以期望的API。事实证明,Suspense只是具有插槽的组件:

<Suspense>
  <template >
    <Suspended-component />
  </template>
  <template #fallback>
    Loading...
  </template>
</Suspense>

后备内容将一直显示到Suspended-component完全渲染为止。挂起可以等待,直到该组件被下载(如果这是一个异步组件),或者在setup功能上执行一些异步操作。


多个v-model同时使用

v-model是一种指令,可用于在给定组件上实现双向绑定。我们可以传递反应性属性并从组件内部对其进行修改。

我们v-model从表单元素非常了解:

<input v-model="property />

但是您知道您可以使用v-model每个组件吗?内幕v-model只是传递value属性和侦听input事件的捷径。将以上示例重写为以下语法将具有完全相同的效果:

<input 
  v-bind:value="property"
  v-on:input="property = $event.target.value"
/>

我们甚至可以使用components model属性更改默认属性和事件的名称:

model: {
  prop: 'checked',
  event: 'change'
}

正如上面所示,vue2.x中采用v-model时,如果我们希望在组件中进行双向绑定,那么伪指令可能是一个非常有用的语法求和者。不幸的是,v-model每个组件只能有一个组件。

幸运的是,在Vue 3中这不会成为问题!您将能够提供v-model属性名称,并根据需要拥有任意数量的属性。在下面,您可以v-model在表单组件中找到两个的示例:

<InviteeForm
  v-model:name="inviteeName"
  v-model:email="inviteeEmail"
/>

当前在此RFC 中讨论了此API更改,这意味着将来可能会更改。


Portals组件(魔法提示类组件)

Portals是特殊的组件,旨在在当前组件之外呈现某些内容。这也是React本身实现的功能之一。这就是React文档关于门户的内容:

Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.

这是处理模态框、弹出窗口和通常显示在页面顶部的组件的一种非常好的方法。通过使用Portals,您可以确保没有任何主机组件CSS规则,会影响您要显示的组件,并使您免于使用进行讨厌的黑客攻击z-index

对于每个门户,我们需要指定它的目标目标,在其中将呈现提示类型内容。在下面,您可以看到portal-vue库的实现,该实现将此功能添加到Vue 2:

<portal to="destination">
  <p>This slot content will be rendered wherever thportal-target with name 'destination'
    is  located.</p>
</portal>

<portal-target name="destination">
  <!--
  This component can be located anywhere in your App.
  The slot content of the above portal component wilbe rendered here.
  -->
</portal-target>

Vue 3将附带对门户的开箱即用支持!


新的自定义指令API

自定义指令API在Vue 3中将略有变化,以更好地与组件生命周期保持一致。这项更改将使API更加直观,从而使新手更容易理解和学习API。

这是当前的自定义指令API:

const MyDirective = {
  bind(el, binding, vnode, prevVnode) {},
  inserted() {},
  update() {},
  componentUpdated() {},
  unbind() {}
}

……这就是Vue 3中的样子。

const MyDirective = {
  beforeMount(el, binding, vnode, prevVnode) {},
  mounted() {},
  beforeUpdate() {},
  updated() {},
  beforeUnmount() {}, // new
  unmounted() {}
}

即使这是一项重大更改,也应该使用Vue兼容性构建轻松涵盖。

当前在此RFC 中讨论了此API更改,这意味着将来可能会更改。


摘要

除了Composition API(它是Vue 3中最大的主要新API)之外,我们还可以找到很多较小的改进。我们可以看到,Vue正在朝着更好的开发人员体验和更简单,更直观的API迈进。也很高兴看到Vue团队决定采用许多想法,而这些想法目前只能通过第三方库提供给框架的核心。

上面的列表仅表示主要的API更改和改进。如果您对其他应用程序感到好奇,可以看一下Vue RFCs存储库。


========

本文转载于toimc前端技术,致力于打造前端知识,前端全栈知识,前端知识体系等前端前沿知识的社区平台,激励大家相互学习,共同进步。


点击查看更多内容
8人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
1370
获赞与收藏
682

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消