如何抽象一個 Vue 公共組件

以前一直想寫一篇關於抽象 Vue 組件的隨筆,無奈一直沒想到好的例子。恰巧最近爲公司項目作了一個數字鍵盤的組件,因而就以這個爲例聊聊如何抽象 Vue 的組件。html

先上 Demo源碼。(demo最好在瀏覽器裏以手機模式瀏覽)vue

 

在講具體實現前,我想先分享下本身認爲的理想的公用組件是什麼樣的:git

1. 黑盒性,即除了你本身之外,其餘的開發者在快速閱讀使用文檔以後能夠馬上上手,而不用關心你的內部實現;github

2. 獨立性,即作好解耦,不與父組件有過多關聯;數組

3 自定義性,適當地暴露一些輸入接口或者方法給外部用於自定義,同時也要設置好這些屬性在外部未輸入時的默認值。瀏覽器

 

下面咱們先以黑盒的方式看看 demo 中數字鍵盤組件是如何調用的(已省略非關鍵部分代碼)。dom

App.vueide

<template>
......
    <keyboard @submit-event='handleSubmit' @change-event='handleChange'></keyboard>
</template>
<script>
import keyboard from 'Keyboard.vue';
export default {
    data() {
        return {
            value: ''
        };
    },
    methods: {
        handleChange(value, currentValue) {
            console.log(value, currentValue);
            this.value = value;
        },
        handleSubmit() {
            console.log('submit: ' + this.value);
        }
    }
}
</script>

如上,最基本的調用就完成了。效果以下:函數

接着,點擊 1-6 與「肯定」。若是以下:佈局

能夠看到數字鍵盤已經如咱們預期工做了,接下來分析下該數字鍵盤組件全部的輸入項。

@change-event:該事件爲自定義事件,父組件經過 v-on 註冊監聽,子組件內部經過 $emit 進行觸發(更多自定義事件相關內容請參考:Vue官方教程)。

每一次點擊數字按鍵以及退格鍵均會觸發該事件,其傳遞兩個參數:value,累積點擊的字符組合;currentValue,當前點擊的字符。父組件經過 handleChange 方法接收該事件的回調內容。

@submit-event:當點擊「肯定」鍵即會觸發該事件,其不傳遞參數,只是告訴父組件「個人肯定按鈕被點擊了,你要作什麼操做本身看着辦吧,以前點擊的數字已經經過 change-event 傳給你了」。父組件經過 handleSubmit 方法接收回調。

若是隻寫這兩個方法未免也太沒誠意了,我還根據一些場景編寫了如下幾個自定義屬性。

max:最大輸入長度,超過的部分將不會觸發 change-event 事件,默認無限制。

<keyboard max='6'></keyboard>

sp-key:自定義的特殊字符,如身份證輸入時的「X」,會添加到左下角空白格,默認無。

<keyboard sp-key='X'></keyboard>

random:是否打亂數字順序,一些有關銀行帳戶或密碼的輸入常常會見到這種場景,默認 false。

<keyboard random='true'></keyboard>

從上面的幾個自定義屬性與事件,咱們大概知道了父組件是如何向子組件傳值以及監聽子組件的變化,但父組件該如何直接調用子組件內部的函數呢?咱們看下面這個場景。

數字鍵盤上的鍵盤圖標,點擊以後會將數字鍵盤收起隱藏。組件內部擁有一個方法 keyboardToggle(true|false) 來控制鍵盤的彈起和收回,那麼若是在組件外部也想調用這個方法呢?好比當父組件中的 input 獲取到焦點時。

能夠經過 Vue 中的 ref 屬性來獲取到鍵盤的組件引用,從而調用其內部的方法,以下:

$refs.[refName].keyboardToggle(true|false)

<template>
    <input type='text' @focus='handleShowKeyboard($event)' />
    <keyboard ref='kbref'></keyboard>
</template>
<script>
import keyboard from 'Keyboard';
export default {
    //...
    methods: {
        handleShowKeyboard(e) {
            e && e.preventDefault();
            this.$refs.kbref.keyboardToggle(true);
        }
    }
}
</script>

以上面這種形式即可以在父組件上下文中調用子組件內的方法。

