Input 實現

基於原生的 HTML 標籤進行拓展的 Input 組件。html

Input 組件通常是一個組件庫的基礎,不少組件都須要依賴它,因此該組件的特色在於:
  • 支持原生的功能,結合 this.$slots 拓展 slot,便於二次封裝;
  • v-modelv-on=$listeners的相關處理;
  • 樣式的封裝以及抽離。

1. 實例

最終效果

代碼git

<!-- 基礎用法 -->
<fat-input placeholder="請輸入內容" v-model="inputValue" />

<!-- 複合型輸入框 -->
<fat-input placeholder="請輸入內容">
    <template slot="prepend">
        <div class="prepend-part c-size-s">Http://</div>
    </template>

    <template slot="append">
        <div class="append-part c-size-s">.com</div>
    </template>
</fat-input>
複製代碼

實例地址:Input 實例github

代碼地址:Github UI-Librarybash

2. 原理

首先拓展 type 屬性,添加值爲 textarea 的狀態,設計該組件的結構爲 input 以下app

<div :class="['input-wrapper']">
    <textarea
        v-if="type === 'textarea'"
        class="textarea-inner"
    />

    <template v-else>
        <input
            :class="['input-inner']"
            :type="type"
        />
    </template>
</div>
複製代碼

基礎功能實現:ui

  • 添加 v-bind="$attrs" 指令,來實現原生 input 的相關屬性,例如 placeholderreadonlymaxlength等,在 input 以及 textarea 上,該指令可以在組件上綁定父做用域中不做爲 prop 被識別 (且獲取) 的特性 (class 和 style 除外);this

  • 添加 v-on="$listeners"指令,實現組件上的 changefocusblur 事件,因爲 Input 組件須要支持 v-model="inputValue" ,而在 input標籤 上 v-model 依賴 input 事件, 其原理是spa

    event => this.$emit("input", event.target.value)
    複製代碼

    可是直接使用時,$emit("input", arg)arg 是一個 [object InputEvent],與實際應用狀況不服, 二者會報異常,這時利用 computed 屬性對 $listeners 進行修改設計

    export default {
        model: {
            prop: "value",
            event: "input"
        },
        computed: {
            inputListeners() {
                return Object.assign({}, this.$listeners, {
                    input: event => this.$emit("input", event.target.value)
                });
            }
        }
    };
    複製代碼

    而後再利用 v-on="inputListeners" 綁定到組件上,同時 watch valuecode

    watch: {
        value: {
            handler(newVal) {
                this.inputValue = newVal;
            },
            // 添加immediate,減小created生命週期中的賦值
            immediate: true
        }
    }
    複製代碼

樣式拓展實現:

  • 添加icon(非 textarea 時生效),添加
    <fat-icon v-if="prefixIcon" class="icon" :name="prefixIcon"/>
    
    <input
        :class="['input-inner']"
        :type="type"
        :value="inputValue"
        v-bind="$attrs"
        v-on="inputListeners"
    />
    
    <fat-icon v-if="suffixIcon" class="icon" :name="suffixIcon"/>
    複製代碼
  • 實現複合型輸入框時,主要依靠具名插槽
    <slot name="prepend"></slot>
    
    <input
        :class="['input-inner', { 'have-prepand': havePrepand, 'have-append': haveAppend }]"
        :type="type"
        :value="inputValue"
        v-bind="$attrs"
        v-on="inputListeners"
    />
    
    <slot name="append"></slot>
    複製代碼
    而且爲了兼容樣式,須要對 input-inner 添加兩個類,have-prepand 以及 have-append,它們的狀態主要是檢查 this.$slots 對象
    computed: {
        havePrepand() {
            return this.$slots.prepend;
        },
        haveAppend() {
            return this.$slots.append;
        }
    }
    複製代碼

3. 使用

因爲上述實現過程,都是在原生的 Input 組件進行的拓展,在實際應用時,可結合業務進行封裝以及抽象。 使用時,主要注意點兩個具名插槽的使用。

<div class="demo-row-content">
    <fat-input placeholder="請輸入內容"> <template slot="prepend"> <div class="prepend-part c-size-s">Http://</div> </template> <template slot="append"> <div class="append-part c-size-s">.com</div> </template> </fat-input> </div>
複製代碼

原創聲明: 該文章爲原創文章,轉載請註明出處。

相關文章
相關標籤/搜索