10個常見的使用場景,助你從 Vue2 絲滑過渡到 Vue3 !

語言: CN / TW / HK

theme: cyanosis highlight: atom-one-dark


本文為稀土掘金技術社區首發簽約文章,14天內禁止轉載,14天后未獲授權禁止轉載,侵權必究!

相信有很多這樣的兄弟,學了 Vue3 的各種 API 和新特性,但公司項目依然使用的是 Vue2 ,也不知道自己的水平能否上手 Vue3 項目。其實你學的是零碎的知識點,缺少真實的使用場景。

今天就把實戰過程中遇到的十個場景分享給大家,結合尤大大推薦的 <script setup>,希望你能從 Vue2 絲滑過渡到 Vue3!

場景一:父子組件數據傳遞

父組件數據傳遞到子組件

Vue3 中父組件同樣是通過屬性傳遞數據,但子組件接受數據的方式和 Vue2 不同。在 <script setup> 中,props 需要使用 defineProps() 這個宏函數來進行聲明,它的參數和 Vue2 props 選項的值是一樣的。 ```js

```

```js

`` 注意:definePropsdefineEmitsdefineExposewithDefaults這四個宏函數只能在

```

```js

```

父組件使用子組件數據

在 <script setup> 中,組件的屬性和方法默認都是私有的。父組件無法訪問到子組件中的任何東西,除非子組件通過 defineExpose 顯式的暴露出去:

```js

```

```js

```

場景二:組件之間雙向綁定

大家都知道 Vue2 中組件的雙向綁定採用的是 v-model.snyc 修飾符,兩種寫法多少顯得有點重複,於是在 Vue3 中合成了一種。Vue3 統一使用 v-model 進行處理,並且可以和多個數據進行綁定,如 v-model:foov-model:bar

v-model 等價於 :model-value="someValue"@update:model-value="someValue = $event"

v-model:foo 等價於 :foo="someValue"@update:foo="someValue = $event"

下面就是一個父子組件之間雙向綁定的例子: ```js

```

```js

`` 子組件可以結合input` 使用:

```js

`` 如果你覺得上面的模板比較繁瑣,也可以結合computed` 一起使用:

```js

```

場景三:路由跳轉,獲取路由參數

在 Vue2 中我們通常是使用 this.$router 或 this.$route 來進行路由的跳轉和參數獲取,但在 <script-setup>中,是這些方法無法使用的。我們可以使用 vue-router 提供的 useRouter 方法,來進行路由跳轉:

```

`` 當我們要獲取路由參數時,可以使用vue-router提供的useRoute`方法:

```

```

場景四:獲取上下文對象

Vue3 的 setup 中無法使用 this 這個上下文對象。可能剛接觸 Vue3 的兄弟會有點懵,我想使用 this 上的屬性和方法應該怎麼辦呢。雖然不推薦這樣使用,但依然可以通過 getCurrentInstance 方法獲取上下文對象:

```js

`` 這樣我們就可以使用$parent$refs` 等,幹自己想幹的事情了,下面是我打印出來的完整屬性。

image.png

場景五:插槽的使用

在 Vue2 的中一般是通過 slot 屬性指定模板的位置,通過 slot-scope 獲取作用域插槽的數據,如:

