Vue 3.0 新特性及使用方法

介紹

2020年9月19日凌晨,尤雨溪大大正式發布了 Vue.js 3.0 版本,代號:One Piece。此框架新的主要版本提供了更好的性能、更小的捆綁包體積、更好的 TypeScript 集成、用于處理大規模用例的新 API,并為框架未來的長期迭代奠定了堅實的基礎。

3.0 版本的開發周期長達兩年多,期間產生了 30+ RFCs、2600+ commits、628 pull requests,以及核心倉庫之外的大量開發和文檔工作。

Vue 3.0 的發布標志著此框架整體上已處于可用狀態。盡管框架的某些子項目可能仍需要進一步的開發才能達到穩定狀態(特別是 devtools 中的路由和 Vuex 集成),不過現在仍然是開始使用 Vue 3 啟動新項目的合適時機。官方還鼓勵庫作者現在可以開始升級項目以支持 Vue 3。

what is RFC?

RFC(Request For Comments) - 即請求評議,旨在為新功能進入框架提供一致且受控的路徑。

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 為新功能的引入提供了統一可控的途徑,利于在Vue核心團隊和社區中進行方案的討論和優化,最終達成共識。

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中包含一個 RFC的markdown文件(非實際代碼),經過討論后核心團隊最終將決定是否接受或拒絕該RFC。RFC的提出者并不一定需要自己去實現它(當然歡迎實現)。

Vue RFCs 倉庫

創建Vue3.0項目

  • 通過腳手架 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的組件庫

目前基于Vue的第三方組件庫兼容Vue 3的情況:

Ant Design Vue:支持 Vue 3.0 的 2.0.0 測試版已發布

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 項目升級為 Vue3.x項目

最簡單的方法,就是使用vue-cli 3.0,創建一個新的項目,然后將原有的項目源碼拷到新的項目中。

Vue3中兼容Vue2中定義組件的寫法,所以只需要將入口文件 main.js 中創建Vue實例的代碼替換為使用Vue3中新引入的 createApp方法,來創建應用程序實例的方式即可。

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):

當組件變得越來越大時,邏輯關注點的列表也會增長。這可能會導致組件難以閱讀和理解,且碎片化使得理解和維護復雜組件變得困難。選項的分離掩蓋了潛在的邏輯問題。此外,在處理單個邏輯關注點時,我們必須不斷地“跳轉”相關代碼的選項塊。

如果能夠將與同一個邏輯關注點相關的代碼配置在一起會更好,于是 Composition API 應運而生。

使用Composition api的位置被稱為setup

setup組件選項

setup 組件選項在創建組件之前執行,一旦 props 被解析,并充當合成 API 的入口點。

注意:由于在執行 setup 時尚未創建組件實例,因此在 setup 選項中沒有 this。這意味著,除了 props 之外,你將無法訪問組件中聲明的任何屬性——本地狀態、計算屬性或方法。

// 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([]) // 定義一個變量
      const getUserRepositories = async () => { // 定義一個方法
        repositories.value = await fetchUserRepositories(props.user)
      }

      onMounted(getUserRepositories) // 生命周期鉤子 當實例mounted后調用getUserRepositories方法

      return {
        repositories, // 返回一個data
        getUserRepositories // 返回一個method
      }
    }
}

單文件組件 Composition API 語法糖 (<script setup>):

當組件可以使用組合API后,setup往往成為了唯一會用到的組件屬性,因此利用語法糖簡化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 語法糖:
<script setup>
  import { ref } from 'vue'

  export const count = ref(0)
  export const inc = () => count.value++
</script>

單文件組件狀態驅動的 CSS 變量 (<style vars>):

有能力在運行時根據組件狀態來動態更新樣式

<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> 現在可以包含全局規則或只針對插槽內容的規則:

帶有scoped屬性的style 不再只能作用域當前單文件組件,通過深度選擇器、插槽選擇器、全局選擇器擁有了更改其他范圍樣式的能力。

<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

背景:

從技術上講,Vue 2 沒有“app”的概念,我們定義的應用程序只是通過 new Vue() 創建的根 Vue 實例。從同一個 Vue 構造函數創建的每個根實例共享相同的全局配置,因此全局配置使得在測試期間很容易意外地污染其他測試用例。用戶需要仔細存儲原始全局配置,并在每次測試后恢復 (例如重置 Vue.config.errorHandler)。有些 API 像 Vue.use 以及 Vue.mixin 甚至連恢復效果的方法都沒有,這使得涉及插件的測試特別棘手。

createApp:

import { createApp } from 'vue'

const app = createApp({})

