天天看點

vue之mixin了解與使用

常見場景

有兩個非常相似的元件,他們的基本功能是一樣的,但他們之間又存在着足夠的差異性,此時的你就像是來到了一個分岔路口:我是把它拆分成兩個不同的元件呢?還是保留為一個元件,然後通過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我們需要輸出一個對象。

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