```html

``` ```html ``` 在 Vue3 中則是通過 `v-slot` 這個指令來指定模板的位置,同時獲取作用域插槽的數據,如: ```html ``` ```html ``` 注意:`v-slot` 在 Vue2 中也可以使用,但必須是 Vue2.6+ 的版本。 ## 場景六:緩存路由組件 緩存一般的動態組件,Vue3 和 Vue2 的用法是一樣的,都是使用 `KeepAlive` 包裹 `Component`。但緩存路由組件,Vue3 需要結合插槽一起使用: ```js // Vue2 中緩存路由組件 ``` ```js // Vue3 中緩存路由組件 ``` 一個持續存在的組件可以通過 `onActivated()` 和 `onDeactivated()` 兩個生命週期鈎子注入相應的邏輯: ``` ``` ## 場景七:邏輯複用 Vue2 中邏輯複用主要是採用 `mixin`,但 `mixin` 會使數據來源不明,同時會引起命名衝突。所以 Vue3 更推薦的是全新的 `Composition Api`。 下面是鼠標跟蹤的例子,我們可以把邏輯提取出來: ```js // mouse.js import { ref, onMounted, onUnmounted } from 'vue' // 按照慣例,組合式函數名以 use 開頭 export function useMouse() { // 組合式函數管理的數據 const x = ref(0) const y = ref(0) function update(event) { x.value = event.pageX y.value = event.pageY } // 組合式函數可以掛靠在所屬組件的生命週期上,來啟動和卸載副作用 onMounted(() => window.addEventListener('mousemove', update)) onUnmounted(() => window.removeEventListener('mousemove', update)) // 通過返回值暴露所管理的數據 return { x, y } } ``` 這時候在組件中我們就可以直接使用 `mouse.js` 暴露的數據了。 ```js ``` 我們還可以在一個組件中引入多個組合式函數,或者在一個組合式函數中引入其他的組合式函數,這個比較簡單,我就不演示了。接下來,我們看看使用異步方法的組合式函數。 在做異步數據請求時,我們通常需要處理三個不同的狀態:加載中、加載成功和加載失敗。獲取這些狀態的邏輯是通用的,我們可以把它提取出來: ```js // request.js import { ref } from 'vue' export function useRequest(url) { const data = ref(null) const error = ref(null) axios.get(url) .then((res) => (data.value = res.data)) .catch((err) => (error.value = err)) return { data, error } } ``` 現在我們在組件中只需要: ```js ``` 任何組件都可以使用上面這個邏輯,這就是邏輯複用。是不是可以節省很多重複的代碼,感覺摸魚時間又要增加了~ ## 場景八:生命週期 Vue3 的生命週期和 Vue2 相比,有以下改動: - `Vue3` 生命週期鈎子都以 `on` 開頭,並且需要在組件中手動導入。 ``` ``` - Vue3 取消了 `beforeCreate` 和 `created` 鈎子。如果需要在組件創建前注入邏輯,直接在 ` ``` Vue3 中其他的全局 API,如 `directive` 、`component` 等,跟 Vue2 的用法都差不多,只不過一個是在 Vue 上調用,一個是在 `app` 實例上調用: ```js // main.js // 全局自定義指令 app.directive('focus', { mounted(el) { el.focus() } }) // 全局自定義組件 import CustomComp from './components/CustomComp.vue' app.component('CustomComp', CustomComp) ``` 需要注意的是,Vue3 廢棄了 `filter` 這個方法,因為通過函數或 `computed` 可以實現一樣的功能。 ## 常見十:與 TypeScript 結合使用 與 `TypeScript` 結合使用,我們只需要在 ` ``` 這被稱為 `運行時聲明` ,因為傳遞給 `defineProps()` 的參數會作為運行時的 props 選項使用。 - 基於類型的聲明。我們還可以通過泛型參數來定義 props 的類型,這種方式更加常用: ```ts ``` 這被稱為 `基於類型的聲明` ,編譯器會盡可能地嘗試根據類型參數推導出等價的運行時選項。這種方式的不足之處在於,失去了定義 props 默認值的能力。為了解決這個問題,我們可以使用 `withDefaults` 宏函數: ```ts ``` #### 為 ref() 標註類型 - 默認推導類型。ref 會根據初始化時的值自動推導其類型: ```ts import { ref } from 'vue' const year = ref(2022) year.value = '2022' // TS Error: 不能將類型 string 分配給類型 number ``` - 通過接口指定類型。有時我們可能想為 ref 內的值指定一個更復雜的類型,可以使用 `Ref` 這個接口: ```ts import { ref } from 'vue' import type { Ref } from 'vue' const year: Ref = ref('2022') year.value = 2022 // 成功! ``` - 通過泛型指定類型。我們也可以在調用 `ref()` 時傳入一個泛型參數,來覆蓋默認的推導行為: ```ts const year = ref('2022') year.value = 2022 // 成功! ``` #### 為 reactive() 標註類型 - 默認推導類型。`reactive()` 也會隱式地從它的參數中推導類型: ```ts import { reactive } from 'vue' const book = reactive({ title: 'Vue 3 指引' }) book.year = 2022 // TS Error: 類型 { title: string; } 上不存在屬性 year ``` - 通過接口指定類型。要顯式地指定一個 `reactive` 變量的類型,我們可以使用接口: ```ts import { reactive } from 'vue' interface Book { title: string year?: number } const book: Book = reactive({ title: 'Vue 3 指引' }) book.year = 2022 // 成功! ``` 其他 API 與 `TypeScript` 結合使用的方法和上面大同小異,這裏我就不一一列舉了。具體可以參考這篇文章:[如何為 Vue3 組件標註 TS 類型,看這個就夠了!](http://juejin.cn/post/7129130323148800031)。 ## 小結 以上就是我在 Vue3 項目中遇到最多的場景,如果你掌握了 Vue3 常用的 API 和今天這些場景,相信參與 Vue3 項目的開發是沒有問題了。當然如果要用好 Vue3 ,可能還需要對 `Pinia` 、 `Vite` 等相關生態有一個深入的瞭解。後面我也會持續分享 Vue3 的使用技巧及相關生態,希望你儘早掌握 Vue3! 有問題歡迎在評論區留言,如果覺得今天的分享對你有所幫助,記得點贊支持一下!😊 參考文檔:[Vue3 官網](http://cn.vuejs.org/guide/introduction.html)