Vue 3 新特性总结
Vue-next(Vue 3)已经发布一段时间了。目前它处于候选发布阶段,这意味着开放 API 不会有太大变化。很高兴看到 Vue 已经稳定下来,可以顺利地融入我们的项目。
不得不说,Vue 2 已经足够惊艳了。但 Vue 3 的新功能很可能会让我们的项目更上一层楼。我猜 Vue 3 中最激动人心的功能莫过于 Composition API。尤雨溪本人也提到, Composition API 的设计灵感源自 React 的 Hooks。虽然 Hooks 和 Compositions 这两个 API 非常相似,但从代码层面来看,它们完全不同。我们暂且不讨论哪个更好或更有前景,因为我并不认为这两个框架哪个更胜一筹。
总而言之,很高兴看到 Vue 也能做到 React 能做到的事情。让我们仔细看看这些新功能。
TLDR;
访问https://pitayan.com/posts/vue-next-features/阅读原文。
1. 维特
这是尤雨溪的又一杰作,旨在替代Vue 开发中的Webpack (目前仅适用于 Vue)。正如其法语名称所暗示的那样,它的设计目标是快速。
Vite 入门
官方 repo 为我们提供了一种通过Vite创建 Vue 3 应用程序的简单方法。
Npm
$ npm init vite-app <project-name>
$ cd <project-name>
$ npm install
$ npm run dev
纱
$ yarn create vite-app <project-name>
$ cd <project-name>
$ yarn
$ yarn dev
启动开发服务器
一切都发生在一眨眼的功夫。
❯ yarn dev
yarn run v1.22.4
$ vite
vite v1.0.0-rc.4
Dev server running at:
> Local: http://localhost:3000/
> Network: http://192.168.3.2:3000/
> Network: http://10.80.67.216:3000/
vue-next-features
我创建了一个小应用程序来演示Vue 3 的新功能。如果你看一下项目,你会发现vue-next-featurespackage.json
依赖项的简洁性会让你立刻爱上Vite。(我的意思是,谁不想从更简单的开始呢?)package.json
还有另一个与Webpack捆绑在一起的 Vue 3 “Hello World” repo ( vue-next-webpack-preview ) 。它也是一个很好的游乐场。
{
...,
"dependencies": {
"vite": "^1.0.0-rc.4",
"vue": "^3.0.0-rc.5"
},
"devDependencies": {
"@vue/compiler-sfc": "^3.0.0-rc.5"
}
}
{
...,
"dependencies": {
"vue": "^3.0.0-beta.2"
},
"devDependencies": {
"@vue/compiler-sfc": "^3.0.0-beta.2",
"css-loader": "^3.4.2",
"file-loader": "^6.0.0",
"mini-css-extract-plugin": "^0.9.0",
"url-loader": "^4.0.0",
"vue-loader": "^16.0.0-alpha.3",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11",¥
"webpack-dev-server": "^3.10.3"
}
}
2. Composition API
作为Vue.js最大的变化,Composition API 将成为你下一个最常用的功能。就像React Hooks一样,使用 Vue Composition API 将有助于获得更多的可定制性。
以下是 Vue 3 组合 API 的列表。(实际上还有更多……)
-
反应性
computed
reactive
ref
readonly
watch
watchEffect
unref
toRefs
isRef
isProxy
isReactive
isReadonly
customRef
markRaw
shallowReactive
shallowReadonly
shallowRef
toRaw
-
生命周期钩子
onBeforeMount
onBeforeUnmount
onBeforeUpdate
onMounted
onUpdated
onErrorCaptured
onRenderTracked
onRenderTriggered
onUnmounted
onActivated
onDeactivated
访问 Vue 3 官方文档了解有关这些 API 的更多信息。https
://v3.vuejs.org/api/composition-api.html
组件样式
在 Vue 2 中
使用配置模板定义组件内容。在 Vue 3 中,这种旧用法仍然可用。如果您更喜欢这种风格,可以继续使用。
<template>
<button @click="count++">count: {{ count }}</button>
</template>
<script>
const multiplier = 2
export default {
data () {
return {
count: 0
}
},
computed: {
result () {
return this.count * multiplier
}
},
mounted () {
console.log(this.count)
},
watch: {
count (val, oldVal) {
console.log(val, oldVal)
}
}
}
</script>
在 Vue 3 中
要使用 Composition API,您需要setup
在默认导出中添加一个属性。以下代码与上面的代码完全等效。
<template>
<button @click="count++">count: {{ count }}</button>
</template>
<script>
import { computed, reactive, toRefs, onMounted, watch } from 'vue'
export default {
setup () {
const multiplier = 2
const state = reactive({
count: 0
})
const result = computed(() => {
return state.count * multiplier
})
onMounted(() => {
console.log(state.count)
})
watch(state.count, (val, oldVal) => {
console.log(val, oldVal)
})
return {
...toRefs(state)
}
}
}
</script>
继续使用新的 API
您应该使用组合 API 而不是默认的 Vue 2 配置模板,原因有 4 个:
- 增加源代码的可读性
- 避免重复或冗余的逻辑
- 将相似的逻辑分组
- 重用逻辑
与 Vue 2 的配置风格相比,逻辑被精准地分解成更小的单元,以便您可以轻松地将相似的逻辑组合在一起。这样,也减少了跳转到不相关逻辑的机会。这无疑有助于提高生产力。
2. 高级反应性 API
我个人认为这与其他响应式 API 没什么不同。但它确实提供了处理诸如自定义钩子和浅层修改等边缘情况的能力。根据 Vue 3 官方文档,它现在是基本响应式 API的一部分。
在Vue 组合 API文档中(是的,有一个仅针对组合 API 的文档),以下 API 被列为高级反应性 API。
- customRef:自定义钩子
- markRaw:无法成为
reactive
- shallowReactive:对象的第一层
reactive
- shallowReadonly:对象的第一层
readonly
- shallowRef:对象的值不是
reactive
- toRaw:恢复
reactive
正常对象
你熟悉 吗Debounce
?这里有一个 的官方演示customRef
:
import { customRef } from 'vue'
const useDebouncedRef = (value, delay = 200) => {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger()
}, delay)
},
}
})
}
export default {
setup () {
return {
text: useDebouncedRef('some text')
}
}
}
3. v-enter-from / v-leave-from
在 Vue 2 中,<Transition>
组件有助于处理组件animation
/ transition
。但组件属性v-enter-active
v-enter
v-enter-to
对我来说相当模糊。有时我会搞不清楚哪个先发生。
现在在 Vue 3 中,这些过渡属性名称变得更加统一和直观。
v-enter
=>v-enter-from
v-leave
=>v-leave-from
<template>
<transition name="fade">
<div v-show="show">fade transition</div>
</transition>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
setup () {
const state = reactive({
show: true
})
setTimeout(() => {
state.show = false
}, 1000)
setTimeout(() => {
state.show = true
}, 2000)
return {
...toRefs(state)
}
}
}
</script>
<style>
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.fade-enter-to,
.fade-leave-from {
opacity: 1;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 2000ms;
}
</style>
过渡顺序:
v-enter-from
(腹部)v-enter-active
v-enter-to
v-leave-from
(V 离开)v-leave-active
v-leave-to
我相信这更容易理解,不是吗?
4. 允许多个根元素
Vue 2 在多个根元素上会抛出错误。模板中的所有元素都必须嵌套在一个根元素内。
<!-- Error -->
<template>
<div>pitayan</div>
<div>blog</div>
</template>
<!-- One Root Element only -->
<template>
<div>
<div>pitayan</div>
<div>blog</div>
</div>
</template>
Vue 3 移除了这种烦人的用法。我觉得当你真的不想把元素嵌套在“容器”父元素中时,这非常有用。有时你可能只需要把这些裸元素插入到正确的位置。
这与React Fragments类似,有助于缓解嵌套问题。
<!-- Vue 3 Multiple Root Element -->
<!-- Okay -->
<template>
<div>pitayan</div>
<div>blog</div>
</template>
5.“过滤器”已弃用(已删除)
我想很多人会觉得这filters
可能是 Vue.js 的一个很棒的功能。它确实在 Vue 的模板引擎中运行良好。(例如,数据格式化/计算等)。
让我们看看 Vue 3 文档如何解释filters
删除的原因:
虽然这看起来很方便,但它需要一种自定义语法,打破花括号内的表达式“只是 JavaScript”的假设,这既有学习成本,也有实施成本。
我相信没有 对开发来说没什么坏处filters
,尽管迁移到 Vue 3 可能会花费你额外的时间。在我的项目中, 的出现filters
相当罕见,因为我可以轻松地用method
或替换这个功能computed
。因为在我看来,method
/computed
比 更易读filters
。
<template>
<!-- Deprecated (removed) & Error -->
<span>{{ count | double }}</span>
<!-- If you have to use fiter, make it a function -->
<span>{{ double(count) }}</span>
</template>
<script>
import { ref } from 'vue'
export default {
// Not working
filters: {
double (val) {
return val * 2
}
},
setup () {
const count = ref(1)
return {
count,
double: val => val * 2
}
}
}
</script>
6. 新的异步组件:Suspense
这或许是 Vue 3 中唯一一个在正式发布后可能会有所改动的功能。它的灵感同样来自于React Suspense。所以在我看来,使用场景应该是一样的。
你还记得之前在 Vue 2 中是如何渲染异步数据的吗?我想答案应该是v-if
“/” 。v-else
<template>
<div>
<div v-for="i in items" :key="i">{{ i }}</div>
<div v-else>loading...<div>
</div>
</template>
<script>
export default {
data () {
return {
items: null
}
},
mounted () {
this.items = await new Promise(resolve => {
setTimeout(() => {
return resolve(['one', 'two'])
}, 3000)
})
}
}
</script>
使用Suspense
组件,你无需自己处理条件。通过设置default
andfallback
槽,Suspense
组件将自动处理异步事件。
<template>
<suspense>
<template #default>
<div v-for="i in items" :key="i">{{ i }}</div>
</template>
<template #fallback>
Loading...
</template>
</suspense>
</template>
<script>
export default {
async setup () {
const items = await new Promise(resolve => {
setTimeout(() => {
return resolve(['one', 'two'])
}, 3000)
})
return {
items
}
}
}
</script>
7. 在其他地方显示:传送
这是基于React Portals 的另一个很酷的东西。它提供了将组件插入目标 DOM 节点的功能。
我们在 Vue 2 中插入自定义组件<body>
(当然有一个 Vue 第三方插件PortalVue提供这样的功能):
import Vue from 'vue'
const Ctor = Vue.extends({
template: `<div>hello world</div>`
})
const vm = new Ctor({ ... }).$mount()
document.body.appendChild(vm.$el)
要在 Vue 3 中使用此功能,请包装目标组件<Teleport>
并在属性中定义目标节点(querySelector)to
。
<template>
<Teleport to="body">
<div>Pitayan</div>
</Teleport>
</template>
8. 允许多个 v-model
v-model
用于表单元素甚至自定义组件中的数据双向绑定。在 Vue 2 中,一个自定义组件v-model
在标签中只能有一个。
<template>
<my-input-form v-model="input" />
</template>
Vue 3 消除了该限制并允许您拥有多个,v-model
以便您可以为更多输入元素分别指定绑定。
<template>
<my-input-form
v-model:first="inputFirst"
v-model:second="inputSecond"
/>
</template>
9. 全局 API
Vue 3 提供了一些新的 API 来帮助我们更好地控制组件和实例。
创建应用程序
在 Vue 2 中,Vue
可以用作构造函数来返回实例对象。在 Vue 3 中,你可以使用createApp
函数来代替。两者的行为实际上是相同的。
// Vue 2
import Vue from 'vue'
import App from '@/src/App'
new Vue({
el: '#app',
components: {
App
}
})
// Vue 3
import { createApp } from 'vue'
import App from '@/src/App'
const app = createApp(App)
extend
component
那么像 mixin
和 这样的全局方法怎么样directive
?
相同,但您需要使用实例方法。
// Global methods
app.extend()
app.component()
app.mixin()
app.directive()
下一个刻度
我认为nextTick
这是一个经常使用的 API,因为很多逻辑实际上是异步的,它们需要安排到下一个 DOM 更新周期。
在 Vue 2 中,nextTick
是一个实例方法。
export default {
...,
mounted () {
this.$nextTick(() => {
console.log('pitayan')
})
}
}
Vue 3 允许您将其用作nextTick
独立函数。
// nextTick function type
export declare function nextTick(fn?: () => void): Promise<void>;
// An official doc Example
import { nextTick } from 'vue'
export default {
setup () {
const message = ref('Hello, Pitayan!')
const changeMessage = async newMessage => {
message.value = newMessage
await nextTick()
console.log('Now DOM is updated')
}
}
}
其他辅助函数
当你需要额外的控件来处理更抽象的场景时,这些新的 API 将非常有用。我个人认为它们可以在第三方库中频繁使用。
- h:返回虚拟节点
- createRenderer:可用于跨环境目的的自定义渲染器
- 定义组件:输入传入的对象
- DefineAsyncComponent:必要时加载异步组件
- resolveComponent:解析当前实例范围内的组件
- resolveDynamicComponent:解析当前实例范围内的动态组件
- resolveDirective:
directive
从当前实例范围获取 - withDirectives:适用
directive
于VNode
结论
我很高兴也很荣幸能够见证 Vue.js 2.x => 3.x 的成长。Vue 团队总结了 Vue 2 原生无法实现的功能,并将其融入 Vue 3 中。我发现 Vue 3 中有很多我们熟悉的代码库。
不难看出,Vue 3 是一个更加稳健的框架。它提供了一种全新且更简单的源代码组织方式,同时代码体积更小、运行速度更快。借助 Vue 3Typescript
及其新功能(例如 Composition API),项目结构可以与以往大不相同。我相信这对前端社区来说是一个积极的影响。
这就是 Vue 3 的新功能的全部内容。
如果您觉得这篇文章很棒,请分享到社交网络。感谢您的阅读。
参考
- https://v3.vuejs.org
- https://vuejs.org/v2/
- https://composition-api.vuejs.org/
- https://reactjs.org/docs/
原文刊登于Pitayan.com
https://pitayan.com/posts/vue-next-features/
文章来源:https://dev.to/pitayan/vue-3-new-features-summary-2cie