3

NutUI-React Input输入框的使用指南

 1 year ago
source link: https://jelly.jd.com/article/63afa3257003cc00613a65f3
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
NutUI-React Input输入框的使用指南
上传日期:2022.12.31
随着 NutUI-React 上线以来,我们听到了许多好的声音,同时也收获了很多中肯的建议和一些问题反馈。在众多的反馈中,用户对输入框Input组件的使用率较高,同时反馈的问题也比较多,本次我们就将展开说说 Input 输入框组件。

NutUI-React Input输入框的使用指南

NutUI 是一套京东风格的轻量级移动端组件库,覆盖移动端主流业务场景。目前已支持 Vue 和 React 两大框架。其中 React 版本从今年1月发版以来,陆续发布了 85 个大小版本,截止目前已完成 60+ 组件数量的建设。 今年 618 期间,我们启动多端小程序适配,选用 Taro 基础框架作为底层实现,经过半年的打磨,目前已完成了所有组件的适配,可以为开发者提供便捷的多端小程序能力。

随着 NutUI-React 上线以来,我们听到了许多好的声音,同时也收获了很多中肯的建议和一些问题反馈。在众多的反馈中,用户对输入框Input组件的使用率较高,同时反馈的问题也比较多,本次我们就将展开说说 Input 输入框组件。

在web的世界要实现人机交流,传递文字、图片、视频、语言等信息,最基本的就是输入信息。那么输入框要怎么实现“输入”的功能呢?

听起来“输入”这个功能好像很简单,但要考虑的事情却很多。在输入前我们要告诉用户是否要输入、在哪里输入、输入什么内容、内容要满足什么条件等;在输入时又要关注用户输入内容是否要校验,输入的交互体验等;完成输入操作后,我们是否要对输入内容做反馈,是否提示用户可清除内容等等。

在调研了市面上的移动端 Input 组件之后,我们确定了 Input 组件的大致功能如下:

11d36b920f7b79f2.png

总体分为五类功能:

  • 基本功能类,实现输入框的输入功能、输入类型
  • 样式类,实现输入框文本对齐、有无图标、有无边框等样式设置
  • 提示类,实现输入内容是否必填、是否有误、是否显示错误文案
  • 自定义类,实现用户自定义按钮、自定义输入框、是否校验文本内容等功能
  • 事件,实现用户点击组件及组件各图标的回调事件

组件的实现

基本功能实现

基础功能的实现都是基于原生 Input 输入框的自带属性,在这些基础属性上做了扩展,首先我们先来看看组件的整体布局。

<div className={`${classes}  ${className || ''}`}
  style={style}
  {...rest}
  onClick={(e) => {
      onClick && onClick(e)
  }}>
    {slotInput?(...)//用户自定义input插槽
      :(<>
      {leftIcon ...} //左侧图标
      {label ...} //输入框标题
      <div className="nut-input-value">
        <div className="nut-input-inner" onClick={(e) => { handleClickInput(e)}}>
        {type === 'textarea' ?(<textarea />)
        :(<input
            name={name}
            className="input-text"
            ref={inputRef}
            style={{ textAlign: inputAlign }}//输入框中文本对齐方式inputAlign
            type={inputType(type)} //输入类型
            maxLength={maxlength} //输入框最大字数限制
            placeholder={placeholder || locale.placeholder} //占位符
            disabled={disabled} //禁用
            readOnly={readonly} //只读
            value={inputValue} //对应props中初始默认值defaultValue
            autoFocus={autofocus}
            onBlur={(e: any) => {handleBlur(e)}}
            onFocus={(e: any) => {handleFocus(e)}}
            onInput={(e: any) => {handleInput(e)}}
        />)}
        {clearable ... } //清除按钮
        </div>
        {rightIcon ...} //右侧图标
        {slotButton ...} //用户自定义按钮插槽
        {showWordLimit && maxlength ...} //字数统计
        {errorMessage ...} //错误提示
      </div>
    </>)}
</div>

以上代码能看出整个 Input 输入框的布局结构,基本上原生组件上有的参数和事件我都做了绑定和露出,实现了输入功能、自定义输入类型、禁用、只读和回调事件,同时也对输入框设置了 style 样式属性,实现了的文本对齐方式 inputAlign。其他扩展的功能,在下文中会有侧重的提及,如果感兴趣原码的可以去 github 中查阅。

样式类功能实现

样式的实现基本上都是对样式名的控制,实现起来相对简单,这里就不做过多的赘述,我们重点讲下如何去使用 Input 组件的现有能力去实现我们想要的样式效果。

.my-label{
    color: rgb(62, 137, 249);
}

