從零實現Vue的元件庫(八)- Input 實現

FatGe發表於2019-01-01

基於原生的 HTML 標籤進行擴充的 Input 元件。

Input 元件一般是一個元件庫的基礎,很多元件都需要依賴它,所以該元件的特點在於:

  • 支援原生的功能,結合 this.$slots 擴充 slot,便於二次封裝;
  • v-modelv-on=$listeners的相關處理;
  • 樣式的封裝以及抽離。

1. 例項

最終效果

程式碼

<
!-- 基礎用法 -->
<
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 UI-Library

2. 原理

首先擴充 type 屬性,新增值為 textarea 的狀態,設計該元件的結構為 input 如下

<
div :class="['input-wrapper']">
<
textarea v-if="type === 'textarea'" class="textarea-inner" />
<
template v-else>
<
input :class="['input-inner']" :type="type" />
<
/template>
<
/div>
複製程式碼

基礎功能實現:

  • 新增 v-bind="$attrs" 指令,來實現原生 input 的相關屬性,例如 placeholderreadonlymaxlength等,在 input 以及 textarea 上,該指令能夠在元件上繫結父作用域中不作為 prop 被識別 (且獲取) 的特性 (class 和 style 除外);

  • 新增 v-on="$listeners"指令,實現元件上的 changefocusblur 事件,由於 Input 元件需要支援 v-model="inputValue" ,而在 input標籤 上 v-model 依賴 input 事件,其原理是

    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 value

    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>
複製程式碼

往期文章:

原創宣告: 該文章為原創文章,轉載請註明出處。

來源:https://juejin.im/post/5c2b1d1d6fb9a04a07307849

相關文章