Vue 3 即将到来!
我一直在尝试 Vue 3,它真的很酷。所以,让我分享一些我的心得。根据他们的路线图,他们计划在 2020 年第二季度末(4 月、5 月、6 月)发布。目前 Vue 3 处于 Alpha 测试阶段,但可能很快就会发布 Beta 版本。
请注意,本文具有时效性。随着代码的不断更改,可能会出现更好的最佳实践,并提供更完善的文档。但如果您想抢先一步,这篇撰写于 2020-04-08 的文章或许能帮到您。
立即开始
如果您愿意,现在就可以创建一个 Vue 3 项目。但请注意,目前尚无官方文档,在正式发布之前,代码可能会有所更改。我创建了一个GitHub 仓库,其中包含一个项目,您可以试用并查看一些示例代码。自述文件包含有关如何设置 Vue 3 项目的信息,以及一些让您随时了解最新情况的资源,以及有关 Vue 3 的文章、视频和播客。
改进
Vue 3 最大的变化在于其底层完全重写。对于我们开发者来说,这意味着一切基本相同。除此之外,最终结果会是一个更好的产品。Vue 本来就很快,但现在它在性能和内存方面都有了巨大的提升,并且在静态树提升和 tree shake(死代码消除)方面也做得更好了。

他们还用 TypeScript 编写了 Vue 3,这使得 Vue 团队能够更轻松地维护项目。同时,它也给我们开发者带来了一些好处,即使你使用的是 JavaScript 或 TypeScript,也能获得更好的 IntelliSense 和 TypeAhead 功能。
他们对每项变更都使用RFC(征求意见稿),以便让社区参与正在制定的决策。
变化
组合 API
现在,组件的 JavaScript 部分新增了一种可选的编写方式。我们将目前使用的方式称为 Options API,其中包含一个包含数据、方法、计算、监视等属性的对象。这在 Vue 3 中仍然有效。组合 API 只是一种附加的方式。我会尽量简短,但如果您想获得更清晰的解释,可以访问此处。
让我们看一下组件对象的骨架。
// Import the API's you are using for the component
import { ref, reactive, computed } from 'vue';
export default {
// the setup method where logic happens
setup(){
return { /* return what logic is exposed to the template */ }
}
}
现在到了激动人心的部分。让我们编写一些设置代码。ref
和reactive
用于存储反应变量。
setup(){
//Let's have two different reactive values
const counter = ref(0);
const state = reactive({
count: 0
});
//Update the values
counter.value++;
state.count++;
return { counter, state }
}
正如你所见,ref 和 react 的功能几乎相同。refref
主要用于原始类型和数组。while 用来reactive
保存对象。使用哪种方法取决于你,但我认为随着时间的推移,关于在何处使用哪种方法的最佳实践将会逐渐出现。
我们已经熟悉了计算属性、方法和监视。原理是一样的,只是写法略有不同。
我们还有watchEffect
与 watch 非常相似的,但是您不必告诉它要监听哪些值,它将在函数内部使用的每个依赖项上运行。
setup(){
const counter = ref(0);
const double = computed(() => counter.value * 2);
const addToCounter = toAdd => counter.value += toAdd;
watch(counter, () => console.log('counter updated'));
return { double, addToCounter }
}
我在这里使用了箭头函数,但它也可以是普通函数。代码不必位于 setup 方法内部,它可以位于 Vue 对象之外,也可以位于其他文件中。重要的是 setup 方法会返回方法和响应值。
这让我开始思考,这能不能用来创建一个非常简单的全局响应状态?答案是肯定的。
globalShoppingCart.js:
import { reactive, computed } from 'vue';
const shoppingCart = reactive({
items: [],
totalPrice: computed(() => shoppingCart.items.reduce((acc, item) => acc + item.price, 0))
});
const addItem = item => shoppingCart.items.push(item);
export { addItem, shoppingCart }
item.vue:
<template>
<h1>Ball</h1>
<button @click="addItem({name: 'ball', price: 99})">Add to Cart</button>
</template>
<script>
import { addItem } from '@/globalShoppingCart'
export default {
setup(){
return { addItem }
}
}
</script>
cart.vue:
<template>
<h1>Cart</h1>
<span>Items: {{ shoppingCart.items.length }}</span>
<span>Price: {{ shoppingCart.totalPrice }}</span>
</template>
<script>
import { shoppingCart } from '@/globalShoppingCart'
export default {
setup(){
return { shoppingCart }
}
}
</script>
太棒了!我们不用再处理那么多 props 和 emits 了。
它也非常适合代码复用。让我们将“点赞”和“超级点赞”功能放在一个独立的 JavaScript 文件中,但每个使用该文件的用户都会拥有各自的状态。
likes.js:
import { ref } from "vue"
const getLikes = () => {
const likes = ref(0)
const superLike = () => likes.value += 1000;
return { likes, superLike }
}
export { getLikes }
hearts.vue:
<template>
<div>
{{likes}}🧡
<button @click="likes++">Love</button>
<button @click="superLike">💕💕💕</button>
</div>
</template>
<script>
import { getLikes } from '@/likesOwn';
export default {
setup(){
return { ...getLikes() }
}
}
</script>
回到 Composition API 的最后一部分,生命周期钩子。它和生命周期钩子基本相同,但你可以在 setup 方法中使用它们。你也可以使用多个生命周期钩子。
setup(){
onMounted(() => console.log('DOM is ready'));
onMounted(() => console.log('mounted called again'));
}
有一点,根本没有 onCreated 之类的方法!这段代码应该放在 setup 方法里。因为 setup 方法会在组件启动时运行一次。所以,获取数据之类的操作最好放在 setup 方法里。
Composition API 是可选的,它可以与 Options API 在同一组件中使用。Composition API 有助于保持相关逻辑彼此接近,将设置代码移至其自己的文件中,并实现代码复用。Vue 的概念与之基本相同,您的数据将是ref
或 ,reactive
以及我们习惯使用的watch
、computed
和生命周期钩子。
分段
你有没有注意到每个模板只需要一个子元素?这很烦人,因为它会污染 DOM,并增加代码量和缩进。
不再
<template>
<h1>This is</h1>
<h2>completely</h2>
<h3>fine! :)</h3>
</template>
悬念
Suspense 是 Vue 3 中引入的新功能。当您的组件尚未准备好时,它可以让您轻松地显示加载微调器。
让我们有一个异步设置方法来获取一些数据。
async setup(){
const response = await fetch('someurl');
const data = await response.json();
return { data }
}
现在,这可能需要一些时间。你的组件什么时候才能准备好?只需让你的父组件像这样使用 Suspense 即可。
<template>
<Suspense>
<template #default>
<MyChildComponenta/> //the component with async setup
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
传送
请注意,Teleport 直到最近才被命名为 Portal,因此如果您正在阅读其他文章,它们可能已经过时了。
Teleport 使我们能够将一些 HTML 代码传送到应用程序中组件之外的另一个位置。
在您的应用程序中的某个地方,您有一个带有 id 的元素:
<div id="arrival-spot"></div>
现在您可以让另一个组件定位该元素。
<template>
<div>
<span>I'm still in my component</span>
<Teleport to="#arrival-spot">
<span>Woho, I can teleport \o/ </span>
</Teleport>
</div>
</template>
多个 v-model
现在,当您想要绑定不同的值时,您可以在自定义组件上拥有多个 v-model。
<HumanStats v-model:age="human.age" v-model:height="human.height"/>
过渡
只是过渡效果的命名略有变化。我发现 v-enter-active、v-enter 和 v-enter-to 有点令人困惑。在 Vue 3 中,v-enter 重命名为v-enter-from
,v-leave 重命名为v-leave-from
。现在,过渡效果更加清晰了,一个类表示活动状态,一个类表示过渡起始位置,一个类表示过渡目标位置。
已移除过滤器
<!-- before -->
{{ date | format }}
<!-- after -->
{{ format(date) }}
在 Vue 2 中,我们曾经使用过滤方法来处理显示值。现在,我们移除了过滤方法,以确保括号内的内容均为有效的 JavaScript。我们应当使用计算属性或方法,这完全没问题,只是另一种编写代码的方式而已。
应用程序配置
在 Vue 2 中,我们有一个全局Vue
对象用于配置。在 Vue 3 中,每个配置的作用域都限定在用 定义的某个 Vue 应用程序内createApp
。
main.js:
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)
app.mount('#app')
结论
我对 Vue 3 感到非常兴奋。我认为这将使 Vue 成为最好的框架之一。
文章来源:https://dev.to/gautemeekolsen/vue-3-is-coming-3icj