基于 Vue3 和 TypeScript 項(xiàng)目大量實(shí)踐后的思考
概述
Vue3出來已經(jīng)有一段時(shí)間了,在團(tuán)隊(duì)中,也進(jìn)行了大量的業(yè)務(wù)實(shí)踐,也有了一些自己的思考。
總的來說,Vue3無論是在底層的原理上,還是在業(yè)務(wù)的實(shí)際開發(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那種隔離式的寫法。compositon Api,它更加聚焦,它講究的是相關(guān)業(yè)務(wù)的聚合性。同時(shí),在composition Api中,為了防止過于重的業(yè)務(wù)邏輯,它提供了一種關(guān)注點(diǎn)分離的方式,大大的提升了我們代碼的可讀性。
完全良好的支持了TypeScript,類型校驗(yàn)也成為了以后Vue3進(jìn)行大型項(xiàng)目開發(fā)的質(zhì)量保障,同時(shí)這也是面向了趨勢(shì) -- 前端的未來就是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
????????}
????}
})
復(fù)制代碼
這時(shí)候,對(duì)于大多數(shù)初學(xué)者來說,可能存在的疑惑就是,那么我能不能定義options Api的寫法,比如data、computed、watch、methods等等。
這里我需要明確的是,Vue3是完全兼容Vue2的這種options Api的寫法,但是從理念上來說,更加推薦setup的方式,來寫我們的組件。原因如下:Vue3的存在,本身是為了解決Vue2的問題的,Vue2的問題就是在于,聚合性不足,會(huì)導(dǎo)致代碼越來越臃腫!setup的方式,能夠讓data、方法邏輯、依賴關(guān)系等聚合在一塊,更方便維護(hù)。
也就是說,以后我們盡量不要寫單獨(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ù)!
在語法層面,兩個(gè)有差異。ref定義的響應(yīng)式數(shù)據(jù)需要用[data].value的方式進(jìn)行更改數(shù)據(jù);reactive定義的數(shù)據(jù)需要[data].[prpoerty]的方式更改數(shù)據(jù)。
const?actTitle:?Ref?=?ref('活動(dòng)名稱');
const?actData?=?reactive({
????list:?[],
????total:?0,
????curentPage:?1,
????pageSize:?10
});
actTitle.value?=?'活動(dòng)名稱2';
actData.total?=?100;
復(fù)制代碼
但是在應(yīng)用的層面,還是有差異的,通常來說:?jiǎn)蝹€(gè)的普通類型的數(shù)據(jù),我們使用ref來定義響應(yīng)式。表單場(chǎng)景中,描述一個(gè)表單的key:value這種對(duì)象的場(chǎng)景,使用reactive;在一些場(chǎng)景下,某一個(gè)模塊的一組數(shù)據(jù),通常也使用reactive的方式,定義數(shù)據(jù)。
那么,對(duì)象是不是非要使用reactive來定義呢?其實(shí)不是的,都可以,根據(jù)自己的業(yè)務(wù)場(chǎng)景,具體問題具體分析!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
????????}
????}
})
復(fù)制代碼
3、store使用
在Vue2中,其實(shí)可以直接通過this.$store進(jìn)行獲取,但是在Vue3中,其實(shí)沒有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
????????}
????}
})
復(fù)制代碼
4、router的使用
在Vue2中,是通過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
????????}
????}
})
復(fù)制代碼
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
????????}
????}
})
復(fù)制代碼
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
??};
}
復(fù)制代碼
3、TypeScript支持
這一部分內(nèi)容,準(zhǔn)確的來說,是TS的內(nèi)容,不過它與Vue3項(xiàng)目開發(fā),息息相關(guān),所以真的想用Vue3,我們還是得了解TS的使用。
不過這一部分,我不會(huì)介紹TS的基礎(chǔ)語法,主要是在業(yè)務(wù)場(chǎng)景中,如何組織TS。
使用TS進(jìn)行業(yè)務(wù)開發(fā),一個(gè)核心的思維是,先關(guān)注數(shù)據(jù)結(jié)構(gòu),再根據(jù)數(shù)據(jù)結(jié)構(gòu)進(jìn)行頁(yè)面開發(fā)。以前的前端開發(fā)模式是,先寫頁(yè)面,后關(guān)注數(shù)據(jù)。
比如要寫一個(gè)禮品列表的頁(yè)面,我們可能要定義這么一些interface。總而言之,我們需要關(guān)注的是:頁(yè)面數(shù)據(jù)的interface、接口返回的數(shù)據(jù)類型、接口的入?yún)㈩愋偷鹊取?/p>
//?禮品創(chuàng)建、編輯、列表中的每一項(xiàng),都會(huì)是這個(gè)數(shù)據(jù)類型。
interface?IGiftItem?{
??id:?string?|?number;
??name:?string;
??desc:?string;
??[key:?string]:?any;
}
//?全局相應(yīng)的類型定義
//?而且一般來說,我們不確認(rèn),接口返回的類型到底是什么(可能是null、可能是對(duì)象、也可能是數(shù)組),所以使用范型來定義interface
interface?IRes?{
????code:?number;
????msg:?string;
????data:?T
}
//?接口返回?cái)?shù)據(jù)類型定義
interface?IGiftInfo?{
????list:?Array;
????pageNum:?number;
????pageSize:?number;
????total:?number;
}
復(fù)制代碼
在一個(gè)常見的接口請(qǐng)求中,我們一般使用TS這么定義一個(gè)數(shù)據(jù)請(qǐng)求,數(shù)據(jù)請(qǐng)求的req類型,數(shù)據(jù)請(qǐng)求的res類型。
export?const?getGiftlist?=?(
??params:?Record<string,?any>
):?Promise>?=>?{
??return?Http.get("/apis/gift/list",?params);
};
復(fù)制代碼 關(guān)于本文:
來源:mapbar_front
https://juejin.cn/post/7008063765585330207
福利時(shí)間
最后,我又來給大家送福利了!

