写点什么

Vue 3 中那些激动人心的新功能

  • 2019-10-30
  • 本文字数:5265 字

    阅读完需:约 17 分钟

Vue 3中那些激动人心的新功能

在近期我们发布的 《Vue 3 最值得期待的五项重大更新》 中,我们了解了 Vue 3 将带来的性能提升,知道了使用新版 Vue 编写的应用程序在性能表现上会很出色。但性能并不是最重要的部分,对于开发人员而言,最重要的是新版本将如何影响我们编写代码的方式。如你所料,Vue 3 带来了许多激动人心的新功能。值得庆幸的是,Vue 团队主要针对当前 API 做了添加和改进,没有引入多少重大更改。因此,熟悉 Vue 2 的开发人员应该可以很快习惯新语法。


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

合成 API

合成(Composition)API 是 Vue 的新大版本中讨论最多的特色语法。这是一种全新的逻辑复用和代码组织方法。


目前,我们使用所谓 Options API 构建组件。要将逻辑添加到 Vue 组件中,我们要填充(option)诸如 data、methods、computed 之类的属性。这种方法的最大缺点是它本身并非有效的 JavaScript 代码。你需要准确了解模板中可以访问哪些属性,以及 this 关键字的行为。在后台,Vue 编译器需要将属性转换为可用的代码。因此我们无法享受自动提示或类型检查功能的帮助。


合成 API 会将组件属性中当前可用的机制暴露为 JavaScript 函数,从而解决这个问题。Vue 核心团队将合成 API 定义为“一组基于函数的附加 API,可以灵活地组合组件逻辑”。用合成 API 编写的代码更具可读性,也没有在幕后隐藏什么魔法,这使它更易于阅读和学习。


下面来看一个使用了新的合成 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'
复制代码


如前所述,合成 API 将组件属性暴露为函数,因此第一步是导入所需的函数。在我们的示例中,我们需要用 ref 创建响应性引用、用 computed 创建计算属性,并用 onMounted 访问挂载的生命周期 hook。


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


export default {  setup() {
复制代码


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


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


const count = ref(0)
复制代码


根据上述内容,我们使用 ref 函数声明了称为 count 的响应属性。它可以包装任何原语或对象,并返回其响应性引用。传递的元素的值将保留在所创建引用的 value 属性中。例如,如果要访问 count 引用的值,则需要显式请求 count.-value。


const double = computed(() => count.value * 2)
function increment() { count.value++}
复制代码


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


onMounted(() => console.log('component mounted!'))
复制代码


我们使用 onMounted hook 在组件挂载时记录了一些消息,这里只是告诉你可以这样做😉


return {  count,  double,  increment}
复制代码


最后,我们使用 increment 方法返回 count 和 double 属性,以使其在模板中可用。


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


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


这是一个简单的示例,也可以通过 Options API 轻松实现。新的合成 API 的真正好处不仅仅是以不同的方式编码,在复用我们的代码 / 逻辑时,其优势就能显现出来。

使用合成 API 复用代码

新的合成 API 有更多优势。想想代码复用,这就是它的一大用武之地。目前,如果我们要在其他组件之间共享一些代码,则有两个选择可用——分别是 mixins 和作用域插槽。两者都有自己的缺点。


假设我们要提取 counter 功能并在其他组件中复用。下面的代码中你可以看到如何分别使用现有的 API 和新的合成 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 组件作用域中使用。


现在是时候使用合成 API 了:


function useCounter() {  const count = ref(0)  function increment () { count.value++ }
return { count, incrememt }}
export default { setup () { const { count, increment } = useCounter() return { count, increment } }}
复制代码


是不是更优雅?我们不受模板和组件作用域的限制,并且确切地知道可以从 counter 访问哪些属性。此外,由于 useCounter 只是返回某些属性的函数,因此我们可以获得编辑器中代码自动完成的帮助。没有隐藏在幕后的魔法,因此编辑器可以帮助我们检查类型并给出建议。


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


const { commit, dispatch } = useStore()
复制代码


如果你想了解有关合成 API 及其用例的更多信息,我强烈建议你阅读 Vue 团队写的这篇文档。这份文档解释了新 API 背后的理念,并给出了最佳用例的建议。Vue 核心团队的 ThorstenLünborg 还提供了一个很棒的存储库,其中包含合成 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')
复制代码


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


它可以让你的代码更容易理解,并且不容易出现由第三方插件引起的意外问题。当前,如果某些第三方解决方案正在修改 Vue 对象,则可能会以意想不到的方式(尤其是全局 mixins)影响你的应用程序,而 Vue 3 则不会出现这种情况。


这一 API 更改现在正在这个 RFC 中讨论,意味着将来它可能还会继续变动。

片段

Vue 3 中值得期待的另一个激动人心的新功能是片段(Fragments)。


你可能会问什么是片段?嗯,如果你创建一个 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>    );  }}
复制代码


