Vue中Mixin的正確用法詳解
令人頭疼的 mixin
眾所周知,vue 的 mixins 是個(gè)非常靈活,但又很容易帶來(lái)混亂的 API。不知道你是否像我一樣,常常因?yàn)轫?xiàng)目中用了 mixins 而感到頭疼。比如說(shuō):
- 來(lái)回切換文件:有人會(huì)因?yàn)槲募蠖岩徊糠謨?nèi)容提取到單獨(dú)的
mixin中,看起來(lái)文件變小了,但改代碼的時(shí)候需要在多個(gè)文件之間不停切換 - 找不到函數(shù)和變量:模板中用到一個(gè)函數(shù),在
methods中搜索不到,然后發(fā)現(xiàn)組件引入了很多mixins,不知道要該去哪里找
Mixins 本該是一種強(qiáng)大的重用代碼的手段,但使用之后往往帶來(lái)更多的混亂,代碼變得不易維護(hù)。所以,在 Vue3 中,不再推薦使用 mixins,而是改用組合式 API的方式來(lái)重用代碼。
那么,我們是不是不應(yīng)該在日常代碼中使用 mixins 呢?我覺得也不是。Mixins 是個(gè)強(qiáng)大的工具,但本身存在一些嚴(yán)重的問(wèn)題,如果我們能把 mixins 中存在的問(wèn)題解決掉,那剩下的就會(huì)是:強(qiáng)大。
為什么會(huì)這樣?
面對(duì) mixins 這樣靈活的工具,我們必須理解它的問(wèn)題所在,才能避免在使用時(shí)帶來(lái)混亂。
本質(zhì)上,mixins 是一種重用代碼的手段,它可以向一個(gè)對(duì)象中注入另一個(gè)對(duì)象中的所有屬性。并且,一個(gè)對(duì)象可以同時(shí)從多個(gè)不同對(duì)象中注入屬性,所以非常靈活。而這樣的靈活導(dǎo)致了一些致命的問(wèn)題:
- 來(lái)源不明:使用的
mixins越多,越難找到某個(gè)屬性或方法來(lái)自哪里 - 無(wú)法精確引入:引入一個(gè)
mixin時(shí),會(huì)引入這個(gè)mixin的全部屬性,因此很可能會(huì)引入一些用不到的東西,也會(huì)導(dǎo)致很難清楚知道到底引入了哪些屬性和方法 - 命名沖突:引入多個(gè)
mixins時(shí),引入的屬性名可能會(huì)沖突 - 耦合問(wèn)題:不規(guī)范地使用
mixins功能,可能會(huì)導(dǎo)致耦合問(wèn)題,比如因?yàn)榻M件太大而抽離一部分屬性到mixins中,這樣產(chǎn)生的mixins一般會(huì)互相依賴,造成強(qiáng)耦合
作為對(duì)比,我們看看其他類似技術(shù)為什么沒(méi)有這些問(wèn)題:
- ES模塊:一個(gè)模塊可以導(dǎo)出很多東西,但我們可以選擇性導(dǎo)入,這樣就能清楚知道導(dǎo)入了哪些內(nèi)容,并且導(dǎo)入的變量和函數(shù)可以重命名,這樣就解決了命名沖突的問(wèn)題
- Vue3組合式函數(shù):Vue3 推薦使用組合式函數(shù)來(lái)替代
mixins實(shí)現(xiàn)邏輯重用,組合式函數(shù)一般返回一個(gè)對(duì)象,解構(gòu)時(shí)可以只取出對(duì)象中的部分屬性,從而可以精確控制引入內(nèi)容,并且解構(gòu)語(yǔ)法支持自定義變量名,因此不會(huì)導(dǎo)致命名沖突
如果我們想要放心使用 mixins 功能,就必須解決以上問(wèn)題。從 ES模塊 和 Vue3組合式函數(shù) 的設(shè)計(jì),我們可以看出一些關(guān)鍵點(diǎn),那就是需要能 精確控制引入的內(nèi)容,具體包括:
- 清晰看到引入的內(nèi)容:在引入
mixins的地方,可以直接看到引入了哪些屬性和方法 - 支持部分引入:可以只引入需要用到的屬性,而不是引入
mixin對(duì)象上的全部屬性 - 自定義引入的屬性名:可以指定要引入的屬性和方法的名字,避免命名沖突
這看起來(lái)似乎是不可能的,因?yàn)?mixin 就是一個(gè)對(duì)象,一旦引入就要接受這個(gè)對(duì)象上的所有屬性和方法,也不可能在引入的時(shí)候去修改對(duì)象的屬性名。
那還能不能用?
當(dāng)然,你可以只使用生命周期鉤子的功能,而不引入 data、計(jì)算屬性和方法,這樣就不會(huì)往實(shí)例上添加額外屬性,也就不會(huì)有這些問(wèn)題。但是,這會(huì)使 mixins 的功能大打折扣。
幸運(yùn)的是,確實(shí)有一個(gè)方法能夠精確控制引入的內(nèi)容,那就是動(dòng)態(tài)創(chuàng)建 mixin 對(duì)象。
一般來(lái)說(shuō),我們習(xí)慣把 mixin 定義為一個(gè)對(duì)象,然后在組件中直接引入。但其實(shí)只要把它定義成一個(gè)函數(shù),問(wèn)題就會(huì)得到解決。
我們可以把 mixin 定義成一個(gè)函數(shù),通過(guò)函數(shù)參數(shù)接收需要引入的屬性名,然后生成并返回真正的 mixin 對(duì)象。這樣的 mixin 就是動(dòng)態(tài)生成的。引入時(shí),調(diào)用這個(gè)函數(shù),通過(guò)傳入的參數(shù)就可以精確控制引入的內(nèi)容,可以指定要引入哪些屬性,也可以指定引入的屬性名字。
import mouse from '@/mixins/mouse'
export default {
mixins: [
mouse({
mouseX: 'x',
mouseY: 'y'
})
]
}我們給這種方法取一個(gè)不沖突的名字,就稱為 動(dòng)態(tài)Mixin 好了。
當(dāng)然,這種寫法增加了編寫 mixins 的難度,所以我認(rèn)為,mixins 適合用來(lái)引入一些簡(jiǎn)單的屬性。比如,VueUse 中的那些工具方法就很適合使用動(dòng)態(tài) Mixin 來(lái)實(shí)現(xiàn)。
動(dòng)態(tài)Mixin示例
接下來(lái)我列舉一些自己在項(xiàng)目中經(jīng)常使用的 mixins,大家可以體會(huì)一下這種動(dòng)態(tài) Mixin 的適用場(chǎng)景以及帶來(lái)的好處。
倒計(jì)時(shí)
倒計(jì)時(shí)是業(yè)務(wù)中經(jīng)常會(huì)用到的一種場(chǎng)景,比如發(fā)送驗(yàn)證碼時(shí)一般會(huì)顯示倒計(jì)時(shí)。然后有些使用須知的彈窗,確認(rèn)按鈕也會(huì)在倒計(jì)時(shí)結(jié)束后才允許點(diǎn)擊。
這種倒計(jì)時(shí)非常簡(jiǎn)單,只需要一個(gè)記錄當(dāng)前剩余時(shí)間的屬性,加上一個(gè)設(shè)置倒計(jì)時(shí)時(shí)長(zhǎng)的函數(shù)。這種場(chǎng)景就非常適合使用 mixins 來(lái)實(shí)現(xiàn)。實(shí)現(xiàn)過(guò)程先不考慮,使用效果是這樣的:
<template>
<button :disabled="!!seconds" @click="setCountdown(60)">
{{ seconds || '發(fā)送驗(yàn)證碼' }}
</button>
</template>
<script>
import countdown from '@/mixins/countdown';
export default {
// 引入 seconds 屬性存儲(chǔ)剩余秒數(shù)
// 引入 setCountdown 方法設(shè)置倒計(jì)時(shí)秒數(shù)
mixins: [countdown('seconds', 'setCountdown')],
};
</script>這個(gè) mixins 引入了一個(gè)屬性和一個(gè)方法,引入的內(nèi)容都是可以指定名字的。調(diào)用 setCountdown 方法時(shí)會(huì)設(shè)置 seconds 屬性的值,并重新開始倒計(jì)時(shí)。
不過(guò)在 Vue 中,我們可以充分利用 Vue 自帶的響應(yīng)式特性。我們可以利用 watch 去進(jìn)行監(jiān)聽,在檢測(cè)到 seconds 變化時(shí),重新開始倒計(jì)時(shí)。這樣就可以少引入一個(gè)方法。
<template>
<button :disabled="!!seconds" @click="seconds = 60">
{{ seconds || '發(fā)送驗(yàn)證碼' }}
</button>
</template>
<script>
import countdown from '@/mixins/countdown';
export default {
// 引入 seconds 屬性記錄倒計(jì)時(shí)秒數(shù)
mixins: [countdown('seconds')],
};
</script>看,使用 mixins 之后,代碼變得特別簡(jiǎn)潔清晰。而且只需要寫一次,今后就可以在其他項(xiàng)目中直接使用這個(gè) mixin。而如果不使用 mixins 自己實(shí)現(xiàn),就需要多寫很多代碼,完善的寫法每次還需要考慮怎么清除定時(shí)器,防止內(nèi)存泄漏。
這個(gè) mixin 的具體實(shí)現(xiàn)可以看這里:vue-library/mixins/countdown at master · web1706/vue-library · GitHub。你可以直接在你的項(xiàng)目中使用。
路由query參數(shù)
編寫一個(gè)操作路由 query 參數(shù)的 mixin 其實(shí)是挺有必要的。
想象這樣一個(gè)場(chǎng)景:頁(yè)面上有一個(gè) Tabs 組件,有多個(gè)頁(yè)簽。當(dāng)我們切換頁(yè)簽時(shí),一般會(huì)把當(dāng)前激活的頁(yè)簽的值存儲(chǔ)在 data 中。
export default {
data() {
return {
// 當(dāng)前 tab 頁(yè)
currentTab: 'one'
}
}
}這樣其實(shí)會(huì)有一個(gè)問(wèn)題,就是刷新頁(yè)面后,或者進(jìn)入其他頁(yè)面再返回時(shí),是回不到之前的頁(yè)簽的。如果有一天需要改成刷新時(shí)保留激活的頁(yè)簽,最好的方法就是把頁(yè)簽值存入路由 query 中。這時(shí)如果有這樣一個(gè)操作 query 參數(shù)的 mixin 就方便了。
import routeQuery from '@/mixins/route-query';
export default {
mixins: [
// 當(dāng)前 tab 頁(yè)
routeQuery('currentTab'),
],
};這個(gè) mixin 會(huì)從 this.$route.query 中讀取對(duì)應(yīng)的參數(shù)值,放到名為 currentTab 的屬性中。并且這個(gè)屬性是可寫的!寫入時(shí)會(huì)自動(dòng)調(diào)用 this.$router.replace 去替換 query 中的參數(shù)值。
當(dāng)然,你可能還需要指定默認(rèn)值,這也沒(méi)問(wèn)題,只需要改成對(duì)象形式:
import routeQuery from '@/mixins/route-query';
export default {
mixins: [
routeQuery({
// 當(dāng)前 tab 頁(yè)
currentTab: {
default: 'one'
}
}),
],
};或許,你想在 query 中使用一個(gè)不一樣的參數(shù)名。
import routeQuery from '@/mixins/route-query';
export default {
mixins: [
routeQuery({
// 當(dāng)前 tab 頁(yè)
currentTab: {
from: 'tab'
},
// 簡(jiǎn)寫形式
activeTab: 'tab'
}),
],
};想要使用數(shù)字類型也沒(méi)問(wèn)題。
export default {
mixins: [
routeQuery({
// 對(duì)引入的屬性值進(jìn)行轉(zhuǎn)換
companyId: {
type: Number,
},
// 簡(jiǎn)寫形式
deptId: Number,
}),
],
};可以看到,這個(gè) mixin 非常靈活,功能也比傳統(tǒng) mixins 強(qiáng)大很多。
后記
本文介紹的這種使用函數(shù)動(dòng)態(tài)生成 Mixin 的方式,大家覺得怎么樣呢?大家平時(shí)又是如何看待和使用 Mixin 的呢?快來(lái)交流一下各自的想法吧。
以上就是Vue中Mixin的正確用法詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue Mixin用法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在Vue中使用SQLite數(shù)據(jù)庫(kù)的基礎(chǔ)應(yīng)用詳解
這篇文章主要為大家詳細(xì)介紹了在Vue中使用SQLite數(shù)據(jù)庫(kù)的基礎(chǔ)應(yīng)用,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02
基于vue寫一個(gè)全局Message組件的實(shí)現(xiàn)
這篇文章主要介紹了基于vue寫一個(gè)全局Message組件的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
nuxt.js服務(wù)端渲染中axios和proxy代理的配置操作
這篇文章主要介紹了nuxt.js服務(wù)端渲染中axios和proxy代理的配置操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
VUE+Canvas實(shí)現(xiàn)財(cái)神爺接元寶小游戲
這篇文章主要介紹了VUE+Canvas實(shí)現(xiàn)財(cái)神爺接元寶小游戲,需要的朋友可以參考下本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-04-04
Vue3 Echarts通用的折線圖帶陰影效果實(shí)現(xiàn)
在環(huán)保倉(cāng)管項(xiàng)目中,做了一個(gè)每月對(duì)藥品、消耗品、設(shè)備的進(jìn)出,進(jìn)行統(tǒng)計(jì)百分比,效果好看,后面經(jīng)常在用這個(gè)樣式,下面通過(guò)示例代碼分享Vue3 Echarts通用的折線圖帶陰影效果實(shí)現(xiàn),感興趣的朋友一起看看吧2024-07-07
vue3中addRoute路由變化頁(yè)面未刷新問(wèn)題解決
這篇文章主要為大家介紹了vue3中addRoute路由變化但頁(yè)面未刷新問(wèn)題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06

