通過範例瞭解vue3.3更新的特徵

2023-06-01 21:00:55

開場白

5月份,vue團隊釋出了 vue3.3.
這次小版本的釋出主要解決了--
Vue 與 TypeScript 一起使用時的許多長期存在的痛點.
下面我們一起來學習一下vue3.3新特徵

準備新新特徵的環境

根據官方團隊的描述,我們需要準備一下工作。
vue升級到 3.3 時,建議同時更新以下依賴項:
Volar / vue-tsc@^1.6.4 
vite@^4.3.5
@vitejs/plugin-vue@^4.2.0
vue-loader@^17.1.0 (如果使用 webpack 或 vue-cli)

使用vite來學習vue3.3的新特徵

1.yarn create vite      建立vite專案
2.輸出專案名
3.選擇包名
4.選擇vue
5.選擇ts

外掛

Vue Language Features (Volar) 需要版本 v1.7.2以上
你可以點選設定小圖示 然後選擇切換版本
也可安裝一下 TypeScript Vue Plugin (Volar) 外掛

script setup + TypeScript 開發體驗改善

在3.3以前,defineProps 和 defineEmits 的使用型別僅限於本地型別,並且僅支援型別文字和介面。
這是因為 Vue 需要能夠分析 props 介面上的屬性,以便生成相應的執行時選項。
現已在 3.3 中解決。編譯器現在可以解析匯入的型別,並支援一組有限的複雜型別:

解析匯入的型別,並支援有限的複雜型別

//hello.ts檔案
// 給HelloWord元件定義型別
export interface HelloPerson {
  name: string;
  age: number;
  likeArr: string[]
}
//HelloWorld.vue檔案
<template>
  <div class="card">
    <p>姓名 {{ name }}</p>
    <p>年齡 {{ age }}</p>
    <p>愛好 {{ likeArr }}</p>
  </div>
</template>

<script setup lang="ts">
//匯入我們定義的型別
import { HelloPerson } from './hello'
// 使用定義的型別
defineProps<HelloPerson>()
</script>
//在頁面中使用
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
</script>
<template>
  <div>
    <HelloWorld name="張三" :age="19" :likeArr="['打豆豆','挖呀挖']" />
  </div>
</template>



需要注意的點

1.元件中 defineProps我使用的是介面 interface 定義。
所以使用元件的時候介面中的引數必須要有,否者會有紅色波浪線。
但在實際的場景中,我們有可能不需每一個引數。
為了解決這個上述問題。
我們需要將 interface 中的欄位改為可選。使用 ? 還處理。
變為下面的樣子就可以了。


// 給HelloWord元件定義型別
//  ? 表示該欄位可以有也可以沒有
export interface HelloPerson {
  name?: string;
  age?: number;
  likeArr?: string[]
}

型別的擴充套件

有些時候我們還需要進行型別的擴充套件。
HelloPerson介面中沒有我們需要的型別。
我們可以自己進行擴充套件,現在我們擴充套件一個其他型別
otherProp 為字串,同樣的這個型別是可有可無的
<script setup lang="ts">
//匯入我們定義的型別
import { HelloPerson } from './hello'
// 使用定義的型別 同時還擴充套件了otherProp型別為字串。
// 同樣的這個型別是可有可無的
defineProps<HelloPerson & { otherProp?: string }>()
</script>

需要注意的點

需要注意的是,複雜型別支援是基於 AST 的,因此不是 100% 全面的。
不支援一些需要實際型別分析的複雜型別,例如條件型別。
我們可以將條件型別用於單個 props 的型別,
但不能對整個 props 物件使用。

通用元件-元件可以接收泛型引數

有些時候我們不知道,傳遞過來的是什麼型別。
這個時候我們就可以使用泛型了。
// Hi元件
<template>
  <div class="card">
    <p>愛好 {{ likeArr }}</p>
    <p>性別 {{ sex }}</p>
  </div>
</template>

<script setup lang="ts" generic="T">
defineProps<{
  likeArr: T[]
  sex: T
}>()
</script>
<script setup lang="ts">
import Hi from './components/Hi.vue'
let likeArr = ['摸魚','睡覺']
</script>
<template>
  <div>
    // 在使用的時候會自動推導型別的
    <Hi :likeArr="likeArr" sex="男"/>
  </div>
</template>

多個泛型

多個泛型使用逗號隔開,於此同時,也是可以繼承的
<template>
  <div class="card">
    <p>愛好 {{ likeArr }}</p>
    <p>性別 {{ sex }}</p>
    <p>年齡 {{ age }}</p>
  </div>
</template>

<script setup lang="ts" generic="T,U extends number">
// 讓U這個泛型繼承數位
defineProps<{
  likeArr: T[]
  sex: T,
  age: U
}>()
</script>
<script setup lang="ts">
import Hi from './components/Hi.vue'
let likeArr = ['摸魚','睡覺']
</script>
<template>
  <div>
    <Hi :likeArr="likeArr" sex="男" :age="10" />
  </div>
</template>
<style scoped>

defineEmits的優化--現在

<template>
  <div class="card">
   <button @click="handlerSay">說</button>
   <button @click="handlerWrite">寫</button>
  </div>
</template>

<script setup lang="ts" generic="T,U extends number">
const emit = defineEmits<{
  //這裡的id是自定義的,你也可以叫其他
  foo: [id: number];  
  //這裡的name, age是自定義的,你也可以叫其他
  bar:[name:string, age:number]
}>()
function handlerSay() {
  emit('foo',1)
}
function handlerWrite() {
  emit('bar',  '張三', 19)
}
</script>
<script setup lang="ts">
import Say from './components/Say.vue'
function bar(a,b) {
  console.log(a,b)
}
</script>
<template>
  <div>
    <Say @bar="bar" />
  </div>
</template>

defineEmits以前的寫法

<template>
  <div class="card">
   <button @click="handlerSay">說</button>
   <button @click="handlerWrite">寫</button>
  </div>
</template>


const emit = defineEmits<{
  (e: 'foo', id: number): void
  (e: 'bar', name: string,  age: number): void
}>()

function handlerSay() {
  emit('foo',1)
}
function handlerWrite() {
  emit('bar',  '張三', 19)
}

尾聲

如果你覺得我寫的不錯的話,請給在下方給我點一下推薦。謝謝啦。
如果這篇文章幫助你了,請給打賞。謝謝。
我敢保證,打賞點讚的今年都可以找到女朋友