$refs.[refName].handleInit()

數字鍵盤組件內部的初始化方法,用於從新渲染組件。若 random 屬性爲 true,則數字鍵會刷新隨機排列。

$refs.[refName].handleClear()

清除以前輸入的字符組合,並觸發 change-event 且返回空字符串。

 

上面分享了這個組件全部對外的屬性與事件,能夠發現咱們並未看過該組件內部的一行代碼,但已經能夠完整的使用它了,下面來聊聊內部實現。

首先來看看佈局,我將鍵盤分爲左右兩部分,右邊部分不用多說,左邊的部分是將一個鍵位數組經過 v-for 循環生成。

那麼是如何讓 0 和 9 之間空出一格呢,下面看下初始化鍵盤組件的方法。

keyboard.vue

handleInit()

<template>
    <div>
        <div class='kb-left'>
            <div class='kb-item' v-for='item in keyArr'>{{item}}</div>
            <div class='kb-item kb-toggle'></div> //鍵盤圖標
        </div>
        <div class='kb-right'>
            //...        
        </div>
    </div>
</template>
<script>
export default {
    data() {
        return {
            baseArr: []
        }
    },
    computed: {
        keyArr() {
            this.handleInit();
            return this.baseArr;
        }
    },
    methods: {
        handleInit() {
            this.baseArr = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
            this.baseArr.splice(this.baseArr.length - 1, 0, '');
        }
    }
}
</script>

即在鍵位數組倒數第二位插入一個空字符,而後循環生成按鍵。下面看下自定義參數是如何生效的。

sp-key

<script>
export default {
    props: ['spKey'],
    data() {
        return {
            baseArr: []
        }
    },
    //....
    methods: {
        handleInit() {
            let spKey = this.spKey;
            this.baseArr = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];

       this.baseArr.splice(this.baseArr.length - 1, 0, spKey); } } } </script>

在組件內部經過 props 屬性接收父組件傳遞的 spKey,以後就可在組件內的屬性和方法中經過 this.spKey 進行訪問。首先判斷 spKey 值是否有效,並代替空字符插入鍵位數組倒數第二項。

random

<script>
export default {
    props: ['spKey', 'random'],
    data() {
        return {
            baseArr: []
        }
    },
    //....
    methods: {
        handleInit() {
            let spKey = this.spKey;
            this.baseArr = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];

          if (this.random && this.random != 'false') {
             this.baseArr.sort(function() {
               return Math.random() - Math.random();
            });
           }

            this.baseArr.splice(this.baseArr.length - 1, 0, spKey);
        }
    }
}
</script>

將鍵位打亂順序其實也很簡單,只要經過數組的 sort 方法。sort 方法能夠接收一個函數做爲參數,若函數返回正數則交換先後兩項的位置,若函數返回負數則不做交換。因此將兩個隨機數相減的結果返回,便可將鍵位數組隨機排序。

下面看看在組件內部是如何觸發 change-event 的。

handleInput()

<template>
    <div>
        <div class='kb-left'>
            <div @click='handleInput(item)' class='kb-item' v-for='item in keyArr'>{{item}}</div>
            <div class='kb-item kb-toggle'></div> //鍵盤圖標
        </div>
        //...
    </div>
</template>
<script>
export default {
    data() {
        return {
            inputStr: ''
        }
    },
    //...
    methods: {
        handleInput(value) {
            this.inputStr += value;
            this.$emit('change-event', this.inputStr, value);
        }
    }
}
</script>

增長了 max 屬性後修改方法以下:

handleInput(value) {
    let max = Number(this.max);
    if (!isNaN(max) && this.inputStr.length+1 > max) {
        return;
    }

    this.inputStr += value;
    this.$emit('change-event', this.inputStr, value);
}

最後看看退格刪除是如何實現的。

handleDelete()

handleDelete() {
    let str = this.inputStr;
   if (!str.length) return;

    this.inputStr = str.substring(0, str.length - 1);
    this.$emit('change-event', this.inputStr);
} 

上面的例子都是些核心代碼的片斷,而且其餘輔助函數並未列出,想查看完整的代碼請看源碼

 

感謝你的瀏覽,但願能有所幫助。

相關文章
相關標籤/搜索