1 前言
Vue3 已經(jīng)正式發(fā)布了一段時(shí)間了,各種生態(tài)已經(jīng)成熟。最近使用 taro+vue3 重構(gòu)冷鏈的小程序,經(jīng)過了一段時(shí)間的開發(fā)和使用,有了一些自己的思考。
總的來說,Vue3 無論是在底層原理還是在實(shí)際開發(fā)過程中,都有了很大的進(jìn)步。
從源碼層面來說,使用 Proxy 代替 Object.defineProperty 的 API,一個(gè)是代理的對(duì)象,一個(gè)是遞歸監(jiān)控的屬性,從而在性能上有了很大的進(jìn)步,并且,也解決了對(duì)象動(dòng)態(tài)屬性增加、數(shù)組改變監(jiān)聽上的缺陷;對(duì) diff 算法進(jìn)行優(yōu)化,增加了靜態(tài)標(biāo)記,大大提高了 Vue 的執(zhí)行效率;還有靜態(tài)提升、事件監(jiān)聽緩存等一系列提升效率的手段。
從應(yīng)用層面來說,主要的改變是將 option API 改成了 composition API(組合式 API),在業(yè)務(wù)中拋棄 data、methods、生命周期函數(shù)隔離開的開發(fā)方式,使代碼相對(duì)于業(yè)務(wù)有更強(qiáng)的聚合性,在代碼開發(fā)、代碼閱讀、代碼維護(hù)方面對(duì)于開發(fā)者都是更加友好。
對(duì)于 typescript 有了更好的支持,我們知道,對(duì)于大型的前端項(xiàng)目來說,使用 typescript 的類型校驗(yàn),能使前端項(xiàng)目有更強(qiáng)的健壯性,這也使得 Vue3 對(duì)于大型項(xiàng)目的開發(fā)提供了更強(qiáng)的質(zhì)量保證。
2 組合式 API
所謂的組合式 API,將 Vue2 中的 data、methods、生命周期、數(shù)據(jù)監(jiān)聽等 option,都封裝成鉤子函數(shù),然后組合到 setup 函數(shù)中,其核心就在于 setup 函數(shù)。setup 函數(shù)存在的意義,就是為了使用這些新增的組合式 API,并且這些 API 只能在 setup 函數(shù)中使用。
setup 函數(shù)執(zhí)行的時(shí)機(jī)是,props 初始化之后,beforeCreate 函數(shù)執(zhí)行之前,所以在執(zhí)行 setup 時(shí),還沒有初始化 Vue 實(shí)例,因此在 setup 中不能使用 this 對(duì)象。setup 函數(shù)的返回值會(huì)被注入到 Vue 實(shí)例中,供 Vue 組件使用,所以任何數(shù)據(jù)想在 Vue 組件的模板中使用,必須在 setup 函數(shù)中 return 出去。
組合式 API 的組合,體現(xiàn)在兩個(gè)層面。第一層的意思是,將某一業(yè)務(wù)相關(guān)數(shù)據(jù)和處理邏輯放到一起,這是一種關(guān)注點(diǎn)的聚合,更方便我們編寫代碼、處理業(yè)務(wù)邏輯,并且能更聚焦業(yè)務(wù)邏輯,更方便我們看代碼。第二層面的意思,當(dāng)某個(gè)組件的業(yè)務(wù)邏輯足夠復(fù)雜,setup 中的代碼足夠大的情況下,我們可以在 setup 內(nèi)部,進(jìn)一步提取相關(guān)的一塊業(yè)務(wù),使代碼邏輯更加清晰,做到了進(jìn)一步的聚合作用。
如下面代碼所示,將業(yè)務(wù)代碼塊 A 抽出來,則代碼塊 A 中 return 出來的數(shù)據(jù)就可以在組件中使用:
// 組件
import functionA from 'A'
export default defineComponent({
name: 'componentName',
setup() {
...functionA()
}
})
// 代碼塊A
export default () => {
return {
a: 1
}
}
3 響應(yīng)式 API
在 Vue3 中響應(yīng)式 API,主要體現(xiàn)在 ref 和 reactive 兩個(gè)函數(shù)。對(duì)于響應(yīng)式 API,想說兩個(gè)問題,第一個(gè)是為什么要增加響應(yīng)式 API,第二個(gè)是響應(yīng)式 API 函數(shù) ref 和 reactive 的異同點(diǎn)。
3.1 為什么增加響應(yīng)式 API
在 Vue2 中所有數(shù)據(jù)都寫在 data 的 option 中,data 中的數(shù)據(jù)都是響應(yīng)式的,這樣產(chǎn)生的一個(gè)問題是,有些常量數(shù)據(jù)本身不需要監(jiān)聽,從而造成了資源的浪費(fèi)。所以在 Vue3 中增加了響應(yīng)式 API,只需要對(duì)需要?jiǎng)討B(tài)更新 dom 的數(shù)據(jù)進(jìn)行響應(yīng)式,不需要?jiǎng)討B(tài)更新 dom 的數(shù)據(jù)不進(jìn)行響應(yīng)式處理,從很大程度上節(jié)省了資源。這里我覺得需要注意的是,寫代碼的時(shí)候一定要仔細(xì)思考一下,哪些數(shù)據(jù)需要進(jìn)行響應(yīng)式綁定,哪些數(shù)據(jù)不需要進(jìn)行響應(yīng)式綁定,而不是一股腦的全給綁定上,這樣即使代碼邏輯不能很清晰易懂,并且也會(huì)影響執(zhí)行效率(寫慣了 Vue2 的同學(xué)需要注意)。
3.2 ref 和 reactive 的異同點(diǎn)
在了解了為什么要增加響應(yīng)式 API 后,我們發(fā)現(xiàn) Vue3 提供了兩個(gè)響應(yīng)式 API 函數(shù),ref 和 reactive。為什么會(huì)提供兩個(gè) API 呢? 一個(gè)不就可以了嗎?那么這兩個(gè) API 之間的區(qū)別是什么呢?
在使用層面,ref 綁定的數(shù)據(jù),需要使用 [data].value 進(jìn)行數(shù)據(jù)更改。而 reactive 綁定的數(shù)據(jù)需要使用 [data].[prpoerty] 的方式進(jìn)行數(shù)據(jù)更改。在使用場(chǎng)景方面,一般的,單個(gè)的普通數(shù)據(jù),我們使用 ref 來定義響應(yīng)式。而復(fù)雜數(shù)據(jù),如:表單數(shù)據(jù)對(duì)象、某一模塊的一組數(shù)據(jù)等,使用 reactive 來定義響應(yīng)式。
那么,對(duì)象是不是必須用 reactive 來定義呢? 其實(shí)不是的,都可以。官方說法是:可以根據(jù)自身習(xí)慣使用不同的 API。其實(shí),我覺得,他們是有各自的使用場(chǎng)景的,ref 更強(qiáng)調(diào)的是數(shù)據(jù) Value 的改變,reactive 更強(qiáng)調(diào)的是數(shù)據(jù)中某一屬性的改變。
4 treeShaking 思想
當(dāng) Javascript 項(xiàng)目達(dá)到一定體積時(shí),將代碼分成模塊會(huì)更易于管理。但是,當(dāng)這樣做時(shí),我們最終可能會(huì)導(dǎo)入實(shí)際上未使用的代碼。Tree Shaking 是一種通過消除最終文件中未使用的代碼來優(yōu)化體積的方法。
Vue3 使用了 tree shaking 的方法,將組件以及其所有的生命周期函數(shù)等方法進(jìn)行分開,如果在組件中使用的代碼將不會(huì)出現(xiàn)在最終的打包文件中,如此,會(huì)減少大大 Vue3 項(xiàng)目的打包體積。由此造成的一個(gè)結(jié)果就是,使用方法的不同。
4.1 生命周期函數(shù)的使用方法
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
}
}
})
4.2 Vuex 的使用方法
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.3 Router 的使用方法
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
}
}
})
5 關(guān)于 Typescript 的使用
這一部分是關(guān)于 Ts 的內(nèi)容,不過它與 Vue3 的開發(fā)息息相關(guān)。Vue3 整體是使用 Ts 寫的,因此,開發(fā) Vue3 的項(xiàng)目需要使用 Ts,所以,我們還是要了解 TS 的。
關(guān)于 Ts 的使用這里就不在細(xì)說了,在這里想說的的是,在實(shí)際業(yè)務(wù)場(chǎng)景中是如何組織 Ts 代碼的。通過對(duì) TS 的大量使用,我的一個(gè)體會(huì)是:Ts 的核心思維是先關(guān)注數(shù)據(jù)結(jié)構(gòu),在根據(jù)數(shù)據(jù)結(jié)構(gòu)進(jìn)行頁(yè)面開發(fā)。而以前的前端開發(fā)模式是,先寫頁(yè)面,然后再關(guān)注數(shù)據(jù)。
比如說,我們要開發(fā)一個(gè)頁(yè)面,我們可能需要先定義一些 interface。開發(fā)頁(yè)面的時(shí)候我們要關(guān)注:頁(yè)面數(shù)據(jù)的 interface、接口返回?cái)?shù)據(jù)的類型、請(qǐng)求參數(shù)的類型等等。
下面是開發(fā)一個(gè)列表頁(yè)面的例子:文章來源:http://www.zghlxwxcb.cn/news/detail-401849.html
// 這是列表中每一項(xiàng)的數(shù)據(jù)類型
interface IDataItem {
id: string | number;
name: string;
desc: string;
[key: string]: any;
}
// 接口返回值類型, 一般來說,我們不確定接口返回的數(shù)據(jù)的類型,因此使用泛型
interface IRes<T> {
code: number;
msg: string;
data: T
}
// 口返回?cái)?shù)據(jù)類型定義
interface IDataInfo {
list: Array<IDataItem>;
pageNum: number;
pageSize: number;
total: number;
}
// 請(qǐng)求
export const getDatalist = (
params: Record<string, any>
): Promise<IRes<IDataInfo>> => {
return Http.get("/api/data/list", params);
};
如上面代碼,當(dāng)我們的 interface 定義完成后,我們的頁(yè)面數(shù)據(jù)基本都已清楚,直接寫頁(yè)面就會(huì)清晰很多,且出錯(cuò)概率會(huì)大大降低。文章來源地址http://www.zghlxwxcb.cn/news/detail-401849.html
到了這里,關(guān)于聊一聊Vue和Ts的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!