尽管片段看起来像是普通的 DOM 元素,但它是虚拟的,根本不会在 DOM 树中渲染。这样我们可以将组件功能绑定到单个元素中,而无需创建多余的 DOM 节点。


目前,你可以在 Vue 2 中使用 vue-fragments 库来应用片段,而在 Vue 3 中它是开箱即用的!

Suspense

React 生态系统中还有一个好主意也将在 Vue 3 中采用,就是 Suspense 组件。


Suspense 会暂停你的组件渲染,并渲染回退组件,直到满足一个条件为止。在 Vue London Evan 期间,Vue 团队简单介绍了这个主题,并向我们展示了值得期待的 API。到头来 Suspense 只是一个具有插槽的组件:


<Suspense>  <template >    <Suspended-component />  </template>  <template #fallback>    Loading...  </template></Suspense>
复制代码


在 Suspended-component 完全渲染之前将显示回退组件。Suspense 可以等待组件下载完毕(如果该组件是异步的),或者在 setup 函数中执行一些异步操作。

多个 v-model

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


从表单元素可以很好地了解 v-model:


<input v-bind="property />
复制代码


但是你知道可以对所有组件使用 v-model 吗?在后台,v-model 只是传递 value 属性和侦听 input 事件的捷径。将上面的示例重写为以下语法会有完全相同的效果:


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


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


model: {  prop: 'checked',  event: 'change'}
复制代码


如你所见,如果我们希望在组件中进行双向绑定,则 v-model 指令可能是一个非常有用的语法糖。不幸的是,每个组件只能有一个 v-model。


还好在 Vue 3 中不会有这个问题!你将能够给 v-model 赋予属性名称,并根据需要拥有尽可能多的 v-model。下面这个示例中,你可以在一个表单组件中找到两个 v-model:


<InviteeForm  v-model:name="inviteeName"  v-model:email="inviteeEmail"/>
复制代码


这一 API 更改现在正在这个 RFC 中讨论,这意味着将来可能会有新的变化。

Portals

Portals 是特殊的组件,用来在当前组件之外渲染某些内容。这也是 React 原生实现的功能之一。React 文档关于 portals 是这样介绍的:


“Portals 提供了一种一流的方式来将子级渲染到父组件的 DOM 层级之外的 DOM 节点中。”


这是一种处理模态、弹出窗口以及页面顶部组件的非常好用的方法。通过 portals,你可以确保没有任何主机组件 CSS 规则会影响你要显示的组件,也无需使用 z-index 搞些小动作了。


对于每个 portal,我们需要指定其目标位置,在其中渲染 portal 内容。下面是 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"> <!-- 这个组件可以放在你应用中的任何位置上 上面 portal 组件的插槽内容会在这里渲染。 --></portal-target>
复制代码


Vue 3 将提供对 portals 的开箱即用支持!

新的自定义指令 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 兼容构建也应该能轻松覆盖。


这一 API 更改现在正在这个 RFC 中讨论,意味着将来它可能还会继续变动。

小结

除了合成 API(它是 Vue 3 中最重要的新 API)之外,我们还能在新版中找到很多较小的改进。我们可以看到,Vue 正在向更好的开发人员体验和更简单、更直观的 API 的目标前进。我们也很高兴看到 Vue 团队决定采用目前由第三方库带来的许多理念,将它们引入核心框架。


上面的内容只介绍了主要的 API 更改和改进。如果你对其他内容感到好奇,请务必查看 Vue RFCs 存储库


作者介绍:


Filip Rakowski 是一名 Web 开发人员,对最新的 Web 技术充满热情,并且特别喜欢 Vue 和渐进式 Web 应用。他的日常工作是开发开源产品、开发程序员接口以及与社区互动。他是 Vue Storefront 的联合创始人、StorefrontUI 的作者、Vue.js 官方社区合作伙伴和 VuePress 核心团队成员。


