常見場景
有兩個非常相似的元件,他們的基本功能是一樣的,但他們之間又存在着足夠的差異性,此時的你就像是來到了一個分岔路口:我是把它拆分成兩個不同的元件呢?還是保留為一個元件,然後通過props傳值來創造差異性進而進行區分呢?
兩種解決方案都不夠完美:如果拆分成兩個元件,你就不得不冒着一旦功能變動就要在兩個檔案中更新代碼的風險,這違背了 DRY 原則。反之,太多的props傳值會很快變得混亂不堪,進而迫使維護者(即便這個人是你)在使用元件的時候必須了解一大段的上下文,拖慢寫碼速度。
使用Mixin。Vue 中的Mixin對編寫函數式風格的代碼很有用,因為函數式程式設計就是通過減少移動的部分讓代碼更好了解(引自 Michael Feathers )。Mixin允許你封裝一塊在應用的其他元件中都可以使用的函數。如果使用姿勢得當,他們不會改變函數作用域外部的任何東西,是以哪怕執行多次,隻要是同樣的輸入你總是能得到一樣的值,真的很強大!
基礎執行個體
我們有一對不同的元件,它們的作用是通過切換狀态(Boolean類型)來展示或者隐藏模态框或提示框。這些提示框和模态框除了功能相似以外,沒有其他共同點:它們看起來不一樣,用法不一樣,但是邏輯一樣。
// 模态框
const Modal = {
template: '#modal',
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
},
components: {
appChild: Child
}
}
// 提示框
const Tooltip = {
template: '#tooltip',
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
},
components: {
appChild: Child
}
}
我們可以在這裡提取邏輯并建立可以被重用的項:
const toggle = {
data() {
return {
isShowing: false
}
},
methods: {
toggleShow() {
this.isShowing = !this.isShowing;
}
}
}
const Modal = {
template: '#modal',
mixins: [toggle],
components: {
appChild: Child
}
};
const Tooltip = {
template: '#tooltip',
mixins: [toggle],
components: {
appChild: Child
}
};
用法
你可以按照你喜歡的任意方式設定你的目錄結構,但為了結構規整我喜歡建立一個mixin目錄。我們建立的這個檔案含有.js擴充名(跟.vue相對,就像我們的其他檔案),為了使用Mixin我們需要輸出一個對象。
目錄結構.jpg
在Modal.vue使用這樣的寫法,來引入這個Mixin:
import Child from './Child'
import { toggle } from './mixins/toggle'
export default {
name: 'modal',
mixins: [toggle],
components: {
appChild: Child
}
}
即便我們使用的是一個對象而不是一個元件,生命周期函數對我們來說仍然是可用的,了解這點很重要。我們也可以這裡使用mounted()鈎子函數,它将被應用于元件的生命周期上。這種工作方式真的很靈活也很強大。
合并
在下面的這個例子,我們可以看到,我們不僅僅是實作了自己想要的功能,并且Mixin中的生命周期的鈎子也同樣是可用的。是以,當我們在元件上應用Mixin的時候,有可能元件與Mixin中都定義了相同的生命周期鈎子,這時候鈎子的執行順序的問題凸顯了出來。預設Mixin上會首先被注冊,元件上的接着注冊,這樣我們就可以在元件中按需要重寫Mixin中的語句。元件擁有最終發言權。當發生沖突并且這個元件就不得不“決定”哪個勝出的時候,這一點就顯得特别重要,否則,所有的東西都被放在一個數組當中執行,Mixin将要被先推入數組,其次才是元件。
//mixin
const hi = {
mounted() {
console.log('hello from mixin!')
}
}
//vue instance or component
new Vue({
el: '#app',
mixins: [hi],
mounted() {
console.log('hello from Vue instance!')
}
});
//Output in console
> hello from mixin!
> hello from Vue instance!
如果這兩個沖突了,我們看看 Vue執行個體或元件是如何決定輸赢的:
//mixin
const hi = {
methods: {
sayHello: function() {
console.log('hello from mixin!')
}
},
mounted() {
this.sayHello()
}
}
//vue instance or component
new Vue({
el: '#app',
mixins: [hi],
methods: {
sayHello: function() {
console.log('hello from Vue instance!')
}
},
mounted() {
this.sayHello()
}
})
// Output in console
> hello from Vue instance!
> hello from Vue instance!
你可能已經注意到這有兩個console.log而不是一個——這是因為第一個函數被調用時,沒有被銷毀,它隻是被重寫了。我們在這裡調用了兩次sayHello()函數。
結論
Mixin對于封裝一小段想要複用的代碼來講是有用的。對你來說Mixin當然不是唯一可行的選擇:比如說高階元件就允許你組合相似函數,Mixin隻是的一種實作方式。我喜歡Mixin,因為我不需要傳遞狀态,但是這種模式當然也可能會被濫用,是以,仔細思考下哪種選擇對你的應用最有意義吧!
連結:https://www.jianshu.com/p/1bfd582da93e