在項目開發的時候,常會碰到這樣的一種現象:有兩個組件非常相似,比如較為熟悉的 Modal 、 Tooltip 和 Popover ,它們都具有同樣的基本函數,而且它們之前也有足夠的不同。很多時候,就讓人很難做出選擇:是把它們拆會成多個不同的組件呢?還是只使用一個組件,創建足夠的屬性來改變不同的情況。
這些解決方案都不夠完美。如果拆會成多個組件,就不得不冒着如果功能變動你要在多個文件中更新它的風險。另一方面,太多的屬笥會很快變得混亂,難維護,甚至對於組件開發者自已面言,也是件難事。
在Vue中,對於這樣的場景,官方提供了一種叫混入 (mixins) 的特性。使用 mixins 允許你封裝一塊在應用的其他組件中都可以使用的函數。如果被正確的使用,他們不會改變函數作用域外部的任何東西,所以多次執行,只要是同樣的輸入,總是能得到一樣的值。
既然Vue的 mixins 這么優秀,那應該怎么使用呢?今天我們的目的就是學習如何在Vue的項目中使用 mixins 。
什么是Mixins
Vue的官方文檔是這樣描述 mixins 的:mixins
是一種分發Vue組件中可復用功能的一種靈活方式。
mixins 是一個JavaScript對象,可以包含組件中的任意選項,比如Vue實例中生命周期的各個鈎子函數,也可以是 data 、 components 、 methods 或 directives 等。在Vue中, mixins 為我們提供了在Vue組件中共用功能的方法。使用方式很簡單,將共用的功能以對象的方式傳入 mixins 選項中。當組件使用 mixins 對象時,所有 mixins 對象的選項都將被混入該組件本身的選項。
如何創建Mixins
在Vue中,創建 mixins 方法很簡單。簡單一點的,在Vue組件中,我們將 mixins 對象指定為:
1 const myMixin = { 2 created () { 3 console.log(`來自Mixins中的消息`) 4 } 5 } 6 7 let app = new Vue({ 8 el: '#app', 9 mixins: [myMixin] 10 })
上面看到的方式是在組件中聲明一個 mixins 對象。如果組件多起來,這樣的方式,感覺還是沒有解決我們文章提到的需求一樣。更好的做法,我們可以像下面這樣做。比如在項目的src
下面創建一個存放 mixins 的目錄,比如一個叫 mixin 目錄。然后這個目錄中創建你想要的.js
文件,比如這里創建了一個叫 mixins.js :
為了方便演示,把上面創建的 mixins 相關的代碼移入 mixins.js 文件中:
1 // src/mixins/mixins.js 2 export const myMixin = { 3 created() { 4 console.log(`來自Mixins中的消息`); 5 } 6 };
在需要使用該 mixins 的組件中先引入 mixins.js 文件,接着在組件中的 mixins 選擇中調用在 mixins.js 創建的 mixins ,比如:
// HelloWorld.vue <script> import { myMixin, myMixin2 } from "../mixins/mixins.js"; export default { name: "HelloWorld", data() { return { msg: "From Vue Component" }; }, mixins: [myMixin] }; </script>
這種方式和前面使用 mixins 方式最終得到的結果是一樣的。
使用 mixins ,在 mixins 中指定的任何選項都會立即與Vue組件的選項合並。可以在組件的 mixins 數組中指定多個 mixin 。一旦指定了,所有的 mixin 選項都會被導入到組件中。比如:
1 // mixins.js 2 export const mixObj = { 3 created() { 4 this.hello() 5 }, 6 methods: { 7 hello() { 8 console.log(`Hello from Mixin`) 9 } 10 } 11 } 12 export const minObjAnother = { 13 created () { 14 this.prompt() 15 }, 16 methods: { 17 prompt() { 18 console.log(`Prompt from Mixin Another`) 19 }, 20 hello() { 21 console.log(`Hello from Mixin Another`) 22 } 23 } 24 }
如果在組件中要同時調用 mixObj 和 minObjAnother 兩個 mixins 時,需要在組件的 mixins 選項的值添加這兩個 mixins ,比如:
1 <!-- HelloWorld.vue --> 2 <script> 3 import { mixObj, minObjAnother } from "../mixins/mixins.js"; 4 5 export default { 6 name: "HelloWorld", 7 mixins: [mixObj, minObjAnother], 8 }; 9 </script>
此時在 console 中輸出的結果如下:
從輸出的結果中我們可以看出, mixObjAnother 中的 hello() 方法取替了 mixObj 中的 hello() 方法。
是不是感到疑惑。如果是,請繼續往下閱讀。
合並選項和沖突
當組件和混入對象含有同名選項時,這些選項將以恰當的方式混合。
什么是“ 恰當的方式 ”?對於我這樣的初學者而言,有點難於理解。上例中我們看到了,每個 mixins 對象中都具有生命周期的鈎子(Vue生命周期)和方法(甚至其他的),而且這些東西都是可用的。另外在Vue中的組件,同樣也有這些生命周期的鈎子函數和方法。所以當在組件上注冊重復的過程時,順序顯得尤其重要。
默認是 mixins 上會首先被注冊,組件上的接着注冊!
這樣的做主要是因為必要時可以重寫。
組件擁有最終發言權: 當有一個沖突並且這個組件不得不決定哪個勝出的時候,這真的變得很重要,否則,所有東西都被放在一個數組中執行, mixins 中的先執行,組件中的接着執行。
在Vue中 mixins 常見的合並主要有三種情形:數據 data 、生命周期中的鈎子函數和值為對象的選項。接下來,咱們分別來看看這三種情形:
數據合並
數據對象在內部分進行淺合並(一層屬性深度),在和組件的數據發生沖突時, 以組件數據優先 。
1 // mixins.js 2 export const mixObj = { 3 data() { 4 return { 5 msg: "Message from Mixin Object" 6 }; 7 } 8 }; 9 export const minObjAnother = { 10 data() { 11 return { 12 msg: "Message from Mixin Object Another", 13 name: "Foo" 14 }; 15 } 16 }; 17 18 <!-- HelloWorld.vue --> 19 <script> 20 import { mixObj, minObjAnother } from "../mixins/mixins.js"; 21 22 export default { 23 name: "HelloWorld", 24 data() { 25 return { 26 msg: "Message from Vue Component", 27 name: 'Bar', 28 age: 20 29 }; 30 }, 31 mixins: [mixObj, minObjAnother], 32 created () { 33 console.log(this.$data) 34 } 35 }; 36 </script>
最終的結果是, HelloWorld
組件中的 msg
和 name
取替了 mixins
中的,另外 age
字段被合並進行。
鈎子函數合並
當組件使用的 mixins 對象有相同的選項時,比如鈎子函數,就會全部被合並到一個數組中,因此都會被執行,並且
mixins `對象中的鈎子會先被執行。
1 const myMixin = { 2 created () { 3 console.log(`來自Mixins中的消息`) 4 } 5 } 6 7 new Vue({ 8 el: '#app', 9 mixins: [myMixin], 10 created () { 11 console.log(`來自組件中的消息`) 12 } 13 })
值為對象選項合並
當 mixins
對象和組件中的選項的值為對象時,比如 methods 、 components 和 directives ,將被混合為同一個對象。當兩個對象鍵名沖突時, 組件選項優先 。
1 const myMixin = { 2 data () { 3 return { 4 msg: 'From Vue Mixins' 5 } 6 }, 7 created() { 8 console.log(`來自Mixins的消息`) 9 }, 10 methods: { 11 message () { 12 console.log(this.msg) 13 } 14 } 15 }; 16 export default { 17 name: "HelloWorld", 18 data() { 19 return { 20 msg: "From Vue Component" 21 }; 22 }, 23 mixins: [myMixin], 24 created() { 25 console.log(`來自組件的消息`) 26 }, 27 methods: { 28 message () { 29 console.log(this.msg) 30 } 31 } 32 };
全局Mixins
當我們使用全局混合時,我們不是指能夠在每個組件上訪問它們,就像是過濾器一樣。我們能夠通過 mixins:[myMixins] 訪問組件上的混合對象。
全局混合被注冊到了每個單一組件上。因此,它們的使用場景極其有限並且要非常的小心。一個我能想到的用途就是它像一個插件,你需要賦予它訪問所有東西的權限。但即使在這種情況下,我也對你正在做的保持警惕,尤其是你在應用中擴展的函數,可能對你來說是不可知的
為了創建一個全局實例,我們可以把它放在 Vue 實例之上。在一個典型的 Vue-cli 初始化的項目中,它可能在你的 main.js 文件中。
1 Vue.mixin({ 2 mounted() { 3 console.log('hello from mixin!') 4 } 5 }) 6 7 new Vue({ 8 ... 9 })
謹慎使用全局混入對象,因為會影響到每個單獨創建的 Vue 實例 (包括第三方模板)。大多數情況下,只應當應用於自定義選項,就像上面示例一樣。也可以將其用作 Plugins 以避免產生重復應用。
使用Mixins實例
經過上面的介紹,我們對Vue中的 mixins 應該有了一定的了解。接下來通過簡單的實例來向大家闡述在項目中怎么使用上面介紹的 mixins 。
先來看一個簡單的示例,也就是文章中提到的 Modal 和 Tooltip 組件。雖然這兩個組件是不同的組件,但實際上它們的作用是類似的: 切換一個狀態布爾值 。換句話說,這兩個組件表面上看起來不一樣,用法不一樣,但邏輯是一樣的。
1 // 模態框 2 const Modal = { 3 template: '#modal', 4 data() { 5 return { 6 isShowing: false 7 } 8 }, 9 methods: { 10 toggleShow() { 11 this.isShowing = !this.isShowing; 12 } 13 }, 14 components: { 15 appChild: Child 16 } 17 } 18 19 // 提示框 20 const Tooltip = { 21 template: '#tooltip', 22 data() { 23 return { 24 isShowing: false 25 } 26 }, 27 methods: { 28 toggleShow() { 29 this.isShowing = !this.isShowing; 30 } 31 }, 32 components: { 33 appChild: Child 34 } 35 }
我們可以提取出這個邏輯並創建可以被重用的項:
1 // toggle.js 2 export const toggle = { 3 data() { 4 return { 5 isShowing: false 6 }; 7 }, 8 methods: { 9 toggleShow() { 10 this.isShowing = !this.isShowing; 11 } 12 } 13 }; 14 15 <!-- Modal.vue --> 16 <template> 17 <div> 18 <h3>Let's trigger this here modal!</h3> 19 <button @click="toggleShow"> 20 <span v-if="isShowing">Hide child</span> 21 <span v-else>Show child</span> 22 </button> 23 <Child v-if="isShowing" class="modal"> 24 <button @click="toggleShow">Close</button> 25 </Child> 26 </div> 27 </template> 28 29 <script> 30 import Child from "./Child"; 31 import { toggle } from "../mixins/toggle.js"; 32 33 export default { 34 name: "Modal", 35 mixins: [toggle], 36 components: { 37 Child 38 } 39 }; 40 </script> 41 42 <!-- ToolTip.vue --> 43 <template> 44 <div class="tooltip-demo"> 45 <h3 @click="toggleShow"> 46 <span v-if="isShowing">Click Me Again</span> 47 <span v-else>Click Me Please</span> 48 </h3> 49 <Child v-if="isShowing" class="tooltip"> 50 <p>I'm a tooltip this time</p> 51 </Child> 52 </div> 53 </template> 54 55 <script> 56 import { toggle } from '../mixins/toggle.js' 57 import Child from './Child' 58 59 export default { 60 name: 'ToolTip', 61 mixins: [toggle], 62 components: { 63 Child 64 } 65 } 66 </script>
著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
原文: https://www.w3cplus.com/vue/vue-mixins.html © w3cplus.com著作權歸作者所有。