3.30 Input 输入框
简介
输入框组件 Input 通过鼠标或键盘输入表单域内容,提供复合型型输入框,带搜索的输入框,还可以进行大小选择。 本文将分析其源码实现,耐心读完,相信会对您有所帮助。🔗 组件文档 Input 🔗 gitee源码
更多组件剖析详见 👉 📚 Element 2 源码剖析组件总览 。
模板HTML
组件的 props 声明,各属性功能描述详见官方文档Input#attributes 。
组件根元素是一个类名为el-textarea或el-input的 div 元素,元素内容包含了三部分:
封装原生
input控件实现单行文本输入框。封装原生
textarea控件多行文本输入文本域。
// packages\input\src\input.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>组件根元素
属性
type值确定使用el-textarea或el-input。组件尺寸
inputSize生成样式el-input--medium/small/mini。禁用状态
inputDisabled生成样式is-disabled。开启输入长度限制,输入超限时
inputExceed生成样式is-disabled。复合型输入框样式
el-input-group、el-input-group--append/prepend根据前置/后置插槽内容生成。头部/尾部样式
el-input--prefix、el-input--suffix根据插槽内容或功能属性值生成。添加了鼠标移入移出事件,使用内部属性
hover记录元素悬停状态。
单行文本输入
单行文本输入框通过封装原生 input 控件实现,支持控件的原生属性。组件通过组合以下多种元素实现文本框 text或密码框password等复合型输入框功能:
输入框前置内容,提供具名插槽
prepend,内容一般为标签或按钮。原生 input 表单输入控件,添加了自定义事件。
输入框头部内容,可以通过
prefix-icon或具名插槽prefix增加显示图标。输入框尾部内容,可以通过
suffix-icon或具名插槽suffix增加显示图标。该元素也用于展示输入框清空Icon、密码显隐切换Icon以及展示输入字数统计。输入框后置内容,提供具名插槽
append,内容一般为标签或按钮。
组件渲染效果如下:
输入框头部/尾部都提供了具名插槽用于增加显示图标,当然也可以传入文本等其他内容,但不建议这么做。
当设置头部/尾部内容时, input 输入框通过属性 padding 提供了 30px 的宽度区域用于内容展示。头部/尾部元素使用绝对布局,将内容偏移覆盖至 padding 区域。
以下示例将自定义文本传入插槽。
示例渲染出现内容覆盖
input 元素类型
组件默认使用 text 类型的input控件。当设置 showPassword可得到一个可切换显示隐藏的密码框,内部属性passwordVisible记录显隐状态,根据不同的状态使用 password 或 text 类型。
属性 type 值也可设置为其他原生input的type值。
使用其他原生类型时组件渲染效果,但是一般不建议这么使用!一般组件类库都会提供对应的更加丰富的功能组件,使用库组件页面样式风格更加统一,提升用户交互体验。
输入法编辑器(IME)事件
输入法在中文、日文和韩文等少数语言中使用。以中文拼音输入法为例,输入的过程大致可以分为组字(composition) 和 提交(commit) 两阶段。比如想打“你好”两个字,会在输入框输入“nihao”的拼音,当输入第一个字母“n”时,组字过程就开始了。此时本地的 IME(input method editor) 软件(比如微软/搜狗拼音输入法)会为我们提供组字框和候选列表的 UI 组件。
关于输入法事件更多介绍,请阅读 Web 键盘输入法应用开发指南 —— 输入法事件。
compositionstart、compositionupdate和compositionend是一组事件。
首先是使用拼音输入法开始输入汉字时
compositionstart被触发,组字框和候选列表相应出现;此后,每按一个新键,就会触发
compositionupdate,此时组字框和候选列表的内容也发生变化;当选择了候选列表中的某个字或词,或者敲击空格(中文输入法),
compositionend事件会触发,表明输入被提交。当取消输入时,比如使用鼠标单击页面空白处,就会终止当前输入,也会触发
compositionend事件。
属性isComposing值为 true表示用户正在输入。输入结束后(选择字词或者取消),调用方法handleInput,触发组件 input 事件。
input/change 事件
当
<input>、<select>、<textarea>元素的value被修改时,会触发input事件。当用户更改
<input>、<select>、<textarea>元素的值并提交这个更改时,change事件在这些元素上触发。基于表单元素的类型和用户对标签的操作的不同,change事件触发的时机也不同。
对于文本输入元素,比如 <input type="text">,每当元素的 value 改变,input 事件都会被触,change 事件在控件失去焦点后才会触发。
对于需要使用输入法的语言, v-model 不会在输入法组合文字过程中得到更新,因为compositionend事件没触发是不会执行handleInput逻辑。
focus/blur 事件
元素获取或失去焦点时,调用事件监听方法,更新内部属性focused记录元素焦点状态,同时触发实例自定义 focus 或 blur 事件。
provide/inject 依赖注入
在 Form 组件中,每一个表单域由一个 Form-Item 组件构成,表单域中可以放置各种类型的表单控件,包括 Input、Select、Checkbox、Radio、Switch、DatePicker、TimePicker等。
表单form和表单域form-item使用provide 选项指定给后代组件的状态,避免了 prop 逐级透传 。
组件 input 使用inject选项注入上层组件提供的数据,如尺寸、校验、禁用,用于组件内部状态的控制计算。
生命周期
在生命周期钩子created、mounted、updated中,添加监听事件,初始化组件状态。
组件对属性 value、 nativeInputValue、 type添加了侦听器,用于状态更新以及关联表单验证事件。
下面逐一介绍下代这些方法的功能和作用。
select()
方法 select 用于选中输入控件的所有内容。
setNativeInputValue()
方法setNativeInputValue用于设置原生控件的 value 属性,该属性时一个包含了文本框当前文字的DOMString。原生控件的value值默认是空字符串 ("").
计算属性nativeInputValue 用于将输入内容格式化成字符串。
在方法setNativeInputValue中使用nativeInputValue更新属性value值。
resizeTextarea()
方法resizeTextarea用来设置文本域的大小,这个讲解 <textarea>详细介绍。
updateIconOffset()
方法updateIconOffset 根据前置/后置内容元素的 offsetWidth,在水平方向移动头部/尾部内容元素。
v-model
指令v-model常用于在表单输入元素(<input>、<textarea> 、 <select>)创建双向绑定数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
它会根据所使用的元素类型自动使用对应的 DOM 属性和事件组合:
文本类型的
<input>和<textarea>元素会绑定valueproperty 并侦听input事件;<input type="checkbox">和<input type="radio">会绑定checkedproperty 并侦听change事件;<select>会绑定valueproperty 并侦听change事件。
v-model会忽略任何表单元素上初始的value、checked或selectedattribute。它将始终将当前绑定的 JavaScript 状态视为数据的正确来源。你应该在 JavaScript 中使用data选项来声明该初始值。
v-model 本质是个语法糖,以组件el-input为例
上面的代码其实等价于下面这段 (编译器会对 v-model 进行展开):
所以在组件 input 的 props 选项里声明 value 时必须的,这也是文档中为什么会说属性 value/v-model 都是绑定值
当组件el-input属性 value 最新值需要更新到父组件属性searchText时,就会使用$emit触发实例 input 事件,实现双向绑定。
所以官方文档这句话 Input 为受控组件,它总会显示 Vue 绑定值 也就不难理解了。
单行文本输入 input
后置内容
后置内容不止用于展示图标,还提供了内容清空、密码显隐、输入文字统计以及表单验证状态图标等内容。
后置内容元素渲染由很多数据状态控制。
可清空
使用clearable属性即可得到一个可清空的输入框。 计算属性showClear根据组件状态、输入内容等判断功能是否开启。
图标绑定 click 事件 ,调用方法 clear ,更新v-model值,触发组件实例的change、clear等自定义事件。
密码框
使用show-password属性即可得到一个可切换显示隐藏的密码框。
图标绑定 click 事件 ,调用方法 handlePasswordVisible ,更新内部属性passwordVisible值,因为密码显隐是通过渲染不同类型 (text 或password) 的input控件实现,此时DOM会重新渲染,所以使用$nextTick,调用方法focus重新获取元素的焦点。
输入长度限制
通过设置 show-word-limit 属性来展示字数统计。只能对类型为 text 或 textarea 的输入框生效, 使用原生maxlength属性限制最大输入长度 。
使用了计算属性 textLength、 upperLimit 显示了输入进度。
计算属性upperLimit 返回最大输入长度,使用$attrs获取原生属性 maxlength值。
计算属性textLength返回当前输入内容的长度
计算属性 inputExceed 判断是否输入超限,用于生成组件根元素的样式is-exceed。
表单验证结果反馈图标
当组件在表单中使用,表单form设置属性status-icon为输入框添加了表示校验结果的反馈图标。
组件实现渲染效果如下:
文本域 textarea
组件通过封装原生 textarea 控件实现多行文本输入文本域功能。组件做了封装统一处理,所以textarea 控件的属性/事件跟input控件是相似的。
控件缩放
控件textarea 控件通过绑定计算属性textareaStyle设置内联样式,实现控件的高度自适应、文本区大小可调整。
计算属性textareaStyle中使用了内部属性textareaCalcStyle和prop属性 resize。
属性
textareaCalcStyle值为文本域的高度属性(height、min-height)样式,在方法resizeTextarea中由文本域内容和配置项计算生成。属性
resize控制文本区是否可调整大小。none元素不能被用户缩放。both允许用户在水平和垂直方向上调整元素的大小。horizontal允许用户在水平方向上调整元素的大小。vertical允许用户在垂直方向上调整元素的大小。
可自适应文本高度
方法 resizeTextarea用来改变文本域的高度大小的。实例挂载时会调用该方法,当实例类型、输入框的值改变时也会多次调用该方法。
通过设置 autosize 属性可以使得文本域的高度能够根据文本内容自动进行调整,并且 autosize 还可以设定为一个对象,指定最小行数和最大行数。
calcTextareaHeight.js
类库导出方法calcTextareaHeight,用于动态计算文本域的高度样式。
calculateNodeStyling()
方法 calculateNodeStyling 用于获取实例文本域元素节点的样式,并计算box-sizing相关属性值。
contextStyle复制当前实例元素的样式用于创建隐藏文本域。通过window.getComputedStyle()获取元素计算后/渲染后的所有 CSS 属性的值,然后获取数组CONTEXT_STYLE中指定属性值生成样式对象并转化字符串。boxSizing获取元素box-sizing属性值。paddingSize获取元素上下内边距和。borderSize获取元素上下边框宽度和。
calcTextareaHeight()
方法 calcTextareaHeight通过创建一个跟实例元素一样的临时文本域,用于计算出自适应高度。
创建临时文本域元素
hiddenTextarea,获取实例元素的内容和样式值、内容赋值给临时元素,使其作为实例元素的复制镜像。通过样式HIDDEN_STYLE用于隐藏临时元素使其不可见。获取元素内容高度
scrollHeight,根据不同box-sizing属性计算出元素总高度。计算出单行文本行高度
singleRowHeight。如果设置
minRows,计算出元素属性min-height值。如果设置
maxRows,计算出元素最大高度,实际 height 不能超过最大高度。清除临时文本域元素。
返回计算结果,格式
{ height:20px }或{ height:20px; minHeight:20px; }。
属性scrollHeight是一个元素内容高度,包括由于溢出导致的视图中不可见内容。包括元素的 padding,但不包括元素的 border 和 margin。
属性 box-sizing 定义了如何计算一个元素的总宽度和总高度。
content-box默认值,标准盒子模型。width与height只包括内容的宽和高,不包括边框(border),内边距(padding),外边距(margin)。width= 内容的宽度height= 内容的高度
border-boxwidth与height属性包括内容,内边距和边框,但不包括外边距。width= border + padding + 内容的宽度height= border + padding + 内容的高度
样式实现
组件样式源码 packages\theme-chalk\src\input.scss 使用混合指令嵌套生成组件样式。
混合指令scroll-bar定义如下:
📚参考&关联阅读
"getComputedStyle",MDN "CSS/box-sizing",MDN "Element/scrollHeight",MDN "表单输入绑定",vuejs "input_event",MDN "change_event",MDN "Input/text",MDN "String",MDN
最后更新于