Input 元件一般是一個元件庫的基礎,很多元件都需要依賴它,所以該元件的特點在於:基於原生的 HTML 標籤進行擴充的 Input 元件。
- 支援原生的功能,結合
this.$slots
擴充slot
,便於二次封裝; v-model
與v-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
的相關屬性,例如placeholder
、readonly
、maxlength
等,在input
以及textarea
上,該指令能夠在元件上繫結父作用域中不作為 prop 被識別 (且獲取) 的特性 (class 和 style 除外); -
新增
v-on="$listeners"
指令,實現元件上的change
、focus
、blur
事件,由於 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"
繫結到元件上,同時 watchvalue
,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>
複製程式碼
往期文章:
- 從零實現Vue的元件庫(零)- 基本結構以及構建工具
- 從零實現Vue的元件庫(一)- Toast 實現
- 從零實現Vue的元件庫(二)- Slider 實現
- 從零實現Vue的元件庫(三)- Tabs 實現
- 從零實現Vue的元件庫(四)- File-Reader 實現
- 從零實現Vue的元件庫(五)- Breadcrumb 實現
- 從零實現Vue的元件庫(六)- Hover-Tip 實現
- 從零實現Vue的元件庫(七)- Message-Box 實現
- 從零實現Vue的元件庫(八)- Input 實現
- 從零實現Vue的元件庫(九)- InputNumber 實現
- 從零實現Vue的元件庫(十)- Select 實現
- 從零實現Vue的元件庫(十一)- Date-picker 實現
- 從零實現Vue的元件庫(十二)- Table 實現
- 從零實現Vue的元件庫(十三)- Pagination 實現
- 從零實現Vue的元件庫(十四)- RadioGroup 實現
- 從零實現Vue的元件庫(十五)- CheckboxGroup 實現
原創宣告: 該文章為原創文章,轉載請註明出處。