Vue3結(jié)合TypeScript項(xiàng)目開(kāi)發(fā)實(shí)戰(zhàn)記錄
概述
Vue3出來(lái)已經(jīng)有一段時(shí)間了,在團(tuán)隊(duì)中,也進(jìn)行了大量的業(yè)務(wù)實(shí)踐,也有了一些自己的思考。
總的來(lái)說(shuō),Vue3無(wú)論是在底層的原理上,還是在業(yè)務(wù)的實(shí)際開(kāi)發(fā)中,都有了長(zhǎng)足的進(jìn)步。
使用 proxy 代替之前的 Object.defineProperty 的API,性能更加優(yōu)異,也解決了之前vue在處理對(duì)象、數(shù)組上的缺陷;在diff算法上,使用了靜態(tài)標(biāo)記的方式,大大提升了Vue的執(zhí)行效率。
在使用的層面,我們從options Api,變成了composition Api,慢慢的在實(shí)際的業(yè)務(wù)中,我們拋棄了原本的data、methods、computed那種隔離式的寫(xiě)法。compositon Api,它更加聚焦,它講究的是相關(guān)業(yè)務(wù)的聚合性。同時(shí),在composition Api中,為了防止過(guò)于重的業(yè)務(wù)邏輯,它提供了一種關(guān)注點(diǎn)分離的方式,大大的提升了我們代碼的可讀性。
完全良好的支持了TypeScript,類(lèi)型校驗(yàn)也成為了以后Vue3進(jìn)行大型項(xiàng)目開(kāi)發(fā)的質(zhì)量保障,同時(shí)這也是面向了趨勢(shì) -- 前端的未來(lái)就是TypeScript!
1、compositon Api
compositon Api的本質(zhì),體現(xiàn)在代碼里面,也就是一個(gè)setup函數(shù),在這個(gè)setup函數(shù)中,返回的數(shù)據(jù),會(huì)用到該組件的模板中。return的這個(gè)對(duì)象,一定程度上,代表了之前vue2中的data屬性。
import { defineComponent, ref } from 'vue'; export default defineComponent({ name: 'Gift', setup() { const counter = ref(0); return { counter } } })
這時(shí)候,對(duì)于大多數(shù)初學(xué)者來(lái)說(shuō),可能存在的疑惑就是,那么我能不能定義options Api的寫(xiě)法,比如data、computed、watch、methods等等。
這里我需要明確的是,Vue3是完全兼容Vue2的這種options Api的寫(xiě)法,但是從理念上來(lái)說(shuō),更加推薦setup的方式,來(lái)寫(xiě)我們的組件。原因如下:Vue3的存在,本身是為了解決Vue2的問(wèn)題的,Vue2的問(wèn)題就是在于,聚合性不足,會(huì)導(dǎo)致代碼越來(lái)越臃腫!setup的方式,能夠讓data、方法邏輯、依賴(lài)關(guān)系等聚合在一塊,更方便維護(hù)。
也就是說(shuō),以后我們盡量不要寫(xiě)單獨(dú)的data、computed、watch、methods等等,不是Vue3不支持,而是和Vue3的理念違背。
components屬性,也就是一個(gè)組件的子組件,這個(gè)配置在Vue2和3的差異不大,Vue2怎么用,Vue3依然那么用。
1、ref 和 reactive的區(qū)別?
在功能方面,ref 和 reactive,都是可以實(shí)現(xiàn)響應(yīng)式數(shù)據(jù)!
在語(yǔ)法層面,兩個(gè)有差異。ref定義的響應(yīng)式數(shù)據(jù)需要用[data].value的方式進(jìn)行更改數(shù)據(jù);reactive定義的數(shù)據(jù)需要[data].[prpoerty]的方式更改數(shù)據(jù)。
const actTitle: Ref<string> = ref('活動(dòng)名稱(chēng)'); const actData = reactive({ list: [], total: 0, curentPage: 1, pageSize: 10 }); actTitle.value = '活動(dòng)名稱(chēng)2'; actData.total = 100;
但是在應(yīng)用的層面,還是有差異的,通常來(lái)說(shuō):?jiǎn)蝹€(gè)的普通類(lèi)型的數(shù)據(jù),我們使用ref來(lái)定義響應(yīng)式。表單場(chǎng)景中,描述一個(gè)表單的key:value這種對(duì)象的場(chǎng)景,使用reactive;在一些場(chǎng)景下,某一個(gè)模塊的一組數(shù)據(jù),通常也使用reactive的方式,定義數(shù)據(jù)。
那么,對(duì)象是不是非要使用reactive來(lái)定義呢?其實(shí)不是的,都可以,根據(jù)自己的業(yè)務(wù)場(chǎng)景,具體問(wèn)題具體分析!ref他強(qiáng)調(diào)的是一個(gè)數(shù)據(jù)的value的更改,reactive強(qiáng)調(diào)的是定義的對(duì)象的某一個(gè)屬性的更改。
2、周期函數(shù)
周期函數(shù),在Vue3中,是被單獨(dú)使用的,使用方式如下:
import { defineComponent, ref, onMounted } from 'vue'; export default defineComponent({ name: 'Gift', setup() { const counter = ref(0); onMounted(() => { // 處理業(yè)務(wù),一般進(jìn)行數(shù)據(jù)請(qǐng)求 }) return { counter } } })
3、store使用
在Vue2中,其實(shí)可以直接通過(guò)this.$store進(jìn)行獲取,但是在Vue3中,其實(shí)沒(méi)有this這個(gè)概念,使用方式如下:
import { useStore } from "vuex"; import { defineComponent, ref, computed } from 'vue'; export default defineComponent({ name: 'Gift', setup() { const counter = ref(0); const store = useStore(); const storeData = computed(() => store); // 配合computed,獲取store的值。 return { counter, storeData } } })
4、router的使用
在Vue2中,是通過(guò)this.$router的方式,進(jìn)行路由的函數(shù)式編程,但是Vue3中,是這么使用的:
import { useStore } from "vuex"; import { useRouter } from "vue-router"; import { defineComponent, ref, computed } from 'vue'; export default defineComponent({ name: 'Gift', setup() { const counter = ref(0); const router = useRouter(); const onClick = () => { router.push({ name: "AddGift" }); } return { counter, onClick } } })
2、關(guān)注點(diǎn)分離
關(guān)注點(diǎn)分離,應(yīng)該分兩層意思:第一層意思就是,Vue3的setup,本身就把相關(guān)的數(shù)據(jù),處理邏輯放到一起,這就是一種關(guān)注點(diǎn)的聚合,更方便我們看業(yè)務(wù)代碼。
第二層意思,就是當(dāng)setup變的更大的時(shí)候,我們可以在setup內(nèi)部,提取相關(guān)的一塊業(yè)務(wù),做到第二層的關(guān)注點(diǎn)分離。
import { useStore } from "vuex"; import { useRouter } from "vue-router"; import { defineComponent, ref, computed } from 'vue'; import useMerchantList from './merchant.js'; export default defineComponent({ name: 'Gift', setup() { const counter = ref(0); const router = useRouter(); const onClick = () => { router.push({ name: "AddGift" }); } // 在該示例中,我們把獲取商家列表的相關(guān)業(yè)務(wù)分離出去。也就是下面的merchant.ts const {merchantList} = useMerchantList(); return { counter, onClick, merchantList } } })
merchant.ts
import { getMerchantlist } from "@/api/rights/gift"; import { ref, onMounted } from "vue"; export default function useMerchantList(): Record<string, any> { const merchantList = ref([]); const fetchMerchantList = async () => { let res = await getMerchantlist({}); merchantList.value = res?.data?.child; }; onMounted(fetchMerchantList); return { merchantList }; }
3、TypeScript支持
這一部分內(nèi)容,準(zhǔn)確的來(lái)說(shuō),是TS的內(nèi)容,不過(guò)它與Vue3項(xiàng)目開(kāi)發(fā),息息相關(guān),所以真的想用Vue3,我們還是得了解TS的使用。
不過(guò)這一部分,我不會(huì)介紹TS的基礎(chǔ)語(yǔ)法,主要是在業(yè)務(wù)場(chǎng)景中,如何組織TS。
使用TS進(jìn)行業(yè)務(wù)開(kāi)發(fā),一個(gè)核心的思維是,先關(guān)注數(shù)據(jù)結(jié)構(gòu),再根據(jù)數(shù)據(jù)結(jié)構(gòu)進(jìn)行頁(yè)面開(kāi)發(fā)。以前的前端開(kāi)發(fā)模式是,先寫(xiě)頁(yè)面,后關(guān)注數(shù)據(jù)。
比如要寫(xiě)一個(gè)禮品列表的頁(yè)面,我們可能要定義這么一些interface??偠灾?,我們需要關(guān)注的是:頁(yè)面數(shù)據(jù)的interface、接口返回的數(shù)據(jù)類(lèi)型、接口的入?yún)㈩?lèi)型等等。
// 禮品創(chuàng)建、編輯、列表中的每一項(xiàng),都會(huì)是這個(gè)數(shù)據(jù)類(lèi)型。 interface IGiftItem { id: string | number; name: string; desc: string; [key: string]: any; } // 全局相應(yīng)的類(lèi)型定義 // 而且一般來(lái)說(shuō),我們不確認(rèn),接口返回的類(lèi)型到底是什么(可能是null、可能是對(duì)象、也可能是數(shù)組),所以使用范型來(lái)定義interface interface IRes<T> { code: number; msg: string; data: T } // 接口返回?cái)?shù)據(jù)類(lèi)型定義 interface IGiftInfo { list: Array<IGiftItem>; pageNum: number; pageSize: number; total: number; }
在一個(gè)常見(jiàn)的接口請(qǐng)求中,我們一般使用TS這么定義一個(gè)數(shù)據(jù)請(qǐng)求,數(shù)據(jù)請(qǐng)求的req類(lèi)型,數(shù)據(jù)請(qǐng)求的res類(lèi)型。
export const getGiftlist = ( params: Record<string, any> ): Promise<IRes<IGiftInfo>> => { return Http.get("/apis/gift/list", params); };
總結(jié)
到此這篇關(guān)于Vue3結(jié)合TypeScript項(xiàng)目開(kāi)發(fā)實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Vue3結(jié)合TS項(xiàng)目開(kāi)發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue項(xiàng)目中掃碼支付的實(shí)現(xiàn)示例(附demo)
本文主要介紹了vue項(xiàng)目中掃碼支付的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Vue實(shí)現(xiàn)點(diǎn)擊當(dāng)前元素以外的地方隱藏當(dāng)前元素(實(shí)現(xiàn)思路)
這篇文章主要介紹了Vue實(shí)現(xiàn)點(diǎn)擊當(dāng)前元素以外的地方隱藏當(dāng)前元素,文中給大家擴(kuò)展了vue實(shí)現(xiàn)點(diǎn)擊其他地方隱藏div的三種方法,需要的朋友可以參考下2019-12-12vue如何將字符串的一部分處理為html文檔并渲染到頁(yè)面
這篇文章主要介紹了vue如何將字符串的一部分處理為html文檔并渲染到頁(yè)面,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06vue3中update:modelValue的使用與不生效問(wèn)題解決
現(xiàn)在vue3的使用越來(lái)越普遍了,vue3這方面的學(xué)習(xí)我們要趕上,下面這篇文章主要給大家介紹了關(guān)于vue3中update:modelValue的使用與不生效問(wèn)題的解決方法,需要的朋友可以參考下2022-03-03解決vue select當(dāng)前value沒(méi)有更新到vue對(duì)象屬性的問(wèn)題
今天小編就為大家分享一篇解決vue select當(dāng)前value沒(méi)有更新到vue對(duì)象屬性的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08vue3.0語(yǔ)法糖內(nèi)的defineProps及defineEmits解析
這篇文章主要介紹了vue3.0語(yǔ)法糖內(nèi)的defineProps及defineEmits解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04vue elementUI el-form 數(shù)據(jù)無(wú)法賦值且不報(bào)錯(cuò)的問(wèn)題及解決方法
vue項(xiàng)目中使用elementUI的el-form組件,里面有部分后端數(shù)據(jù)遍歷的字段和部分確定的字段,遇到個(gè)問(wèn)題遍歷的字段可以修改值但是確定的幾個(gè)字段無(wú)法修改值,下面小編給大家分享vue elementUI el-form 數(shù)據(jù)無(wú)法賦值且不報(bào)錯(cuò)的問(wèn)題及解決方法,感興趣的朋友一起看看吧2023-12-12基于vue-cli配置lib-flexible + rem實(shí)現(xiàn)移動(dòng)端自適應(yīng)
這篇文章主要介紹了基于vue-cli配置lib-flexible + rem實(shí)現(xiàn)移動(dòng)端自適應(yīng),需要的朋友可以參考下2017-12-12