有趣的新闻Vue 3

而不是前言


Vue用于所有FunCorp项目。 我们密切监视框架的发展,不断改进开发过程并实施最佳实践。 而且,当然,我们不能通过,也不能翻译VueStorefront联合创始人Philip Rakovsky的文章,该文章关于严重影响代码编写的Vue 3新功能。

图片
上次我们研究了影响Vue 3性能的功能。 我们已经知道,在新版本的框架上编写的应用程序运行非常迅速,但是性能并不是最重要的变化。 对于大多数开发人员而言,Vue 3如何影响您编写代码的方式更为重要。

您可能已经猜到了,Vue 3将具有很多很棒的功能。 幸运的是,Vue团队增加了更多的增强功能和附加功能,而不是打破更改。 因此,大多数了解Vue 2的开发人员都应该很快适应新语法。

让我们从许多人可能听说过的API开始。

合成API


Composition API是Vue的下一个主要版本中讨论最多的功能。 Composition API语法提供了一种用于组织和重用代码的全新方法。

现在,我们正在使用称为Option API的语法创建组件。 为了添加逻辑,我们在组件对象中创建属性(选项),例如数据,方法,计算等。 这种方法的主要缺点是它不是JavaScript代码。 您需要确切知道模板中有哪些可用选项,以及它们的外观。 Vue编译器可将属性转换为适用的JavaScript代码。 由于此功能,我们不能完全使用自动完成或类型检查。

Composition API解决了这个问题,并使得可以使用普通JavaScript函数通过选项使用可用的机制。
Vue团队将Composition API描述为“一个可选的,基于功能的API,它允许在组件逻辑中灵活地使用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创建一个反应性属性,并使用onMounted函数访问已安装的生命周期挂钩。

您可能会有一个问题:这种神秘的设置方法是什么?

 export default { setup() {} } 

简而言之,设置只是将属性和功能传递给模板的功能。 我们将在setup函数中描述所有反应和计算属性,生命周期挂钩以及所有观察者,然后将其返回以在模板中使用。

事实上,我们不会从安装程序中返回,因此模板中将没有访问权限。

 const count = ref(0) 

使用ref函数初始化count反应性属性。 它接受一个原语或对象,并返回一个反应式链接。 传递的值将存储在创建的链接的value属性中。 例如,如果要访问count的值,则需要显式访问count.value。

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

因此,我们声明了一个计算的double属性和一个递增函数。

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

使用onMounted钩子,我们在安装组件后将消息打印到控制台以演示这种可能性。

 return { count, double, increment } 

为了使count和double属性以及递增方法在模板中可用,我们从设置方法中返回它们。

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

瞧! 我们可以从安装程序访问属性和方法,就像通过旧的Options API声明它们一样。

这是一个简单的示例,可以使用Options API轻松编写类似的示例。
但是,新的Composition API的优点并不在于以不同样式编写代码的能力,而是在于重用逻辑的可能性。

通过Composition API重用代码


让我们仔细研究一下新的Composition API的好处,例如,重用代码。 现在,如果要在多个组件中使用某些代码,则有两个选择:mixins和作用域插槽。 两种选择都有其缺点。

我们要提取计数器的功能,并在其他组件中重用它。 这是一个示例,说明如何使用现有API和新API来完成此操作。

首先,考虑使用mixins的实现。

 import CounterMixin from './mixins/counter' export default { mixins: [CounterMixin] } 

这种方法的最大问题是,我们对组件中添加的内容一无所知。 这使理解变得困难,并可能导致与现有属性和方法的冲突。

现在考虑范围有限的插槽。

 <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函数,而不会使用$ .Store属性阻塞Vue原型。 这种方法使您可以摆脱插件中的其他操作。

 const { commit, dispatch } = useStore() 

如果您想了解有关Composition API及其应用程序的更多信息,我建议您阅读一份文档,其中Vue团队将解释创建新API的原因并提供有用的案例。 还有一个很棒的存储库,其中包含使用Vue核心团队成员之一ThorstenLünborg的Composition API的示例。

配置和安装更改


新的Vue在构建和配置应用程序的方式上还有其他重要变化。 让我们来看一个例子。

 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 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对象的第三方库都可能在意想不到的地方(特别是如果是全局mixin)影响您的应用程序,这在Vue 3中是不可能的。

RFC 中讨论了这些更改,也许将来的实现会有所不同。

碎片


我们可以在Vue 3中依靠的另一个很酷的功能。
什么是碎片?
当前,一个组件只能有一个根元素,这意味着下面的代码将无法工作。

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

原因是隐藏在每个组件后面的Vue实例只能附加到一个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 2中使用片段,但可以使用vue-fragments库,而在Vue 3中,它们将立即可用!

悬念


将在Vue 3中实现的来自React生态系统的另一个好主意是Suspense。

挂起将暂停组件渲染并显示存根,直到满足某些条件为止。 在伦敦Vue上,Ewan Yu随便触摸了Suspense,并透露了我们可以期望的API。 暂挂组件将有2个插槽:用于内容和存根。

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

存根将一直显示,直到<Suspended-component />组件准备就绪为止。 暂挂组件可能还希望加载异步组件或在设置功能中执行一些异步操作。

多个v模型


v-model是可以使用双向绑定的指令。 我们可以传递反应性并在组件内部对其进行更改。

我们以使用表单元素而闻名。

 <input v-model="property" /> 

但是您知道v模型可以与任何组件一起使用吗? 在内部,v模型只是转发value参数并监听输入事件。

您可以使用以下语法重写前面的示例,如下所示:

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

您甚至可以使用模型选项更改默认属性名称和事件:

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

如您所见,如果我们要在组件中使用双向绑定,则v-model指令可以是非常有用的“语法糖”。 不幸的是,每个组件只能有一个v模型。

幸运的是,在Vue 3中将解决此问题。 我们可以将名称传递给v模型,并根据需要使用尽可能多的v模型。

用法示例:

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

RFC 中讨论了这些更改,也许将来的实现会有所不同。

门户网站


门户是为在当前组件的层次结构之外呈现内容而创建的组件。 这也是React中实现的功能之一 。 在React文档中,门户描述如下:“门户允许您在父组件的DOM层次结构之外的DOM节点中呈现子级。”

门户非常适合实现模态窗口,弹出窗口以及所有需要在页面顶部显示的组件等组件。

使用门户网站时,可以确保父组件的样式不会影响子组件。 它还可以为您节省肮脏的z-index骇客。

对于每个门户,我们需要指定显示门户内容的目的地。

以下是portal-vue库上的实现选项,该选项将门户添加到Vue 2。

 <portal to="destination"> <p>This slot content will be rendered wherever the portal-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中进行一些更改,以更好地匹配组件的生命周期。 创建指令将变得更加直观,从而使初学者更容易理解和学习。

现在,自定义指令声明如下所示:

 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也已进行了讨论 ,将来可能会更改。

总结


除了重大创新-Composition API之外,我们还可以发现一些较小的改进。 显然,Vue正在改善开发人员体验,简化和直观的API。 看到Vue团队决定将很多想法添加到框架的核心(已经在第三方库中实现)也很酷。

上面的列表仅包含最重要的API改进和更改。 如果您想了解其他信息,请查看RFC信息库

Source: https://habr.com/ru/post/zh-CN475968/


All Articles