調用 createApp 返回一個應用實例,應用程序實例暴露當前全局 API 的子集,任何全局改變 Vue 行為的 API 現在都會移動到應用實例上,以下是當前全局 API 及其相應實例 API 的表:

[圖片上傳失敗...(image-c4a9d6-1601349914900)]

所有其他不全局改變行為的全局 API 現在被命名為 exports。

全局和內部API已重構為可 tree-shakable

Tree shaking 是一個通常用于描述移除 JavaScript 上下文中的未引用代碼(dead-code) 行為的術語。
它依賴于ES2015中的 import 和 export 語句,用來檢測代碼模塊是否被導出、導入,且被 JavaScript 文件使用。
在現代 JavaScript 應用程序中,我們使用模塊打包(如webpack或Rollup)將多個 JavaScript 文件打包為單個文件時自動刪除未引用的代碼。這對于準備預備發布代碼的工作非常重要,這樣可以使最終文件具有簡潔的結構和最小化大小。

2.x 語法:

// 全局 API Vue.nextTick() 不能tree-shaking
import Vue from 'vue'

Vue.nextTick(() => {
  // 一些和DOM有關的東西
})

3.x語法:

全局 API 現在只能作為 ES 模塊構建的命名導出進行訪問,如果模塊綁定器支持 tree-shaking,則 Vue 應用程序中未使用的全局 api 將從最終捆綁包中消除,從而獲得最佳的文件大小。

import { nextTick } from 'vue'

nextTick(() => {
  // 一些和DOM有關的東西
})

受影響的API:

  • Vue.nextTick
  • Vue.observable (用Vue.reactive替換)
  • Vue.version
  • Vue.compile
  • Vue.set
  • Vue.delete

組件上 v-model 用法已更改

  • 自定義v-model時,prop和事件默認名稱已更改:
    prop: value -> modelValue
    event: input -> update:modelValue
  • .sync和組件的model選項已移除,可用v-model作為替代
  • 現在可以在同一個組件上使用多個 v-model 進行雙向綁定;
  • 現在可以自定義 v-model 修飾符
    比如自定義v-model.capitalize,綁定為字符串第一個字母的大寫

<template v-for> 和非 - v-for 節點上 key 用法已更改

  • Vue 2.x 建議在 v-if/v-else/v-else-if 的分支中使用 key,Vue 3.x 中仍能正常工作,但不再建議,因為沒有為條件分支提供 key 時,也會自動生成唯一的 key。

  • 在 Vue 2.x 中 <template> 標簽不能擁有 key,在 Vue 3.x 中 key 則應該被設置在 <template> 標簽上。

在同一元素上使用的 v-if 和 v-for 優先級已更改

  • Vue 3.x 中v-if 會擁有比 v-for 更高的優先級。
    由于語法上存在歧義,建議避免在同一元素上同時使用兩者,比如利用計算屬性篩選出列表。

v-bind="object" 現在排序敏感

  • Vue 2.x 如果一個元素同時定義了 v-bind="object" 和一個相同的單獨的 property,那么這個單獨的 property 總是會覆蓋 object 中的綁定。
  • Vue 3.x 聲明綁定的順序決定了它們如何合并。
// 2.x中 id最終為red  3.x中 id為blue
<div id="red" v-bind="{ id: 'blue' }"></div>

v-for 中的 ref 不再注冊 ref 數組

  • Vue 2 中,在 v-for 里使用 ref屬性時,從$refs中獲取的相應屬性會是一個ref數組。

  • Vue 3中則將ref綁定到一個更靈活的函數上 (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
        }
      }
    }
    

官方庫的支持情況

所有的官方庫和工具現在都支持 Vue 3,但大多數仍然處于 beta 狀態,并在 NPM 的 next dist 標簽下發。計劃在 2020 年底前穩定所有項目,并將其轉換為使用 latest 的 dist 標簽。

Vue Cli

從 v4.5.0 開始,vue-cli 現在提供了內置選項,可在創建新項目時選擇 Vue 3 預設。現在可以升級 vue-cli 并運行 vue create 來創建 Vue 3 項目。

Vue Router

Vue Router 4.0 提供了 Vue 3 支持,并有許多突破性的變化。

Vuex

Vuex 4.0 提供了 Vue 3 支持,其 API 與 3.x 基本相同。唯一的突破性變化是插件的安裝方式。

Devtools Extension

正在開發一個新版本的 Devtools,目前只支持Vue 3。

IDE 支持

推薦使用 VSCode 和官方拓展 Vetur,Vetur為 Vue 3 提供了全面的 IDE 支持

參考

vue3 中文文檔

vue-router 4.0 英文文檔

Vuex 4 README

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380