原生实现输入框可清空操作

女生的网名这么多〃 提交于 2021-01-22 17:56:07

今年伊始至今都在做系统平台的开发,还没有做过组件的开发,难得难得,昨儿有个组件迭代需求,给搜索组件新增清空操作。

就是需要实现如下这样的效果:

这是我从 elementUI 那找的 demo,但是之前写的这个搜索组件就是原生实现的,也不至于为了个新功能再去引第三方库。

那该如何实现呢?

花了我两个小时的时间......

分析需求

首先,就是需求分析,拆分实现的功能点,这也方便下一步的代码编写。

这个功能的关键点不是点击 x 按钮实现输入数据的清空,关键点应该在于这个清空按钮的交互问题。

这里,我将这个问题分为如下几点:

  • 输入框没有值的时候,鼠标滑入不显示按钮,鼠标聚焦也就是有光标时候也不显示按钮
  • 输入框输入值的时候,实时监听数据变化,此时显示按钮
  • 输入框聚焦时,鼠标移出,按钮仍然显示
  • 输入框失去焦点时,按钮隐藏,此时鼠标滑入显示按钮
  • 输入框有值时,鼠标聚焦显示按钮

清空按钮的显示隐藏,交互大致就是这样。

页面布局

实现一个搜索组件,基础的就应该需要一个输入框,一个搜索按钮,这里因为清空操作就还需要个清空按钮。

<div class="container">
    <input id="searchInput" type="text" :value="${this.inputValue}" />
    <div class="deleteBtn" @click="${this.deleteData}"></div>
    <div class="searchBtn" @click="${this.sendData}"></div>
</div>

再随便调整调整样式,应该是如下这个样子:

忽略那个删除和搜索按钮,找 UI 随便给的两张图片,组件都是支持自定义配置的。

一般搜索框的布局基本都是这样的吧,其他也写不出来什么花了,但是按照这个布局,在实现清空按钮的交互时候会有个 bug,这个在下面会讲到。

解决方案

朴实无华,来根据之前需求分析的几点依次来展开。

第一步

实现输入框没有值的时候,鼠标滑入不显示按钮,鼠标聚焦也就是有光标时候也不显示按钮。

鼠标的滑入滑出操作先不考虑,这涉及到刚刚说的那个 bug。

按钮的显示隐藏可以通过一个布尔值的变量来控制,直接在 css 中控制 deleteBtn 这个 div 的 display 的值,

.deleteBtn {
    display: $ {
        this.showDeleteBtn?"block""none";
    }
    ...;
}

这里组件的开发采用的 lit-element.polymer 的架构,还用的 ts,和原生 js 的写法还是会有出入,但是实现逻辑都是一样的。

输入框没有值时,鼠标聚焦不显示按钮,那这个方法就是需要写在 input 的 onfocus 上,

<input
    id="searchInput"
    type="text"
    :value="${this.inputValue}"
    @focus="${this.focusData}"
/>

focusData() {
    const container = (this.shadowRoot as ShadowRoot).getElementById("searchInput"as HTMLInputElement;
    if (container.value) {
        this.showDeleteBtn = true;
    } else {
        this.showDeleteBtn = false;
    }
}

focusData 方法中就是先获取 input 的值,有值时候聚焦就显示按钮,没值时候聚焦就不显示,这里顺带把第五步解决了。

清空的事件 deleteData 也是用如上代码实现,别忘了清空之后无值是需要隐藏按钮的,

deleteData() {
    const container = (this.shadowRoot as ShadowRoot).getElementById("searchInput"as HTMLInputElement;
    container.value = "";
    this.showDeleteBtn = false;
}

第二步

实现输入框输入值的时候,实时监听数据变化,此时显示按钮。

文本区域实时监听的功能,input 是有提供原生方法的 oninput,但是对于 IE 浏览器(IE6/7/8)不支持。

对所有 IE 使用 onpropertychange,其他浏览器用 oninput,工作中一般都使用公司浏览器,是基于 chrome 内核开发的,所以都不用考虑 IE 的兼容性。

<input
    id="searchInput"
    type="text"
    :value="${this.inputValue}"
    @focus="${this.focusData}"
    @input="${this.watchData}"
/>

watchData() {
    const container = (this.shadowRoot as ShadowRoot).getElementById("searchInput"as HTMLInputElement;
    if (container.value) {
        this.showDeleteBtn = true;
    }
}

第三步

又有鼠标的滑入滑出,一会再说。

第四步

实现输入框失去焦点时,按钮隐藏。

<input
    id="searchInput"
    type="text"
    :value="${this.inputValue}"
    @focus="${this.focusData}"
    @input="${this.watchData}"
    @blur="${this.blurData}"
/>

blurData() {
    this.showDeleteBtn = false;
}

bug 就在这儿,此时点击清空按钮失效。

输入框失去焦点的时候直接就隐藏了按钮,在点击清空按钮的时候,此时是先失去了焦点再进行点击,但失去焦点时已经隐藏了按钮,只是页面渲染的速度太快,感觉是点击了按钮其实没点到,所以清空按钮上绑定的事件就没有执行。

为了解决这个 bug,就需要新增鼠标滑入滑出事件,这两个事件要绑定在外容器 container 上。这时候即使输入框失去了焦点,但是鼠标滑入时仍会显示按钮。

<div
    class="container"
    @mouseout="${this.mouseoutData}"
    @mouseover="${this.mouseoverData}"
>
</div>
mouseoutData() {
    if (!this.inputFocus) {
        this.showDeleteBtn = false;
    }
}

mouseoverData() {
    const container = (this.shadowRoot as ShadowRoot).getElementById("searchInput"as HTMLInputElement;
    if (container.value) {
        this.showDeleteBtn = true;
    } else {
        this.showDeleteBtn = false;
    }
}

其中第一步和第三步,需要判断鼠标滑入滑出时输入框聚焦情况,还是可以使用个布尔值变量 inputFocus 来进行判断。在上面的 focusData 和 blurData 的方法中分别设置 inputFocus 的真假值。

focusData() {
    this.inputFocus = true;
    ...
}

blurData() {
    this.inputFocus = false;
    ...
}

这样就愉快的实现了输入框清空操作。

本文分享自微信公众号 - 前端一起学(gh_3ba18d51f982)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!