本書從Vue框架的基礎(chǔ)語法講起,逐步深入Vue進(jìn)階實(shí)戰(zhàn),并在后配合項(xiàng)目實(shí)戰(zhàn)案例,重點(diǎn)演示Vue在項(xiàng)目開發(fā)中的一些應(yīng)用。在系統(tǒng)地講解Vue的相關(guān)知識(shí)之余,本書力圖使讀者更深入地理解Vue項(xiàng)目開發(fā)。?
本書共分為11章,涵蓋的主要內(nèi)容有前端技術(shù)的發(fā)展歷程、Vue基本介紹、Vue語法、Vue選項(xiàng)、Vue內(nèi)置組件、Vue項(xiàng)目化、使用Vue開發(fā)電商類網(wǎng)站、使用Vue開發(fā)企業(yè)官網(wǎng)、使用Vue開發(fā)移動(dòng)端資訊類網(wǎng)站、使用Vue開發(fā)工具類網(wǎng)站等。?
這次準(zhǔn)備了多種方式抽獎(jiǎng),「群、在看」這兩種方式都可以參與!感謝親愛的讀者們,你們的支持也是我持續(xù)更文最大的動(dòng)力。
為了避免中獎(jiǎng)后失聯(lián),提前加我微信哈
抽獎(jiǎng)活動(dòng)規(guī)則
獎(jiǎng)品設(shè)置:《Vue.js從入門到項(xiàng)目實(shí)踐》?5?本,10 個(gè)?5 元紅包
開獎(jiǎng)時(shí)間:6 月 8 日 晚上 21:00
群抽獎(jiǎng)(3本 + 5個(gè)5元紅包)
添加瓶子君好友,私聊瓶子君回復(fù)?抽獎(jiǎng)?,拉你進(jìn)群抽獎(jiǎng),6?月 8 日 晚上 21:00在群里發(fā)紅包
大獎(jiǎng):贈(zèng)書紅包「3位」,各送出一本?
Vue.js從入門到項(xiàng)目實(shí)踐參與獎(jiǎng):參與紅包「5位」,各送出「5元」紅包。
在看抽獎(jiǎng)(2本 + 5個(gè)5元紅包)
記得先添加我微信,不然我看不到哪些小伙伴點(diǎn)再看
大獎(jiǎng):隨機(jī)抽取「2位」在看同學(xué)各送出一本?
Vue.js從入門到項(xiàng)目實(shí)踐參與獎(jiǎng):隨機(jī)抽取「5位」在看各送出「5元」紅包。
