1、前言
今天写的这个组件是平时很常用的一个,输入框(Input)组件,常用于各种表单中。那么话不多说,直接开始造轮子吧。
2、Input组件-需求
首先造一个组件,得需要知道它的需求是吧,不然需求不清楚,在写的过程中就会很痛苦,我在写输入框的时候,主要考虑了以下这几个需求:
- 输入状态(包括提示,报错)
- 不可输入
disabled - 只读状态
readonly - 支持输入框中自定义图标
icon图标的位置- 输入时的事件
以上就是我在做Input组件时想到的几个点,其它一些复杂的功能就没考虑啦。
3、Input组件-实现
明确需求之后,那么就要想一下用户使用组件的API了,大概就是如下进行调用:
<y-input value="hello world"></y-input>
<y-input v-model="value" readonly></y-input>
<y-input v-model="value" disabled></y-input>
<y-input value="hello world" error="输入格式不对"></y-input>
<y-input value="" icon="settings" placeholder="enter something"></y-input>
上面主要列了几个,其它的就看下面的属性表格,往里面加就好啦。
知道用户怎么使用按钮之后,接下来就是代码实现了。Input组件主要有几个要考虑的地方,
- 错误信息的提示
- 图标的位置的实现,左边(默认)和右边
- 事件的处理
接下去我会仔细讲解组件的代码,代码如下:
<div class="y-input" :class="{ error }">
<y-icon v-if="icon !== ''" :name="icon" :class="classes"></y-icon>
<input
:value="value"
:type="type"
:disabled="disabled"
:readonly="readonly"
:placeholder="placeholder"
:class="{ [`inline-icon-${iconPosition}`]: icon !== '' }"
@change="$emit('change', $event.target.value)"
@focus="$emit('focus', $event.target.value)"
@blur="$emit('blur', $event.target.value)"
@input="$emit('input', $event.target.value)"
/>
<template v-if="error">
<y-icon name="error" class="icon-error"></y-icon>
<span class="message-error">{{ error }}</span>
</template>
</div>
接收的参数如下:
props: {
icon: {
type: String,
default: '',
},
iconPosition: {
type: String,
default: 'left',
},
disabled: {
type: Boolean,
default: false,
},
value: {
type: String,
},
type: {
type: String,
default: 'text',
},
readonly: {
type: Boolean,
default: false,
},
error: {
type: String,
},
placeholder: {
type: String,
default: '',
},
}
具体含义如下:
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|---|---|---|---|---|
| value | 绑定值 | string | — | — |
| type | 类型 | string | text,textarea 和其他原生 input 的 type 值 | text |
| readonly | 原生属性,是否只读 | boolean | — | false |
| error | 错误信息 | string | — | — |
| disabled | 禁用 | boolean | — | false |
| placeholder | 输入框占位文本 | string | — | — |
| icon | 图标名称 | string | — | — |
| iconPosition | 图标位置 | string | left / right | left |
上面就是组件的主要代码了,然后各个属性的说明也在表格中给出,接下去主要就是说明一下实现的主要思路,
-
首先给最外面的
div添加一个动态类error,这个主要用来控制有错误信息的时候,显示错误提示,没有error那就显示正常的输入框。 -
第二行的
<y-icon>就是用来控制图标的显示,如果用户传了icon参数,那么就显示图标,否则就不显示,注意这里的动态class,主要是用来控制图标是显示在左侧还是右侧,
computed: {
classes() {
return {
[`icon-left`]: this.icon !== '' && this.iconPosition === 'left',
[`icon-right`]: this.icon !== '' && this.iconPosition === 'right',
}
},
},
对于图标的控制,主要还是通过定位来实现,让其相对于输入框进行定位,然后对输入框相应的设置一个padding,部分css样式如下:
&.inline-icon-left {
padding-left: 2em;
}
&.inline-icon-right {
padding-right: 2em;
}
.icon-left {
position: absolute;
top: 50%;
left: 10px;
transform: translateY(-50%);
z-index: 2;
}
.icon-right {
position: absolute;
top: 50%;
right: 6px;
transform: translateY(-50%);
z-index: 2;
}
-
第三行开始的就是真正的
input组件部分了,首先它接受一个value,用来表示输入框的值,支持双向绑定。然后type的话表示支持的输入框类型,可以详见原生 input 的 type 值。同时,输入框支持的事件有,
change,focus,blur,input,在这里我没有对这些事件做相应的处理,只是对其进行了向外触发,并将输入框的值传递给使用这个组件的父组件,让用户得到这个值根据自己的需求去处理。当时也有想过这么处理事件,就是用户通过传递回调函数,在组件中去执行,然后把处理后的再传出去。但是这样子设计显然更麻烦,而且使用这个组件的体验也不好,所以放弃了这种想法。
-
最后的
template主要是用于控制显示错误信息,这里的template其实就是一个占位符的作用,不会真正显示在文档中,这样子比用div可以节省DOM元素。然后里面的内容就是一个错误的icon和具体的错误信息。这个主要用于表单验证的时候,当验证失败,这个错误信息就能用上啦。 -
最后一步,就是给各个状态添加样式了。
到此,Input组件就已经造完了,是不是很简单哈!
4、Input组件-遇到的问题
这个组件和昨天的Button组件其实都是利用了原生的html元素,然后在其基础进行改写,添加了不同状态,不同场景下的样式,所以没有什么难度。
5、结束
今天的组件还是很简单吧,主要样式写的好,你也可以做出一个好看的Input组件。下一个组件打算写一下栅格组件,那个就没有这两个这么简单了,加油!
项目地址Yue UI