携手创作,共同成长!这是我参与「日新计划 8 月更文挑战」的第17天,点击查看活动详情
简介
输入框组件 Input
通过鼠标或键盘输入表单域内容,提供复合型型输入框,带搜索的输入框,还可以进行大小选择。 本文将分析其源码实现,耐心读完,相信会对您有所帮助。 组件文档 Input gitee源码
更多组件剖析详见 Element 2 源码剖析组件总览 。
模板HTML
组件的props
声明,各属性功能描述详见官方文档Input#attributes。
组件根元素是一个类名为el-textarea
或el-input
的 div 元素,元素内容包含了三部分:
- 封装原生
input
控件实现单行文本输入框。 - 封装原生
textarea
控件多行文本输入文本域。
// packagesinputsrcinput.vue
<template>
<div :class="[type === 'textarea' ? 'el-textarea' : 'el-input',]" >
<!-- 单行文本输入框 -->
<template v-if="type !== 'textarea'">
<!-- 输入框前置内容 -->
<div class="el-input-group__prepend"></div>
<!-- 表单输入控件 -->
<input>
<!-- 输入框头部内容 -->
<span class="el-input__prefix"></span>
<!-- 输入框尾部内容 -->
<span class="el-input__suffix"></span>
<!-- 输入框后置内容 -->
<div class="el-input-group__append"></div>
</template>
<!-- 多行文本输入的文本域 -->
<textarea></textarea>
</div>
</template>
单行文本输入
单行文本输入框通过封装原生 input
控件实现,支持控件的原生属性。组件通过组合以下多种元素实现文本框 text
或密码框password
等复合型输入框功能:
- 输入框前置内容,提供具名插槽
prepend
,内容一般为标签或按钮。 - 原生 input 表单输入控件,添加了自定义事件。
- 输入框头部内容,可以通过
prefix-icon
或具名插槽prefix
增加显示图标。 - 输入框尾部内容,可以通过
suffix-icon
或具名插槽suffix
增加显示图标。该元素也用于展示输入框清空Icon、密码显隐切换Icon以及展示输入字数统计。 - 输入框后置内容,提供具名插槽
append
,内容一般为标签或按钮。
<template v-if="type !== 'textarea'">
<!-- 输入框前置内容 -->
<div class="el-input-group__prepend" v-if="$slots.prepend">
<slot name="prepend"></slot>
</div>
<!-- 表单输入控件 -->
<input
:tabindex="tabindex" // 元素是否可以聚焦 键盘导航
v-if="type !== 'textarea'"
class="el-input__inner"
v-bind="$attrs" // 透传 Attributes 例如 placeholder
:type="showPassword ? (passwordVisible ? 'text': 'password') : type" // text/password 也支持其他原生input的type值
:disabled="inputDisabled" // 是否禁用
:readonly="readonly" // 是否只读
:autocomplete="autoComplete || autocomplete" // 自动补全
ref="input"
@compositionstart="handleCompositionStart" // 输入法编辑器 (IME) 事件
@compositionupdate="handleCompositionUpdate"
@compositionend="handleCompositionEnd"
@input="handleInput" // 输入内容
@focus="handleFocus" // 获取焦点
@blur="handleBlur" // 失去焦点
@change="handleChange" // 输入值变化
:aria-label="label" // ARIA 无障碍属性
>
<!-- 输入框头部内容 -->
<span class="el-input__prefix" v-if="$slots.prefix || prefixIcon">
<slot name="prefix"></slot>
<i class="el-input__icon" v-if="prefixIcon" :class="prefixIcon"></i>
</span>
<!-- 输入框尾部内容 -->
<span class="el-input__suffix" v-if="getSuffixVisible()">
<span class="el-input__suffix-inner">
<template v-if="!showClear || !showPwdVisible || !isWordLimitVisible">
<slot name="suffix"></slot>
<i class="el-input__icon" v-if="suffixIcon" :class="suffixIcon"></i>
</template>
// ...
</span>
// ...
</span>
<!-- 输入框后置内容 -->
<div class="el-input-group__append" v-if="$slots.append">
<slot name="append"></slot>
</div>
</template>
组件渲染效果如下:
输入框头部/尾部都提供了具名插槽用于增加显示图标,当然也可以传入文本等其他内容,但不建议这么做。
当设置头部/尾部内容时, input 输入框通过属性 padding
提供了 30px
的宽度区域用于内容展示。头部/尾部元素使用绝对布局,将内容偏移覆盖至 padding 区域。
.el-input__prefix {
position: absolute;
height: 100%;
left: 5px;
top: 0;
}
.el-input__suffix {
position: absolute;
height: 100%;
right: 5px;
top: 0;
}
.el-input--prefix .el-input__inner{
padding-left: 30px;
}
.el-input--suffix .el-input__inner{
padding-right: 30px;
}
以下示例将自定义文本传入插槽。
<el-input placeholder="请输入内容" v-model="input">
<template slot="prefix">
<span style="display: flex; align-items: center; height: 100%">头部内容</span>
</template>
<template slot="suffix">
<span style="display: flex; align-items: center; height: 100%">尾部内容</span>
</template>
</el-input>
示例渲染出现内容覆盖
input 元素类型
组件默认使用 text
类型的input控件。当设置 showPassword
可得到一个可切换显示隐藏的密码框,内部属性passwordVisible
记录显隐状态,根据不同的状态使用 password
或 text
类型。
:type="showPassword ? (passwordVisible ? 'text': 'password') : type"
属性 type
值也可设置为其他原生input的type值。
<el-input v-model="input" placeholder="请输入内容" type="color"></el-input>
<el-input v-model="input" placeholder="请输入内容" type="date"></el-input>
<el-input v-model="input" placeholder="请输入内容" type="datetime-local"></el-input>
<el-input v-model="input" placeholder="请输入内容" type="file"></el-input>
<el-input v-model="input" placeholder="请输入内容" type="month"></el-input>
<el-input v-model="input" placeholder="请输入内容" type="time"></el-input>
<el-input v-model="input" placeholder="请输入内容" type="week"></el-input>
使用其他原生类型时组件渲染效果,但是一般不建议这么使用!一般组件类库都会提供对应的更加丰富的功能组件,使用库组件页面样式风格更加统一,提升用户交互体验。
输入法编辑器(IME)事件
输入法在中文、日文和韩文等少数语言中使用。以中文拼音输入法为例,输入的过程大致可以分为组字(composition) 和 提交(commit) 两阶段。比如想打“你好”两个字,会在输入框输入“nihao”的拼音,当输入第一个字母“n”时,组字过程就开始了。此时本地的 IME(input method editor) 软件(比如微软/搜狗拼音输入法)会为我们提供组字框和候选列表的 UI 组件。
关于输入法事件更多介绍,请阅读 Web 键盘输入法应用开发指南 —— 输入法事件。
compositionstart
、compositionupdate
和compositionend
是一组事件。
-
首先是使用拼音输入法开始输入汉字时
compositionstart
被触发,组字框和候选列表相应出现; -
此后,每按一个新键,就会触发
compositionupdate
,此时组字框和候选列表的内容也发生变化; -
当选择了候选列表中的某个字或词,或者敲击空格(中文输入法),
compositionend
事件会触发,表明输入被提交。 -
当取消输入时,比如使用鼠标单击页面空白处,就会终止当前输入,也会触发
compositionend
事件。
属性isComposing
值为 true
表示用户正在输入。输入结束后(选择字词或者取消),调用方法handleInput
,触发组件 input
事件。
// @compositionstart="handleCompositionStart"
// @compositionupdate="handleCompositionUpdate"
// @compositionend="handleCompositionEnd"
handleCompositionStart() {
this.isComposing = true; // 正在输入
},
handleCompositionUpdate(event) {
const text = event.target.value;
const lastCharacter = text[text.length - 1] || '';
// 韩文字符编码 判断最后一个字符是否特殊的功能键 Process Key
this.isComposing = !isKorean(lastCharacter);
},
handleCompositionEnd(event) {
// 输入结束后,触发 input 事件
if (this.isComposing) {
this.isComposing = false;
this.handleInput(event);
}
},
input/change 事件
- 当
<input>
、<select>
、<textarea>
元素的value
被修改时,会触发input
事件。 - 当用户更改
<input>
、<select>
、<textarea>
元素的值并提交这个更改时,change
事件在这些元素上触发。基于表单元素的类型和用户对标签的操作的不同,change
事件触发的时机也不同。
对于文本输入元素,比如<input type="text">
,每当元素的value
改变,input
事件都会被触,change
事件在控件失去焦点后才会触发。
// @input="handleInput"
// @change="handleChange"
handleInput(event) {
// 输入法下用户正在输入
if (this.isComposing) return;
// IE 11下 DatePicker组件 hack 写法,详见issues
// https://github.com/ElemeFE/element/issues/8548
// should remove the following line when we don't support IE
if (event.target.value === this.nativeInputValue) return;
// 触发触发当前实例上的input事件
this.$emit('input', event.target.value);
// Input 为受控组件 更新组件的绑定值
this.$nextTick(this.setNativeInputValue);
},
handleChange(event) {
// 触发触发当前实例上的change事件
this.$emit('change', event.target.value);
},
focus/blur 事件
元素获取或失去焦点时,调用事件监听方法,更新内部属性focused
记录元素焦点状态,同时触发实例自定义 focus
或 blur
事件。
// @focus="handleFocus"
// @blur="handleBlur"
handleFocus(event) {
this.focused = true;
// 触发触发当前实例上的focus事件
this.$emit('focus', event);
},
handleBlur(event) {
this.focused = false;
// 触发触发当前实例上的blur事件
this.$emit('blur', event);
if (this.validateEvent) {
this.dispatch('ElFormItem', 'el.form.blur', [this.value]);
}
},
关注专栏
如果本文对您有所帮助请关注➕、 点赞、 收藏⭐!您的认可就是对我的最大支持!
此文章已收录到专栏中 ,可以直接关注。