<Input
    labelWidth="100" //标题区域宽度100
    labelClass="my-label" //自定义标题样式类名,修改标题区域样式
    label="图标显示" //标题文案
    defaultValue="leftIcon和rightIcon" //输入框默认文案,即value属性的现实文案
    leftIcon="dongdong" //左侧图标显示,引用Icon组件的图标名称
    rightIcon="ask2"  //右侧图标显示,引用Icon组件的图标名称
    leftIconSize="12" //左侧图标大小
    rightIconSize="18" //右侧图标大小
/>
<Input
    label="标题和文本方向"
    placeholder="inputAlign 为 right"
    labelAlign="left" //标题对齐方式
    inputAlign="right" //输入框文案对齐方式
/>
<Input label="无边框" colon labelAlign="right" placeholder="无边框" border={false} />
<Input placeholder="无标题" />

具体效果如下:

11d36b920f7b79f2.png

上述代码中我们对涉及样式类的参数如图标、标题、文本方向、边框、冒号等属性做了配置,展示了一些容易被忽略的参数如:colon 冒号符号设置,leftIconSizerightIconSize 图标大小设置,labelClasslabelWidth 标题区域的样式和宽度的设置,这里都简单的举了个例子,希望在实际应用中会对你有所帮助。

提示类功能实现

提示类功能比如清除按钮提示、错误文案提示、字数限制提示和必填提示的实现也相对简单,我们看下清除按钮和错误消息提示的代码。

//清除按钮显示
{clearable && !readonly && active && inputValue.length > 0 ? (
    <Icon
        classPrefix={iconClassPrefix}
        fontClassName={iconFontClassName}
        className="nut-input-clear"
        name={clearIcon}
        size={clearSize}
        onClick={(e) => {handleClear(e)}}
    />
) : null}

清除按钮的代码逻辑中给了一些限制条件,只有在设置了 clearable 为 true 时,且不是只读,输入框 focus 状态,并且输入框有文字输入时才给出清除按钮的提示。清除按钮图标是引用了 Icon 组件,可以支持图标的替换和尺寸的修改,具体使用方法可以参见 NutUI-React 的 Icon 组件。

//错误消息提示
{errorMessage ? (
    <div
      className="nut-input-error-message"
      style={{ textAlign: errorMessageAlign}}
    >
      {errorMessage}
    </div>
) : null}

从代码可以看出,错误消息提示需要设置 errorMesge 属性的文案才能出现提示,错误提示还提供了提示文案位置的配置,具体使用方法如下。

//清除按钮
<Input
    label="文本"
    placeholder="必填项"
    required
    showWordLimit
    maxlength={10}
    clearable
    clearIcon="del"
    clearSize="20"
/>
const [errorState, setError] = useState(false)
const [firstFlag, setFirstFlag] = useState(true)

<Input
    label="文本"
    defaultValue=""
    placeholder="必填项"
    onFocus={() => {
       setFirstFlag(false)
    }}
    onChange={(value) => {
        if (value.length === 0 && !firstFlag) {
            setError(true)
        } else {
            setError(false)
        }
    }}
    required
    error={errorState}
    errorMessage={errorState ? '不能为空提示' : ''}
/>

上面两个例子对输入框设置了必填项提示、清除按钮提示、字数显示和错误文案的提示,错误提示的非空校验也运用 onChangeonFocus 事件做了个小案例,具体效果如下:

11d36b920f7b79f2.png

看完例子是不是对 Input 输入框提示类功能有了更清晰的了解呢?接下来我们来看看 Input 的自定义的功能。

自定义功能实现

在 NutUI-React 的 Input 组件中,我们还为用户扩展了几个自定义的属性:

输入格式校验

当用户设置参数 formatter规则和 formatterTrigger 时决定了用户输入的内容将经过正则校验。 我们会根据 formatterTrigger 设置的触发事件 onChangeonBlur 来决定执行校验的时机,校验规则是用 formatter 中所设置的规则,具体使用方法如下。

const formatter = (value: string) => value.replace(/\d/g, '')

<Input
    label="文本"
    placeholder="在输入时执行格式化"
    formatter={formatter}
/>
<Input
    label="文本"
    placeholder="在失焦时执行格式化"
    formatter={formatter}
    formatTrigger="onBlur"
/>
11d36b920f7b79f2.png

上述例子中,我们设置了 formatter 校验规则为不能为数字,当我们不设置 formatTrigger 时默认走的是 onChange 校验时机,即实时输入校验。当设置 formatTriggeronBlur 时则是走的失焦后校验。

文本输入框模式

Input 组件除了使用了 Input 原生输入框,我们还为用户提供了文本框 Textarea 组件,满足了用户操作多行文本的需求,我们先来看下代码。

