1. 程式人生 > 其它 >Vue 3.0 新特性及使用方法

Vue 3.0 新特性及使用方法

Vue 3.0 新特性及使用方法

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 支援