介紹
2020年9月19日凌晨,尤雨溪大大正式發(fā)布了 Vue.js 3.0 版本,代號(hào):One Piece。此框架新的主要版本提供了更好的性能、更小的捆綁包體積、更好的 TypeScript 集成、用于處理大規(guī)模用例的新 API,并為框架未來的長(zhǎng)期迭代奠定了堅(jiān)實(shí)的基礎(chǔ)。
3.0 版本的開發(fā)周期長(zhǎng)達(dá)兩年多,期間產(chǎn)生了 30+ RFCs、2600+ commits、628 pull requests,以及核心倉(cāng)庫(kù)之外的大量開發(fā)和文檔工作。
Vue 3.0 的發(fā)布標(biāo)志著此框架整體上已處于可用狀態(tài)。盡管框架的某些子項(xiàng)目可能仍需要進(jìn)一步的開發(fā)才能達(dá)到穩(wěn)定狀態(tài)(特別是 devtools 中的路由和 Vuex 集成),不過現(xiàn)在仍然是開始使用 Vue 3 啟動(dòng)新項(xiàng)目的合適時(shí)機(jī)。官方還鼓勵(lì)庫(kù)作者現(xiàn)在可以開始升級(jí)項(xiàng)目以支持 Vue 3。
what is RFC?
RFC(Request For Comments) - 即請(qǐng)求評(píng)議,旨在為新功能進(jìn)入框架提供一致且受控的路徑。
The "RFC" (request for comments) process is intended to provide a consistent and controlled path for new features to enter the framework.
Many changes, including bug fixes and documentation improvements can be implemented and reviewed via the normal GitHub pull request workflow.
Some changes though are "substantial", and we ask that these be put through a bit of a design process and produce a consensus among the Vue core team and the community.
RFC 為新功能的引入提供了統(tǒng)一可控的途徑,利于在Vue核心團(tuán)隊(duì)和社區(qū)中進(jìn)行方案的討論和優(yōu)化,最終達(dá)成共識(shí)。
The RFC life-cycle
An RFC goes through the following stages:
- Pending: when the RFC is submitted as a PR.
- Active: when an RFC PR is merged and undergoing implementation.
- Landed: when an RFC's proposed changes are shipped in an actual release.
- Rejected: when an RFC PR is closed without being merged.
如何參與
提出RFC pull request前,先在issue中討論該問題,然后提出RFC PR,PR中包含一個(gè) RFC的markdown文件(非實(shí)際代碼),經(jīng)過討論后核心團(tuán)隊(duì)最終將決定是否接受或拒絕該RFC。RFC的提出者并不一定需要自己去實(shí)現(xiàn)它(當(dāng)然歡迎實(shí)現(xiàn))。
創(chuàng)建Vue3.0項(xiàng)目
- 通過腳手架 vite 安裝:
npm init vite-app hello-vue3 # OR yarn create vite-app hello-vue3
Vite is an opinionated web dev build tool that serves your code via native ES Module imports during dev and bundles it with Rollup for production.
Vite目前僅支持 Vue 3.x以上,這意味著你不能使用不兼容Vue 3的組件庫(kù)
目前基于Vue的第三方組件庫(kù)兼容Vue 3的情況:
Ant Design Vue:支持 Vue 3.0 的 2.0.0 測(cè)試版已發(fā)布
ElementUI:尚未支持
MintUI:尚未支持
iView(ViewUI):尚未支持
Vue2-leaflet:很明顯不支持
- 通過腳手架 vue-cli 安裝:
首先全局更新最新版的 Vue CLI,4.5.0以上版本支持 Vue3:
npm install -g @vue/cli # OR yarn global add @vue/cli
vue create hello-vue3
# select vue 3 preset
Vue2.x 項(xiàng)目升級(jí)為 Vue3.x項(xiàng)目
最簡(jiǎn)單的方法,就是使用vue-cli 3.0,創(chuàng)建一個(gè)新的項(xiàng)目,然后將原有的項(xiàng)目源碼拷到新的項(xiàng)目中。
Vue3中兼容Vue2中定義組件的寫法,所以只需要將入口文件 main.js 中創(chuàng)建Vue實(shí)例的代碼替換為使用Vue3中新引入的 createApp方法,來創(chuàng)建應(yīng)用程序?qū)嵗姆绞郊纯伞?/p>
Vue 2 main.js:
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App),
}).$mount('#app')
Vue 3 main.js:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
值得注意的Vue3 新特性
Composition API(組合 API):
當(dāng)組件變得越來越大時(shí),邏輯關(guān)注點(diǎn)的列表也會(huì)增長(zhǎng)。這可能會(huì)導(dǎo)致組件難以閱讀和理解,且碎片化使得理解和維護(hù)復(fù)雜組件變得困難。選項(xiàng)的分離掩蓋了潛在的邏輯問題。此外,在處理單個(gè)邏輯關(guān)注點(diǎn)時(shí),我們必須不斷地“跳轉(zhuǎn)”相關(guān)代碼的選項(xiàng)塊。
如果能夠?qū)⑴c同一個(gè)邏輯關(guān)注點(diǎn)相關(guān)的代碼配置在一起會(huì)更好,于是 Composition API 應(yīng)運(yùn)而生。
使用Composition api的位置被稱為setup
setup組件選項(xiàng)
setup 組件選項(xiàng)在創(chuàng)建組件之前執(zhí)行,一旦 props 被解析,并充當(dāng)合成 API 的入口點(diǎn)。
注意:由于在執(zhí)行 setup 時(shí)尚未創(chuàng)建組件實(shí)例,因此在 setup 選項(xiàng)中沒有 this。這意味著,除了 props 之外,你將無(wú)法訪問組件中聲明的任何屬性——本地狀態(tài)、計(jì)算屬性或方法。
// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted } from 'vue'
// in our component
export default {
setup (props) {
const repositories = ref([]) // 定義一個(gè)變量
const getUserRepositories = async () => { // 定義一個(gè)方法
repositories.value = await fetchUserRepositories(props.user)
}
onMounted(getUserRepositories) // 生命周期鉤子 當(dāng)實(shí)例mounted后調(diào)用getUserRepositories方法
return {
repositories, // 返回一個(gè)data
getUserRepositories // 返回一個(gè)method
}
}
}
單文件組件 Composition API 語(yǔ)法糖 (<script setup>):
當(dāng)組件可以使用組合API后,setup往往成為了唯一會(huì)用到的組件屬性,因此利用語(yǔ)法糖簡(jiǎn)化setup的寫法
<template>
<button @click="inc">{{ count }}</button>
</template>
// Composition API
<script>
export default {
setup() {
const count = ref(0)
const inc = () => count.value++
return {
count,
inc,
}
},
}
</script>
// 使用了 Composition API 語(yǔ)法糖:
<script setup>
import { ref } from 'vue'
export const count = ref(0)
export const inc = () => count.value++
</script>
單文件組件狀態(tài)驅(qū)動(dòng)的 CSS 變量 (<style vars>):
有能力在運(yùn)行時(shí)根據(jù)組件狀態(tài)來動(dòng)態(tài)更新樣式
<template>
<div class="text">hello</div>
</template>
<script>
export default {
data() {
return {
color: 'red'
}
}
}
</script>
<style vars="{ color }">
.text {
color: var(--color);
}
</style>
單文件組件 <style scoped> 現(xiàn)在可以包含全局規(guī)則或只針對(duì)插槽內(nèi)容的規(guī)則:
帶有scoped屬性的style 不再只能作用域當(dāng)前單文件組件,通過深度選擇器、插槽選擇器、全局選擇器擁有了更改其他范圍樣式的能力。
<style scoped>
/* deep selectors */
::v-deep(.foo) {}
/* shorthand */
:deep(.foo) {}
/* targeting slot content */
::v-slotted(.foo) {}
/* shorthand */
:slotted(.foo) {}
/* one-off global rule */
::v-global(.foo) {}
/* shorthand */
:global(.foo) {}
</style>
Vue 3的重大改變
引入createApp
背景:
從技術(shù)上講,Vue 2 沒有“app”的概念,我們定義的應(yīng)用程序只是通過 new Vue() 創(chuàng)建的根 Vue 實(shí)例。從同一個(gè) Vue 構(gòu)造函數(shù)創(chuàng)建的每個(gè)根實(shí)例共享相同的全局配置,因此全局配置使得在測(cè)試期間很容易意外地污染其他測(cè)試用例。用戶需要仔細(xì)存儲(chǔ)原始全局配置,并在每次測(cè)試后恢復(fù) (例如重置 Vue.config.errorHandler)。有些 API 像 Vue.use 以及 Vue.mixin 甚至連恢復(fù)效果的方法都沒有,這使得涉及插件的測(cè)試特別棘手。
createApp:
import { createApp } from 'vue'
const app = createApp({})
調(diào)用 createApp 返回一個(gè)應(yīng)用實(shí)例,應(yīng)用程序?qū)嵗┞懂?dāng)前全局 API 的子集,任何全局改變 Vue 行為的 API 現(xiàn)在都會(huì)移動(dòng)到應(yīng)用實(shí)例上,以下是當(dāng)前全局 API 及其相應(yīng)實(shí)例 API 的表:
[圖片上傳失敗...(image-c4a9d6-1601349914900)]
所有其他不全局改變行為的全局 API 現(xiàn)在被命名為 exports。
全局和內(nèi)部API已重構(gòu)為可 tree-shakable
Tree shaking 是一個(gè)通常用于描述移除 JavaScript 上下文中的未引用代碼(dead-code) 行為的術(shù)語(yǔ)。
它依賴于ES2015中的 import 和 export 語(yǔ)句,用來檢測(cè)代碼模塊是否被導(dǎo)出、導(dǎo)入,且被 JavaScript 文件使用。
在現(xiàn)代 JavaScript 應(yīng)用程序中,我們使用模塊打包(如webpack或Rollup)將多個(gè) JavaScript 文件打包為單個(gè)文件時(shí)自動(dòng)刪除未引用的代碼。這對(duì)于準(zhǔn)備預(yù)備發(fā)布代碼的工作非常重要,這樣可以使最終文件具有簡(jiǎn)潔的結(jié)構(gòu)和最小化大小。
2.x 語(yǔ)法:
// 全局 API Vue.nextTick() 不能tree-shaking
import Vue from 'vue'
Vue.nextTick(() => {
// 一些和DOM有關(guān)的東西
})
3.x語(yǔ)法:
全局 API 現(xiàn)在只能作為 ES 模塊構(gòu)建的命名導(dǎo)出進(jìn)行訪問,如果模塊綁定器支持 tree-shaking,則 Vue 應(yīng)用程序中未使用的全局 api 將從最終捆綁包中消除,從而獲得最佳的文件大小。
import { nextTick } from 'vue'
nextTick(() => {
// 一些和DOM有關(guān)的東西
})
受影響的API:
- Vue.nextTick
- Vue.observable (用Vue.reactive替換)
- Vue.version
- Vue.compile
- Vue.set
- Vue.delete
組件上 v-model 用法已更改
- 自定義
v-model時(shí),prop和事件默認(rèn)名稱已更改:
prop:value->modelValue
event:input->update:modelValue -
.sync和組件的model選項(xiàng)已移除,可用v-model作為替代 - 現(xiàn)在可以在同一個(gè)組件上使用多個(gè) v-model 進(jìn)行雙向綁定;
- 現(xiàn)在可以自定義 v-model 修飾符
比如自定義v-model.capitalize,綁定為字符串第一個(gè)字母的大寫
<template v-for> 和非 - v-for 節(jié)點(diǎn)上 key 用法已更改
Vue 2.x 建議在 v-if/v-else/v-else-if 的分支中使用 key,Vue 3.x 中仍能正常工作,但不再建議,因?yàn)闆]有為條件分支提供 key 時(shí),也會(huì)自動(dòng)生成唯一的 key。
在 Vue 2.x 中 <template> 標(biāo)簽不能擁有 key,在 Vue 3.x 中 key 則應(yīng)該被設(shè)置在 <template> 標(biāo)簽上。
在同一元素上使用的 v-if 和 v-for 優(yōu)先級(jí)已更改
- Vue 3.x 中v-if 會(huì)擁有比 v-for 更高的優(yōu)先級(jí)。
由于語(yǔ)法上存在歧義,建議避免在同一元素上同時(shí)使用兩者,比如利用計(jì)算屬性篩選出列表。
v-bind="object" 現(xiàn)在排序敏感
- Vue 2.x 如果一個(gè)元素同時(shí)定義了 v-bind="object" 和一個(gè)相同的單獨(dú)的 property,那么這個(gè)單獨(dú)的 property 總是會(huì)覆蓋 object 中的綁定。
- Vue 3.x 聲明綁定的順序決定了它們?nèi)绾魏喜ⅰ?/li>
// 2.x中 id最終為red 3.x中 id為blue
<div id="red" v-bind="{ id: 'blue' }"></div>
v-for 中的 ref 不再注冊(cè) ref 數(shù)組
Vue 2 中,在 v-for 里使用 ref屬性時(shí),從$refs中獲取的相應(yīng)屬性會(huì)是一個(gè)ref數(shù)組。
-
Vue 3中則將ref綁定到一個(gè)更靈活的函數(shù)上 (ele) => { ...//保存ele的操作 }:
template:
<div v-for="item in list" :ref="setItemRef"></div>script:
import { ref, onBeforeUpdate, onUpdated } from 'vue' export default { setup() { let itemRefs = [] const setItemRef = el => { itemRefs.push(el) } onBeforeUpdate(() => { itemRefs = [] }) onUpdated(() => { console.log(itemRefs) }) return { itemRefs, setItemRef } } }
官方庫(kù)的支持情況
所有的官方庫(kù)和工具現(xiàn)在都支持 Vue 3,但大多數(shù)仍然處于 beta 狀態(tài),并在 NPM 的 next dist 標(biāo)簽下發(fā)。計(jì)劃在 2020 年底前穩(wěn)定所有項(xiàng)目,并將其轉(zhuǎn)換為使用 latest 的 dist 標(biāo)簽。
Vue Cli
從 v4.5.0 開始,vue-cli 現(xiàn)在提供了內(nèi)置選項(xiàng),可在創(chuàng)建新項(xiàng)目時(shí)選擇 Vue 3 預(yù)設(shè)?,F(xiàn)在可以升級(jí) vue-cli 并運(yùn)行 vue create 來創(chuàng)建 Vue 3 項(xiàng)目。
Vue Router
Vue Router 4.0 提供了 Vue 3 支持,并有許多突破性的變化。
Vuex
Vuex 4.0 提供了 Vue 3 支持,其 API 與 3.x 基本相同。唯一的突破性變化是插件的安裝方式。
Devtools Extension
正在開發(fā)一個(gè)新版本的 Devtools,目前只支持Vue 3。
IDE 支持
推薦使用 VSCode 和官方拓展 Vetur,Vetur為 Vue 3 提供了全面的 IDE 支持