{type === 'textarea' ? (
    <textarea
        name={name}
        className="input-text"
        ref={inputRef}
        style={{
            textAlign: inputAlign,
            height: `${Number(rows) * 24}px`,
        }}
        maxLength={maxlength}
        placeholder={placeholder || locale.placeholder}
        disabled={disabled}
        readOnly={readonly}
        value={inputValue}
        autoFocus={autofocus}
        onBlur={(e: any) => {handleBlur(e)}}
        onFocus={(e: any) => {handleFocus(e)}}
        onInput={(e: any) => {handleInput(e)}}
    />
  ): (<input ... />)
}

当用户设置了 typetextarea 时,代码中就是使用 textarea 原生组件,这里绑定的属性与 Input 功能基本一致,只是在 style 属性上增加了行数的设置,用户可以通过 rows 设置文本的高度,具体使用如下。

 <Input
    label='留言'
    placeholder='留言'
    defaultValue=''
    type="textarea"
    showWordLimit
    rows="2"
    maxlength="50"
/>
11d36b920f7b79f2.png

自定义输入框和按钮插槽

实现用户自定义的输入框的这个功能,我们用 slotInput 来接收用户传入的代码,保留了基本的输入框布局保证了其他出 Input 本身之外的功能,比如label属性。核心代码如下。

{slotInput ? (
  <>
    {label ? (...) : null}
    <div className="nut-input-value">
        <div
            className="nut-input-inner"
            onClick={(e) => {handleClickInput(e)}}
        >
            {slotInput}
        </div>
    </div>
  </>
) : (<input />)
}

而自定义按钮的插槽,我们用 slotButton 来接收。自定义按钮在整个输入框组件中,按照功能分区只能是在右侧图标的位置上,所以在布局这里我们将它与 rightIcon 放在一起,但是没有做与 rightIcon 互斥的逻辑,这个要根据用户的实际使用场景来选择。

{slotButton ? (
    <div className="nut-input-button">{slotButton}</div>
) : null}

具体使用方法:

<Input
    label="短信验证码"
    placeholder="请输入短信验证码"
    defaultValue="请输入短信验证码"
    clearable
    center
    slotButton={
    <Button size="small" type="primary">
        发送验证码
    </Button>
    }
/>
<Input
    label="自定义输入框"
    slotInput={
    <Cell>
        <input type="text" style={{ width: '100%', height: '30px' }} />
    </Cell>
    }
/>
11d36b920f7b79f2.png

从上述例子中我们可以简单的了解到插槽的使用,具体的使用方法还是要根据每个用户的不同使用场景来设置,这里不做过多赘述,仅供参考。

事件的实现

事件的实现其实从上边各功能分析就能看出是如何实现的,除了 Input 和 Textarea 的原生事件,我们在各个图标 Icon 上也做了点击事件的绑定,方便用户使用。具体事件调用可以查看 官方文档

Issue

自 NutUI-React Input 上线以来,我们也收到了一些用户的Issue反馈,这里我们挑了一些比较典型的跟大家聊聊。

  • input 双向绑定问题 (Issue #355)

React 与 Vue 不同,它是没有双向绑定的概念的,因为它的设计思想就是单向数据流。但是它也是可以通过改变 state 来实现双向数据绑定的功能。

const [value, updateValue] = useState('')

<Input
    name="text"
    label='text'
    placeholder='text'
    defaultValue={value}
    onChange={(val) => {
        updateValue(val)
    }}
/>

上边的例子就实现了一个数据双向绑定的功能,当用户输入内容触发 onChange 事件时会通过 updateValue 来改变 value 的值,从而实现双向绑定。

  • Input defaultValue无法清空 (Issue #446)

这个问题是用户在清除组件 value 也就是 defaultValue 时,发现不能置空。经过排差是因为在设计之初,考虑到用户输入的文字时才更新输入框内容,导致 defaultValue 为空时输入框不能被更新。于是我们放开了输入限制,只要改变输入内容就会被更新。

11d36b920f7b79f2.png

这个问题也让我注意到在设计组件时要考虑使用场景的全面性,开发完之后要实际使用下每个属性的功能。

  • Input 实际与文档不符(Issue #355)

这个问题是因为多次改版升级和功能迭代引起的遗漏问题,为此我们做了文档优化和事件统一的工作,将功能补齐和文档规范化。

希望本篇文章能对未使用过或使用过程中遇到问题的朋友们有所帮助,也感谢社区的小伙伴对 Input 组件的使用和问题反馈,我们还有诸多不足,需要不断地打磨,为了实现“好用的” Input 输入框,接下来我们还有许多待优化的点要跟进。期待我们更好的 NutUI-React Input 输入框吧。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK