Vue3 + TypeScript 開(kāi)發(fā)實(shí)踐總結(jié)

遲來(lái)的Vue3文章,其實(shí)早在今年3月份時(shí)就把Vue3過(guò)了一遍。
在去年年末又把 《 TypeScript 》 重新學(xué)了一遍,為了上Vue3 的車(chē),更好的開(kāi)車(chē)。
在上家公司4月份時(shí),上級(jí)領(lǐng)導(dǎo)分配了一個(gè)內(nèi)部的 黨務(wù)系統(tǒng)開(kāi)發(fā) ,這個(gè)系統(tǒng)前端是由我一個(gè)人來(lái)開(kāi)發(fā),功能和需求也不怎么復(fù)雜的一個(gè)B 端 系統(tǒng),直接上的 Vue3 + TypeScript + Element Plus 開(kāi)發(fā)的,開(kāi)發(fā)兩周到最后的上線,期間也遇到很多小坑,很多無(wú)處可查,慢慢琢磨最后還是克服了。
Vue3 + TypeScript Study
一, 環(huán)境配置
1.1 安裝最新 Vue 腳手架
npm install -g @vue/cli
yarn global add @vue/cli
1.2 創(chuàng)建Vue3 項(xiàng)目
vue create projectName
1.3 現(xiàn)有Vue 2 項(xiàng)目 升級(jí)到 Vue3
vue add typescript
二, 進(jìn)擊Vue3
2. 1 Vue 2 局限性
隨著組件與組件依賴之間不斷變大,組件很難讀取和維護(hù)
沒(méi)有完美的方法解決跨組件代碼重用
2.2 Vue 3 如何解決Vue 2 局限
組件難以維護(hù)管理
【在Vue3 中 編寫(xiě)組合函數(shù),使用 Compositon Api setUp 來(lái)解決】
沒(méi)有完美的方法解決跨組件代碼重用
三,Vue3 Composition Ap i
3.1 關(guān)于 Composition Api
在Vue3中,也可以不使用 Composition Api 來(lái)編寫(xiě)組件,它只是在Vue3 中編寫(xiě)組件中的另一種方法,內(nèi)部簡(jiǎn)化了好多操作。
所以你還可以繼續(xù)使用 Vue2 的方式來(lái) 編寫(xiě) 組件。
3.2 什么時(shí)候使用Composition Api
TypeScript 的支持
編寫(xiě)大型組件時(shí),可以使用
Composition Api組合函數(shù)很好的管理狀態(tài)跨組件重用代碼時(shí)
四,Composition Api 必備基礎(chǔ)
4.1 什么是 setup
setup 是用來(lái)配置組件狀態(tài)的另一種實(shí)現(xiàn)。
在setup 中定義的狀態(tài),方法要想在模板中使用,必須 return
注意:
setup方法是在components,propsdataMethodsComputedLifecycle methods之前執(zhí)行同時(shí)在 setup中是不能訪問(wèn)this
4.2 ref 創(chuàng)建響應(yīng)式變量
在 Vue2 中,我們定義一個(gè)響應(yīng)式變量可以直接在 data 中 定義并且在模板中使用該變量。如果 使用的 composition api 的話,我們得在 setup 中 使用 ref 來(lái)創(chuàng)建 響應(yīng)式變量,并且得將它返回,才能在頁(yè)面中使用。
使用
引入 refimport { ref } from 'vue'初始變量 const name = ref('指定默認(rèn)值')返回變量 return { name }在return中還可以返回方法在 setup中 訪問(wèn) 定義的變量值,不能直接通過(guò)變量名來(lái)獲取,必須通過(guò) 變量名.value 來(lái)獲取到該對(duì)象 、 值
這樣的好處
狀態(tài)好管理,可以劃分好幾個(gè) setup狀態(tài)管理,最后在一個(gè) 文件導(dǎo)入所有,并且使用。
<template>
<div>
<h1>{{title}}</h1>
</div>
</template>
<script>
import {ref,defineComponent} from 'vue'
export default defineComponent({
setup () {
// 定義響應(yīng)式變量
const title = ref('前端自學(xué)社區(qū)')
// 訪問(wèn)該變量
console.log(title.value)
// 返回變量
return {title}
}
})
</script>
4.3 生命周期
Composition Api生命周期鉤子 和 Vue 2 選項(xiàng)式 生命周期鉤子名稱一樣,只是在使用 組合式API時(shí),前綴為 on, onMounted`
sd
下面代碼中有兩個(gè) mounted 生命鉤子,你猜哪個(gè)會(huì)先執(zhí)行?
setup會(huì)先執(zhí)行
setup () {
// 定義響應(yīng)式變量
const title = ref('前端自學(xué)社區(qū)')
console.log(title)
// 返回變量
function getTitle(){
console.log(title.value)
}
// 頁(yè)面在加載
onMounted(getTitle)
return {title}
},
mounted() {
console.log('測(cè)試 mounted 執(zhí)行順序')
},
4.4 watch
在 setup 中使用 watch響應(yīng)式更改
引入 watch,
import { watch } from 'vue'直接使用watch,watch 接受 3 個(gè)參數(shù)
要監(jiān)聽(tīng)更新的 響應(yīng)式引用或者 getter 函數(shù) 一個(gè)回調(diào)用來(lái)做更新后的操作 可選配置項(xiàng)
import {wathc} from 'vue'
// 定義響應(yīng)式變量
const num = ref(0)
// 更新響應(yīng)式變量
function changeNum(){
num.value++
}
// wathc 監(jiān)聽(tīng)響應(yīng)式變量
watch(
num,(newValue, oldValue) => {
console.log(`newValue為:${newValue},--------oldValue為:${oldValue}`)
}
)
4.5 computed
它也是 從 vue 導(dǎo)入,computed 函數(shù)返回一個(gè)作為 computed 的第一個(gè)參數(shù)傳遞的 getter 類(lèi)回調(diào)的輸出的一個(gè)只讀的響應(yīng)式引用。為了訪問(wèn)新創(chuàng)建的計(jì)算變量的 value,我們需要像使用 ref 一樣使用 .value property。
當(dāng)num值變化時(shí),nums 的值會(huì) 3
import {ref,computed} from 'vue';
const num = ref(0)
//更新num
function changeNum(){
num.value++
}
//監(jiān)聽(tīng)num變化
const nums = computed(() =>{
return num.value * 3
})
五,setup
5.1 接受兩個(gè)參數(shù)
props: 父組件傳遞過(guò)來(lái)的屬性, setup` 函數(shù)中 props 是響應(yīng)式的,它會(huì)隨著數(shù)據(jù)更新而更新,并且不能使用 ES6 解構(gòu),因?yàn)樗鼤?huì)不能使 props 為響應(yīng)式。
context : 它是一個(gè)普通的 對(duì)象,它暴露3個(gè)組件的· property
Attribute 插槽 觸發(fā)事件
context 不是 響應(yīng)式的,所以可以使用ES6 解構(gòu)來(lái)簡(jiǎn)便寫(xiě)法。
props:{
obj:{
type:Object
}
},
setup (props,{attrs,slots,emit}) {
console.log(attrs)
console.log(slots)
console.log(emit)
console.log(props.obj)
}
5.2 組件加載 setup 時(shí)注意
在組件執(zhí)行 setup 時(shí), 組件實(shí)例沒(méi)有被創(chuàng)建,因此就無(wú)法訪問(wèn)以下屬性
datacomputedmethods
六,生命周期
在 setup 中使用 生命周期時(shí),前綴必須加 on.
| 選項(xiàng)式 API | Hook inside setup |
|---|---|
beforeCreate | |
created | |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
errorCaptured | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
七, 跨組件之間傳值
在 Vue 2 中,我們可以使用 Provide/Inject 跨組件傳值,在 Vue 3 中也可以。
在 setup 中 使用,必須從 vue 中導(dǎo)入使用。
使用 Provide 時(shí),一般設(shè)置為 響應(yīng)式更新的,這樣的話,父組件變更,子組件,子孫組件也跟著更新。
怎么設(shè)置為響應(yīng)式更新呢?
使用 ref/reactive創(chuàng)建響應(yīng)式變量使用 provide('name', '要傳遞的響應(yīng)式變量')最后添加一個(gè)更新 響應(yīng)式變量的事件,這樣響應(yīng)式變量更新, provide中的變量也跟著更新。
父組件
父組件
import { provide, defineComponent, ref, reactive } from "vue";
<template>
<Son/>
</template>
<script>
import { provide, defineComponent, ref, reactive } from "vue";
export default defineComponent({
setup() {
const father = ref("我父組件");
const info = reactive({
id: 23,
message: "前端自學(xué)社區(qū)",
});
function changeProvide(){
info.message = '測(cè)試'
}
provide('father',father)
provide('info',info)
return {changeProvide};
}
})
</script>
子組件
<template>
<div>
<h1>{{info.message}}</h1>
<h1>{{fatherData}}</h1>
</div>
</template>
<script>
import {provide, defineComponent,ref,reactive, inject} from 'vue'
export default defineComponent({
setup () {
const fatherData = inject('father')
const info = inject('info')
return {fatherData,info}
}
})
</script>
八, 在Vue 中 使用 TypeScirpt 技巧
8.1 接口約束約束屬性
采用
TypeScirpt的特性, 類(lèi)型斷言 + 接口 完美的對(duì) 屬性進(jìn)行了 約束
interface
分頁(yè)查詢 字段屬性類(lèi)型驗(yàn)證
export default interface queryType{
page: Number,
size: Number,
name: String,
age: Number
}
組件中使用
import queryType from '../interface/Home'
data() {
return {
query:{
page:0,
size:10,
name:'測(cè)試',
age: 2
} as queryType
}
},
8.2 組件使用 來(lái) defineComponent 定義
這樣
TypeScript正確推斷Vue組件選項(xiàng)中的類(lèi)型
import { defineComponent } from 'vue'
export default defineComponent({
setup(){
return{ }
}
})
8.3 類(lèi)型聲明 reactive
export default interface Product {
name:String,
price:Number,
address:String
}
import Product from '@/interface/Product'
import {reactive} from 'vue'
const product = reactive({name:'xiaomi 11',price:5999,address:'北京'}) as Product
return {fatherData,info,product}

