我们已经知道用新的主要版本Vue编写的应用程序性能会很好,但是性能并不是最重要的部分。对我们开发人员而言最重要的是,新版本将如何影响我们编写代码的方式。
如您所料,Vue 3带来了许多令人兴奋的新功能。 值得庆幸的是,Vue团队主要介绍了对当前API的添加和改进,而不是重大更改,因此,已经了解Vue 2的人们应该很快对新语法感到满意。
让我们从大多数人可能听说过的API开始...
合成API
组合API是Vue的下一个主要版本中最常用的讨论和特色语法。这是一种全新的逻辑重用和代码组织方法。
当前,我们使用的Options API来构建组件。要添加到逻辑组件的Vue我们填充(可选),如属性data
,methods
,computed
等这种方法的最大缺点是这不是JavaScript本身代码。您需要确切了解模板中可以访问哪些属性以及this
关键字的行为。在后台,Vue编译器需要将此属性转换为工作代码。因此,我们无法从自动建议或类型检查中受益。
Composition API旨在通过将组件属性中当前可用的机制公开为JavaScript函数来解决此问题。Vue核心团队将Composition API描述为 “一组基于功能的附加API,它们允许灵活地组成组件逻辑”。 用Composition 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
,使用计算属性,使用computed
访问访问生命周期挂钩onMounted
。
现在您可能想知道这种神秘的setup
方法是什么?
export default {
setup() {
简而言之,它只是一个将属性和函数返回到模板的函数。而已。我们在这里声明所有反应性属性,计算属性,观察者和生命周期挂钩,然后将它们返回,以便可以在模板中使用它们。
我们没有从setup
函数返回的内容将在模板中不可用。
const count = ref(0)
根据上面的内容,我们声明了count
用ref
函数调用的反应性。它可以包装任何原语或对象并返回其反应性引用。传递的元素的值将保留在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
}
最后,我们将返回count
和double
属性withincrement
方法,以使它们在模板中可用。
<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更改,意味着将来可能会更改。
Fragment
我们可以在Vue 3中期待的另一个激动人心的附加功能是片段。
您可能会问什么Fragment?好吧,如果您创建一个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 2中将Fragments与vue-fragments库一起使用,而在Vue 3中,您可以立即使用它!
悬挂 Suspense
React生态系统中另一个将在Vue 3中采用的好主意是Suspense组件。
Suspense暂停您的组件渲染,并渲染后备组件,直到满足条件为止。在Vue London Evan期间,Evan简短地谈到了这个主题,并向我们展示了我们可以期望的API。事实证明,Suspense只是具有插槽的组件:
<Suspense>
<template >
<Suspended-component />
</template>
<template #fallback>
Loading...
</template>
</Suspense>
将显示后备内容,直到Suspended-component
完全渲染为止。挂起可以等待,直到该组件被下载(如果这是一个异步组件),或者在setup
功能上执行一些异步操作。
多个v模型
V模型是一种指令,可用于在给定组件上实现双向绑定。我们可以传递反应性属性并从组件内部对其进行修改。
我们v-model
从表单元素非常了解:
<input v-model="property />
但是您知道您可以使用v-model
每个组件吗?内幕v-model
只是传递value
属性和侦听input
事件的捷径。将以上示例重写为以下语法将具有完全相同的效果:
<input
v-bind:value="property"
v-on:input="property = $event.target.value"
/>
我们甚至可以使用componentsmodel
属性来更改默认属性和事件的名称:
model: {
prop: 'checked',
event: 'change'
}
如您所见,v-model
如果我们希望在组件中进行双向绑定,那么伪指令可以是一个非常有用的语法求和者。不幸的是,v-model
每个组件只能有一个组件。
幸运的是,在Vue 3中这不会成为问题!您将能够提供v-model
属性名称,并根据需要拥有任意数量的属性。在下面,您可以v-model
在表单组件中找到两个的示例:
<InviteeForm
v-model:name="inviteeName"
v-model:email="inviteeEmail"
/>
当前在RFC中讨论了此API更改,这意味着将来可能会更改。
门户网站
门户网站是特殊的组件,旨在在当前组件之外呈现某些内容。这也是React本身实现的功能之一。这就是React文档关于门户的内容:
“门户网站可以提供一流的方式来呈现子组件到存在的父组件的DOM层次结构之外的DOM节点。”
这是处理模态,弹出窗口以及通常显示在页面顶部的组件的一种非常好的方法。通过使用门户,您可以确保没有任何主机组件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团队决定采用许多想法,而这些想法目前只能通过第三方库提供给框架的核心。
网友评论