Input组件
写在开头:在学习源码前要熟悉vue
的语法,比如$slot
,$attr
,双向绑定…毕竟ElementUI是基于vue
开发的。其次学习源码过程中一定要经常翻源码文件,如果能主动思考某一属性或事件实现方式是最快速理解源码的方式。
Input
组件的源码地址:https://github.com/ElemeFE/element/blob/dev/packages/input/src/input.vue
value/v-model双向绑定
毫无疑问双向绑定是每个组件最重要的属性,在实现双向绑定前要掌握vue组件双向绑定的语法,实现Input
的双向绑定还是非常简单的。
// DInputText.vue
<template>
<input type='text' :value="value" @input="handleInput">
</template>
<script>
export default {
props: {
value: {type: String, default: ''},
}
handleInput(event) {
this.$emit('input', event.target.value)
}
}
</script>
在输入框内容更改时通过触发input
组件原生@input
事件,向父组件抛出修改后的内容从而更新值。但是在ElementUI中Input
组件并不是通过这种方式实现双向绑定。在源码中并没有看到给组件绑定:value
属性,源码如图。
Input
组件实际上是通过主动修改input value
属性,有一个计算属性nativeInputValue
,同时监听这个属性的变化来触发设置input value
属性值。
原生属性max-length、min-length、placeholder、autofocus、name…
原生属性如果没有在组件内做额外的逻辑封装,通常都可以通过$attrs
透传语法来实现。在input
标签上绑定了v-bind="$attrs"
,通过打印就会找到这些属性。
prefix、suffix头尾部内容
亲身体验一把,手敲了一部分代码,便于理解其组件封装思想。
<template>
<div
:class="[
'dh-input',
{
'dh-input--prefix': $slots.prefix,
'dh-input--suffix': $slots.suffix
}
]"
>
<input class="dh-input__inner" :value="value" @input="handleInput">
<!-- 前置图标 -->
<span class="dh-input__prefix">
<slot name="prefix" />
</span>
<!-- 后置图标 -->
<span class="dh-input__suffix">
<slot name="suffix" />
</span>
</div>
</template>
内置在输入框里面的效果是要通过定位样式,头尾部自定义内容是通过$slots
语法来实现。当头尾部有内容是动态加个padding
值为了效果更美观,输入内容不会盖到自定义内容上面。
.dh-input {
position: relative;
&__inner {
box-sizing: border-box;
height: 40px;
line-height: 40px;
padding: 0 15px;
}
&--suffix .dh-input__inner {
padding-right: 30px;
}
&--prefix .dh-input__inner {
padding-left: 30px;
}
}
.dh-input__prefix {
position: absolute;
left: 5px;
height: 100%;
top: 0;
text-align: center;
}
.dh-input__suffix {
position: absolute;
right: 5px;
height: 100%;
top: 0;
text-align: center;
}
clearable、show-password、show-word-limit属性
之所以把这几个属性放在一起是因为在Input
组件中它们的实现效果类似,在结构上都是在后置内容区域加入图标,根据是否传入对应属性来判断显示,再给图标绑定相应事件。
对于清除按钮:清除输入框内容,向外抛出clear
事件用于清楚回调。
对于控制密码显示按钮:组件内部声明了passwordVisible
变量,点击后置反,如果密码显示控制输入框type
为text
,不显示说为password
blur、focus、change事件
这三类事件要么HTMLInputElement
的API,要么是Element
的API,都是之间绑定在元素上,在触发时向外抛出事件本身即可。
blur、focue方法
通过给父元素绑定$refs
可以调用Input
组件的这两种方法,所以在组件内部一定是有这两种方法的,实现方式是获取Input
元素实例拿到元素,调用input
元素原生方法。代码思想如下,其中Dtext是input
元素
getInput() {
return this.$refs.DText;
},
focus() {
this.getInput().focus();
},
blur() {
this.getInput().blur();
},
那写到这里对于我使用过Input
组件的场景包含的属性和方法,基本上已经覆盖了,在看源码的过程中我发现组件内部有很多文档中没有的属性和方法,我猜测是为了组件相互嵌套的时候所使用的,比如在一个Form
表单组件中嵌套Input
组件,进行校验等等,那后面把整个组件源码学习差不多了,大概有整体框架思想的时候再回来细化这部分内容。
但有个事情还需要弄明白就是Input
组件并不支持v-model
使用修饰符,原因是啥,如何判断输入的是数组还是字符。