原文链接:


https://vueschool.io/articles/vuejs-tutorials/exciting-new-features-in-vue-3/


2019-10-30 20:085418
用户头像
王文婧 InfoQ编辑

发布了 126 篇内容, 共 74.3 次阅读, 收获喜欢 275 次。

关注

评论

发布
暂无评论
发现更多内容

什么是鱼骨图,怎么用AI制作鱼骨图?4个鱼骨图生成工具盘点!

职场工具箱

人工智能 效率工具 AI软件 AIGC 鱼骨图

初识华为RazorAttention

zjun

爬虫 API 科普:一文搞懂网络数据抓取的门道

代码忍者

API 接口

去中心化云算力(PowerVerse)是如何提供算力服务的?

PowerVerse

智能合约 去中心化 算力 #区块链 AI‘’

一篇论文,看见百度广告推荐系统在大模型时代的革新

百度Geek说

百度

电力生产和供应业需要堡垒机的情形简单聊聊

行云管家

网络安全 信息安全 数据安全 等保 堡垒机

国产替代势不可挡:大型企业ERP国产替代的挑战与机遇

用友BIP

ERP 国产替代 用友BIP 数智底座

升级数智底座:企业AI规模化应用的“中国解法”

用友BIP

科技 用友BIP 数智底座 国产大模型 企业AI

KubeEdge边缘设备管理系列(五):Mapper-Framework设备数据写入

华为云原生团队

云计算 容器 云原生

如何在线绘制roadmap路线图?5个简单易用的路线图软件盘点!

职场工具箱

在线白板 办公软件 AIGC 路线图 技术路线图

XEOS 与 AutoMQ 推出联合方案,共筑云原生 Kafka 新生态

AutoMQ

云计算 大数据 云原生 XSKY AutoMQ

户外全彩LED屏幕可以做成什么样的造型?

Dylan

广告 LED LED display LED显示屏 LED屏幕

【等保小知识】等保3.0出了吗?啥时候发布的?

行云管家

网络安全 等保 等保测评

zk源码—数据节点与Watcher机制及权限

不在线第一只蜗牛

源码 架构 zk

《Operating System Concepts》阅读笔记:p586-p586

codists

操作系统

无需登录+离线调试,Apipost比Apifox更值得拥有

数据追梦人

如何在API中实现搜索和过滤功能

数据追梦人

博睿数据全面接入DeepSeek:运用AI 铺就大模型可观测性进阶之路

博睿数据

博睿数据 DeepSeek v3

过剩与稀缺:现代社会的思考与启示

TechLead Studio

个人成长

三级等保测评的企业需要做什么准备?

黑龙江陆陆信息测评部

践行低碳行动!北京地铁签约用友

用友BIP

数智化 用友BIP 智能财务 北京地铁

条件锁存在的意义:用生活中的例子秒懂线程间的"暗号系统"

不在线第一只蜗牛

Java

飞机电气系统技术分析:数字样机技术引领创新

DevOps和数字孪生

高质发展,匠心智造!狄耐克荣获“2025年度中国精工品牌”荣誉称号

新消费日报

Cursor 在前端需求开发工作流中的应用|得物技术

得物技术

前端 AI‘’ cursor

腾讯云服务器怎么对接高防

网络安全服务

CDN DDoS 腾讯云服务器 高防IP DDoS 攻击

Kube Scheduler 可观测性最佳实践

观测云

Kubernetes

征文大赛 |「码」上数据库—— KWDB 2025 创作者计划启动

KaiwuDB

征文大赛 征文活动 征文投稿 数据库、 KaiwuDB 分布式多模数据库

新版 Midjourney V7 支持语音生图;语音 AI 平台 Phonic 融资 400 万美元,构建自主端到端模型丨日报

声网

共探 AI 硬件未来图景,火山引擎“智变浪潮”技术沙龙圆满落幕

火山引擎边缘云

AIOT AI 大底座 AI 数据基础设施

什么是BTC铭文?什么是MSKE马斯克铭文?

MSKE铭文

区块链 数字货币 MSKE铭文 马斯克铭文 比特币铭文

Vue 3中那些激动人心的新功能_大前端_Filip Rakowski_InfoQ精选文章