在 Vue.js 中使用混合 —— CSS-Tricks
有一種很常見的情況:有兩個非常相似的組件,它們共享同樣的基本函數,并且它們之間也有足夠的不同,這時你站在了一個十字路口:我是把它拆分成兩個不同的組件?還是只使用一個組件,創建足夠的屬性來改變不同的情況。
這些解決方案都不夠完美:如果你拆分成兩個組件,你就不得不冒著如果功能變動你要在兩個文件中更新它的風險,這違背了 DRY 前提。另一方面,太多的屬性會很快會變得混亂不堪,對維護者很不友好,甚至是你自己,為了使用它,需要理解一大段上下文,這會讓你感到失望。
使用混合。Vue 中的混合對編寫函數式風格的代碼很有用,因為函數式編程就是通過減少移動的部分讓代碼更好理解(引用于 Michael Feathers )。混合允許你封裝一塊在應用的其他組件中都可以使用的函數。如果被正確的使用,他們不會改變函數作用域外部的任何東西,所以多次執行,只要是同樣的輸入你總是能得到一樣的值。這真的很強大。
基礎實例
我們有一對不同的組件,它們的作用是切換一個狀態布爾值,一個模態框和一個提示框。這些提示框和模態框除了在功能上,沒有其他共同點:它們看起來不一樣,用法不一樣,但是邏輯一樣。
// 模態框
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
}
};
查看 Sarah Drasner( @sdras ) 在 CodePen 上編寫 混合 的例子
為了更容易理解混合,這個例子故意編寫的簡單一些。真實應用中使用混合的有,包含但不限于:獲取視窗和組件的尺寸,采集特定的鼠標事件和圖表的基本元素。Paul Pflugradt 有一個關于 Vue Mixins 的優秀項目 ,但值得一提的是它是用 coffeescript 編寫的。
用法
這個例子沒有告訴我們在一個真實的應用中如何使用,所以,我們看看接下來要怎么做。
你可以按照你喜歡的任意方式設置你的目錄結構,但為了更好的組織結構我喜歡新建一個 mixin 目錄。我們創建的這個文件含有 .js 擴展名(跟 .vue 相對,就像我們的其他文件),并且為了混合我們需要輸出一個對象。
接著在 Modal.vue 中使用它,通過像下面這樣的引入方式:
import Child from './Child'
import { toggle } from './mixins/toggle'
export default {
name: 'modal',
mixins: [toggle],
components: {
appChild: Child
}
}
即使我們使用的是一個對象而不是一個組件,生命周期函數對我們來說仍然是可用的,理解這點很重要。我們可以在這使用 mounted() 鉤子函數,它將被應用于組件的生命周期上,這種工作方式真的很靈活也很強大。
合并
看最后這個例子,我們可以看到,我們不僅有自己的函數,而且來自于混合的生命周期函數對我們來說也是可用的,所以當在組件上注冊重復的過程時,順序很重要。默認混合上會首先被注冊,組件上的接著注冊,這樣如有必要我們可以重寫它。 組件擁有最終發言權 當有一個沖突并且這個組件不得不“決定”哪個勝出的時候,這真的變得很重要,否則,所有的東西都被放在一個數組當中執行,混合中的先執行,組件中的接著執行。
//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() 函數。
全局混合
當我們使用全局混合時,我們不是指能夠在每個組件上訪問它們,就像是過濾器一樣。我們能夠通過 mixins:[toggle] 訪問組件上的混合對象。
全局混合被注冊到了 每個單一組件上 。因此,它們的使用場景極其有限并且要非常的小心。一個我能想到的用途就是它像一個插件,你需要賦予它訪問所有東西的權限。但即使在這種情況下,我也對你正在做的保持警惕,尤其是你在應用中擴展的函數,可能對你來說是不可知的。
為了創建一個全局實例,我們可以把它放在 Vue 實例之上。在一個典型的 Vue-cli 初始化的項目中,它可能在你的 main.js 文件中。
Vue.mixin({
mounted() {
console.log('hello from mixin!')
}
})
new Vue({
...
})
再次提醒,小心使用它!那個 console.log 將會出現在每個組件上。這種情況還不算壞(除了控制臺上有多余的輸出),但如果它被錯誤的使用,你將能看到它會多么的有害。
結論
混合對于封裝一小段想要復用的代碼來講是有用的。對你來說它們當然不是唯一可行的選擇:高階組件,例如,允許組合相似函數,這只是實現的一種方式。我喜歡混合,因為我不需要傳遞狀態,但是這種模式當然也可能會被濫用,所以,仔細思考哪種選擇對你的應用最有意義。
來自:http://www.zcfy.cc/article/using-mixins-in-vue-js-css-tricks-3257.html