Vue中的 mixins 和 provide/inject詳解
一、mixins
1、簡介
? mixins
又稱 混入,是指將一些可復用的代碼(JS、生命周期鉤子函數(shù)等等)抽離出來,定義成mixins
模塊,然后混入到多個組件中,從而實現(xiàn)組件間的邏輯代碼共享,減少重復代碼。當組件使用mixins
模塊時,mixins
模塊內(nèi)部的代碼將會被“混合”進組件的代碼,代碼“混合”邏輯與Vue.extend()
相同,具體邏輯下面有講解。
2、基礎(chǔ)使用
? mixins
模塊在組件內(nèi)是通過與data
、mounted
、methods
等鉤子函數(shù)同級的mixins
鉤子調(diào)用的,該鉤子的值是一個數(shù)組,里面包含要混入當前組件的mixins
模塊,這些模塊的混入順序按照mixins
鉤子數(shù)組的排列順序執(zhí)行,而且mixins
模塊內(nèi)如果包含生命周期鉤子函數(shù),則模塊內(nèi)的鉤子函數(shù)執(zhí)行順序先于組件本身的鉤子函數(shù)。
案例代碼:
// 定義一個mixin模塊 mixin.js export default { created: function () { console.log('這里是mixin1模塊的created') } } // 在組件實例中引入并使用定義的mixin模塊 // 引入mixin模塊 import mixin from "../mixins/mixin"; export default { created: function () { console.log('這里是組件本身的created') }, // 使用mixin模塊 mixins: [mixin] }
執(zhí)行結(jié)果:
3、選項合并
? 當組件與引入的mixins
模塊含有同名選項時,這些鉤子將依照下面的規(guī)則進行合并( Vue.extend()
的合并邏輯相同):
? ① mixins
模塊中的data
數(shù)據(jù)對象,將與組件的data
數(shù)據(jù)進行遞歸合并,如果存在同名數(shù)據(jù),則取組件內(nèi)的數(shù)據(jù)值。
? 當組件引入多個mixins
模塊時,將按照mixins
鉤子數(shù)組的排列順序進行合并,如果mixins
模塊之間存在同名數(shù)據(jù),則取排序最后的那個mixins
模塊的數(shù)據(jù)值,當然,如果該數(shù)據(jù)在組件內(nèi)也存在,則還是取組件內(nèi)的數(shù)據(jù)值。
案例代碼:
// 定義一個mixin1.js模塊 export default { data() { return { a: 1, // 第一個混入模塊中的變量a b: 11 // 第一個混入模塊中的變量b } }, } // 定義一個mixin2.js模塊 export default { data() { return { a: 2, // 第二個混入模塊中的變量a b: 22 // 第二個混入模塊中的變量b } }, } // 在組件實例中引入并使用定義的mixin模塊 // 引入兩個mixin模塊 import mixin1 from "../mixins/mixin1"; import mixin2 from "../mixins/mixin2"; export default { data() { return { b: 0, // 組件內(nèi)的變量b }; }, mounted() { // 組件內(nèi)不存在這個變量 兩個混入模塊存在同名變量 最終值取決于模塊引用順序 console.log("經(jīng)過合并后變量a的值是-----", this.a); // 組件內(nèi)存在這個變量 最終值取組件內(nèi)的值 console.log("經(jīng)過合并后變量b的值是-----", this.b); }, // 使用兩個mixin模塊 注意先后順序 決定同名變量的最終取值 mixins: [mixin1, mixin2], }
執(zhí)行結(jié)果:
? ② mixins
模塊中的鉤子函數(shù),將與組件內(nèi)的同名鉤子函數(shù)合并成一個數(shù)組,依次執(zhí)行,且mixins
模塊中的鉤子函數(shù)在組件同名鉤子函數(shù)之前調(diào)用執(zhí)行。不同名的鉤子函數(shù),依舊按照鉤子函數(shù)的先后順序執(zhí)行。
? 當組件引入多個mixins
模塊時,如果mixins
模塊之間存在同名鉤子函數(shù),則會按照mixins
鉤子數(shù)組的排列順序合并成一個數(shù)組,排列順序與執(zhí)行順序相同,排序靠前的mixins
模塊中的同名鉤子函數(shù)先執(zhí)行,排序靠后的后執(zhí)行,最終才會執(zhí)行組件本身的同名鉤子函數(shù)。
案例代碼:
// 定義一個mixin1.js模塊 export default { created: function () { console.log('這里是mixin1模塊的created') }, } // 定義一個mixin2.js模塊 export default { created: function () { console.log('這里是mixin2模塊的created') }, mounted: function () { console.log('這里是mixin2模塊的mounted') }, } // 在組件實例中引入并使用定義的mixin模塊 // 引入兩個mixin模塊 import mixin1 from "../mixins/mixin1"; import mixin2 from "../mixins/mixin2"; export default { created() { console.log("這里是組件本身的created"); }, // 使用兩個mixin模塊 注意先后順序 決定同名鉤子函數(shù)的執(zhí)行順序 mixins: [mixin1, mixin2], }
執(zhí)行結(jié)果:
? ③ mixins
模塊中的methods
、components
等值為對象的選項,將會與組件內(nèi)部的對應選項合并為一個對象,當對象中的鍵名發(fā)生沖突時,則取組件內(nèi)的鍵名對應的值。
? 當組件引入多個mixins
模塊時,如果mixins
模塊之間的選項存在同名沖突時,則會按照mixins
鉤子數(shù)組的排列順序進行覆蓋,后面的mixins會覆蓋前面的mixins,鍵名對應的值將取排在最后的mixins
模塊中對應的值,當然,如果該鍵名在組件內(nèi)也存在,則最終還是取組件內(nèi)的對應的值。
案例代碼:
// 定義一個mixin1.js模塊 export default { methods: { test() { console.log('這里是mixin1模塊methods中的test函數(shù)') }, test1() { console.log('這里是mixin1模塊methods中的test1函數(shù)') } }, } // 定義一個mixin2.js模塊 export default { methods: { // 如果mixin模塊之間存在鍵名沖突 則以組件中mixin數(shù)組的引用順序為準 // 取排序最后的鍵名對應的值 test1() { console.log('這里是mixin2模塊methods中的test1函數(shù)') } }, } // 在組件實例中引入并使用定義的mixin模塊 // 引入兩個mixin模塊 import mixin1 from "../mixins/mixin1"; import mixin2 from "../mixins/mixin2"; export default { mounted() { this.test(); this.test1(); }, // 使用兩個mixin模塊 注意先后順序 決定鍵名沖突的最終結(jié)果 mixins: [mixin1, mixin2], methods: { // 如果mixin模塊與組件本身鍵名沖突 則以組件為最終結(jié)果 test() { console.log("這里是組件本身methods中的test函數(shù)"); }, }, }
執(zhí)行結(jié)果:
總結(jié):
? 當一個組件使用了多個mixins
時,它們的順序很重要。因為當mixins
之間的選項存在沖突時,后面的mixins
會覆蓋前面的mixins
。而且同名鉤子函數(shù)的執(zhí)行順序也取決于多個mixins
的順序。
? 當組件與mixins
的選項存在沖突時,一切以組件為準。
? 在使用多個mixins
時,記得注意命名沖突問題。
4、全局混入
? 上面我們舉的例子都是在組件中依次引入mixins
模塊,如果我們想要在多個組件中,甚至是所有組件中都引入某個mixins
模塊,如果在每個組件中都引入一次,就太過繁瑣。此時我們可以使用全局混入特性。
? 全局混入是指將聲明的mixins
模塊,在main.js
文件中的全局Vue實例創(chuàng)建之前,通過Vue.mixin()
方法,掛載到Vue上。其作用相當于全局引入了mixins
模塊,會影響到每一個單獨創(chuàng)建的Vue頁面實例和組件,因此請慎用該特性?。。?/p>
? 如果全局混入的mixins
模塊中包含生命周期鉤子函數(shù),那么該鉤子函數(shù)將會根據(jù)當前頁面做包含的Vue實例數(shù)量來決定執(zhí)行的次數(shù),main.js文件的中的 全局Vue實例也算。
案例代碼:
// 定義一個allmixin.js 模塊 export default { created: function () { console.log('這里是全局mixin模塊的created') }, methods: { test() { console.log('這里是全局mixin模塊methods中的test函數(shù)') } }, } // 在main.js中引入并進行全局混入 import Vue from 'vue' import App from './App.vue' import allMixin from './mixins/allMixin' // 一定要在 new Vue 之前 否則不起作用 Vue.mixin(allMixin) // 創(chuàng)建全局Vue實例 new Vue({ render: h => h(App), }).$mount('#app') // 此時的頁面結(jié)構(gòu) // mian.js的new Vue -> APP.vue -> test.vue
執(zhí)行結(jié)果:
5、自定義選項
? 我們該可以結(jié)合this.$options
自定義選項來使用全局混入,只有使用自定義選項的組件才會觸發(fā)相關(guān)邏輯,從而局限mixins
模塊中部分代碼的作用范圍:
案例代碼:
// 定義一個allmixin.js 模塊 export default { created: function () { // 自定義選項 并接收傳遞的值 const myOptionValue = this.$options.myOption // 輸出傳遞的值 if (myOptionValue) { console.log('-*------', myOptionValue) } }, } // 在main.js中引入并進行全局混入 import Vue from 'vue' import App from './App.vue' import allMixin from './mixins/allMixin' // 一定要在 new Vue 之前 否則不起作用 Vue.mixin(allMixin) // 創(chuàng)建全局Vue實例 new Vue({ render: h => h(App), }).$mount('#app') // 在組件使用全局混入中自定義的選項 export default { data() { return {} }, // 使用自定義選項 myOption: "這是我向自定義選項傳遞的字符串", }
執(zhí)行結(jié)果:
? mixins
模塊中的自定義選項在合并時,使用的是默認策略,即簡單的覆蓋已有的值。當然我們也可以通過Vue.config.optionMergeStrategies
來自定義合并邏輯:
// 自定義合并邏輯 Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) { // 返回合并后的值 } // 或者 // 采用現(xiàn)有邏輯 與methods相同 Vue.config.optionMergeStrategies.myOption = Vue.config.optionMergeStrategies.methods
二、provide/inject
1、簡介
? provide/inject
是Vue在2.2.0版本新增的特性,該特性可以實現(xiàn)祖先組件向其后代組件跨層級傳遞數(shù)據(jù),無論兩者中間相隔多少組件層級,相對于傳統(tǒng)的props
傳遞方式,減少了傳遞數(shù)據(jù)的繁瑣操作,提升了代碼的可讀性和可維護性。該特性與React 框架的上下文特性很相似。
? 但是過多的使用provide/inject
特性,會增加組件之間的耦合性,降低組件的可復用性,因此使用該特性時要謹慎,不可濫用。而且provide
和inject
的綁定并不是響應式的,傳遞的數(shù)據(jù)并不會自動響應數(shù)據(jù)變化,如果想要響應數(shù)據(jù)變化,請借助data
或computed
。
2、provide
? provide
選項需要在祖先組件中使用,作用是向后代組件傳遞數(shù)據(jù),其選項值為一個對象或一個返回值為對象的函數(shù),對象的屬性即為要向其后代組件傳遞的數(shù)據(jù)。傳遞的數(shù)據(jù)可以是任意類型的數(shù)據(jù),如基本類型、對象、函數(shù)等等。
? provide
選項中支持使用 ES2015 Symbols 作為 key,但是只在原生支持 Symbol
和 Reflect.ownKeys
的環(huán)境下可工作
案例代碼:
// provide 的選項值為一個對象 export default { data() { return {} }, provide: { a: "這是祖先組件向后代組件傳遞的字符串數(shù)據(jù)", b: { c: "這是祖先組件向后代組件傳遞的對象數(shù)據(jù)", }, f: function () { console.log("這是祖先組件向后代組件傳遞的函數(shù)數(shù)據(jù)"); }, }, } // provide 的選項值為一個返回值為對象的函數(shù) export default { data() { return {} }, provide() { return { a: "這是祖先組件向后代組件傳遞的字符串數(shù)據(jù)", b: { c: "這是祖先組件向后代組件傳遞的對象數(shù)據(jù)", }, f: function () { console.log("這是祖先組件向后代組件傳遞的函數(shù)數(shù)據(jù)"); }, }; }, }
3、inject
? inject
選項是在后代組件中使用,作用是接收祖先組件傳遞的數(shù)據(jù),其選項值為一個字符串數(shù)組(推薦)或一個對象。更推薦使用字符串數(shù)組的形式,其中數(shù)組元素對應的是provide
對象中的key
,通過this.數(shù)組字符串元素
的形式來訪問祖先組件傳遞的對應數(shù)據(jù);如果使用對象形式,則需要通過鍵值對來接收數(shù)據(jù),鍵名表示當前組件內(nèi)的訪問名稱,value
為字符串,對應的是provide
對象中的key
,通過this.鍵名
的形式來訪問祖先組件傳遞的對應數(shù)據(jù)。
案例代碼:
// inject 的選項值為一個字符串數(shù)組(推薦) export default { data() { return {} }, inject: ["a", "b", "f"], } // inject 的選項值為一個對象(不推薦) export default { data() { return {} }, inject: { a: "a", b: "b", f: "f", }, } // 在后代組件中通過inject接收傳遞的數(shù)據(jù)之后 調(diào)用傳遞的數(shù)據(jù) mounted() { console.log("inject接收的祖先組件傳遞過來的字符串數(shù)據(jù)-----", this.a); console.log("inject接收的祖先組件傳遞過來的對象數(shù)據(jù)-----", this.b); console.log("inject接收的祖先組件傳遞過來的函數(shù)數(shù)據(jù)-----", this.f); },
執(zhí)行結(jié)果:
4、進階知識
① 在Vue的2.2.1版本之后,后代組件中通過inject
接收傳遞的數(shù)據(jù),會在props
和data
初始化之前得到,因此我們可以使用inject
中的數(shù)據(jù)給props
和data
中的數(shù)據(jù)設置默認值。
export default { inject: ['foo'], props: { a: { default() { return this.foo } } }, data() { return { b: this.foo } }, }
② 在Vue的2.5.0 版本之后,我們可以給選項值為對象形式的inject
中的數(shù)據(jù)設置默認值,使其在祖先組件中變成可選項,即在不傳遞數(shù)據(jù)時,后代組件依舊能正常工作。from
屬性設置數(shù)據(jù)源,default
屬性設置默認值。
與props
設置默認值類似,如果直接將非原始值(復雜數(shù)據(jù)類型)作為默認值,那么它將成為所有子組件實例之間共享的引用,相互之間會產(chǎn)生影響。因此我們需要對非原始值(復雜數(shù)據(jù)類型)使用一個工廠方法,以便于每次使用默認值時都獲得一個新的副本,而不是共享同一個引用。
export default { inject: { // 當組件內(nèi)名稱與祖先組件的key相同時,可省略form屬性 foo: { default: 'foo' }, // 當組件內(nèi)名稱與祖先組件的key不同時,需要通過form屬性指定對應的數(shù)據(jù) bar: { from: 'barFather', default: 'bar' }, // 對復雜數(shù)據(jù)類型使用一個工廠方法 arr: { from: 'arr', default: () => [1, 2, 3] }, }, data() { return {} }, }
三、參考資料
到此這篇關(guān)于Vue中的 mixins 和 provide/inject詳解的文章就介紹到這了,更多相關(guān)Vue mixins 和 provide/inject內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue項目如何使用$router.go(-1)返回時刷新原來的界面
這篇文章主要介紹了vue項目如何使用$router.go(-1)返回時刷新原來的界面問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09vue中實現(xiàn)Monaco Editor自定義提示功能
最近小編接到一個項目,需要在瀏覽器的ide中支持自定義提示功能,接下來通過本文給大家介紹在vue中實現(xiàn)Monaco Editor自定義提示功能,需要的朋友可以參考下2019-07-07vue3.0父子傳參,子修改父數(shù)據(jù)的實現(xiàn)
這篇文章主要介紹了vue3.0父子傳參,子修改父數(shù)據(jù)的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04vue3輸入無效路由跳轉(zhuǎn)到指定error頁面問題
這篇文章主要介紹了vue3輸入無效路由跳轉(zhuǎn)到指定error頁面問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03vite創(chuàng)建vue3項目頁面引用public下js文件失敗解決辦法
Vue3相較于之前的版本有了不少變化,如引用全局Js文件,這篇文章主要給大家介紹了關(guān)于vite創(chuàng)建vue3項目頁面引用public下js文件失敗的解決辦法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2023-11-11Vue3?echarts組件化及使用hook進行resize方式
這篇文章主要介紹了Vue3?echarts組件化及使用hook進行resize方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04