Vue中的Mixins


在項目開發的時候,常會碰到這樣的一種現象:有兩個組件非常相似,比如較為熟悉的 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  中輸出的結果如下:

Vue2.0學習筆記:Vue中的Mixins

從輸出的結果中我們可以看出,  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>

Vue2.0學習筆記:Vue中的Mixins

最終的結果是, 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 })

Vue2.0學習筆記:Vue中的Mixins

值為對象選項合並

當 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 };

Vue2.0學習筆記:Vue中的Mixins

全局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著作權歸作者所有。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM