最近在项目中需要做一个标签输入框,还挺实用的,演示效果如下:

主要交互要求是这样的:

  • 点击输入框可以输入内容。
  • 按回车可以生成标签。
  • 按退格键可以删除标签。
  • 点击标签上的关闭按钮可以删除标签。

习惯了各种 react 框架或者UI库,大家有多久没接触没有原生开发了呢?有时候页面比较简单,没必要引入一个完整的框架,原生实现就完全满足了,一起看看吧!

一、自适应输入框布局

不管什么组件,布局都是最重要的。这个布局分为标签和输入框两个部分,假设 HTML 如下:

<div class="tags-content">
  <tag>CSS<a class="tag-close"></a></tag> 
  <input class="tags-input" placeholder="添加标签">
</div>

简单修饰一下:

.tags-content{
   display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 6px;
    width: 400px;
    box-sizing: border-box;
    padding: 8px 12px;
    border: 1px solid #D9D9D9;
    border-radius: 4px;
    font-size: 16px;
    line-height: 24px;
    color: #333;
    outline-color: #4F46E5;
    overflow: auto;
    cursor: text;
}
tag{
    display: flex;
    align-items: center;
    padding: 4px 0 4px 8px;
    font-size: 16px;
    line-height: 24px;
    background: #F5F5F5;
    color: rgba(0, 0, 0, 0.85);
    cursor: default;
}
tag-close{
    width: 18px;
    height: 18px;
    cursor: pointer;
    background: url("data:image/svg xml,") center no-repeat;
}
.tags-input{
    flex: auto;
    border: 0;
    outline: 0;
    padding: 4px 0;
    line-height: 24px;
    font-size: 16px;
}
.tags-content:focus-within,
.tags-content:active{
    outline: auto #4F46E5;
}

注意几点实现技巧:

  • 标签的间隔可以用 gap 实现。
  • 为了让输入框的区域铺满剩余空间,这里用到了flex: auto。
  • 为了让父级处于聚焦状态,这里用到了:focus-within。

效果如下:

但是这里的输入框用 input 还是有些问题的,如下所示:

由于 input 输入内容无法跟随宽度自适应,所以有时候会出现文字被截断的情况:

理想情况下,当输入内容较多时,应该整体换行。如何实现呢?可以用普通的 div 来实现。

<div class="tags-content">
  <tag>CSS<a class="tag-close"></a></tag> 
  <div class="tags-input" placeholder="添加标签"></div>
</div>

可以通过添加contenteditable或者以下 CSS 来实现:

.tags-input{
  -webkit-user-modify: read-write-plaintext-only;
}

这个属性表示只允许输入纯文本,有兴趣的可以参考张鑫旭的这篇文章:小tip: 如何让contenteditable元素只能输入纯文本[1]。

这样可以自适应内容宽度了。

二、输入框占位提示

由于输入框已经从 input 换成了普通的 div 标签,并没有 placeholder 特性。不过,我们仍然可以通过其他 CSS 特性来实现占位效果,当输入框没有内容时,就可以匹配到 :empty选择器,然后通过伪元素::before动态生成 placeholder 内容,具体实现如下:

.tags-input:empty::before{
    content: attr(placeholder);
    color: #828282;
}

效果如下:

这样就几乎和 input 的占位效果一致了。

另外还有一种情况,如果需要仅在没有任何标签的情况下才显示占位,如何实现呢?可以想想,在没有任何标签的情况下,HTML 就变成了这样:

<div class="tags-content">
  <div class="tags-input" placeholder="添加标签"></div>
</div>

这种情况,就仅剩输入框唯一元素了,唯一元素可以通过:only-child来匹配,所以实现如下:

.tags-input:only-child:empty::before{
    content: attr(placeholder);
    color: #828282;
}

这样添加一个伪类就解决了。

两种需求都符合认知,看设计如何决定了。

三、标签的输入与删除

要实现标签的输入与删除就需要 JS 出马了,只需要监听键盘的“回车”和“退格”两个键值。需要注意的是,默认情况下,普通 contenteditable元素在回车时,会出现换行,如下:

因此,在监听键盘事件时需要阻止默认事件,然后动态创建标签元素,通过 before添加到输入框前面,具体实现如下:

// TagInput是输入框
TagInput.addEventListener('keydown', function(ev) {
  if (ev.key === 'Enter') {
    ev.preventDefault()
    if (this.innerText) { // 输入框内容通过 innerText 获取
      const tag = document.createElement('TAG');
      tag.innerHTML = this.innerText   '<a class="kalos-tag-close"></a>';
      this.before(tag);
      this.innerText = '';
    }
  }
})

这样就能正常创建标签了。

然后是标签的删除。

这里有两种途径,首先看键盘的删除,具体逻辑是当输入框内容为空时删除标签,很简单,删除的标签就是输入框的前面一个元素,通过previousElementSibling获取,具体实现如下:

TagInput.addEventListener('keydown', function(ev) {
  if (ev.key === 'Backspace' && !this.innerText) {
    this.previousElementSibling?.remove(); // 需要判断前一个元素是否存在
  }
})

然后是点击删除图标的删除。由于标签是动态生成的,所以这里需要用事件委托的方式来添加删除事件。

// TagContent是父级容器
TagContent.addEventListener('click', function(ev) {
  if (ev.target.className === 'tag-close') {
    ev.target.parentNode.remove();
  }
  TagInput.focus(); //点击任意地方输入框都需要聚焦
})

这样就实现了文章开头的所示效果:

四、选择框架还是原生

总结一下!

整体实现并不算复杂,不少交互逻辑 CSS 也可以轻松实现,JS 也就 10 来行代码,这里总结一下实现要点:

  • 普通 div 元素输入纯文本可以使用 -webkit-user-modify: read-write-plaintext-only
  • 普通 div 元素输入可以自适应内容宽度
  • 普通 div 元素输入框的 placeholder 占位可以通过 :empty 结合伪元素实现
  • 回车事件需要阻止默认事件,不然会换行
  • 在一个元素的前面新增元素可以用 before 方法
  • 删除一个元素的前面一个元素,可以用 previousElementSibling.remove 方法
  • 给动态生成的元素绑定事件可以用事件委托的方式

在各种框架大行其道的氛围下,有些原生的属性和方法可能都不太关注了,这也不失为是一种损失。当然,我本身也是各种框架都会用,特别是大型、复杂的交互页面,一般比较小的交互,比如文章这个例子,在 ant design 中有相关的组件,也使用过,因为整体 UI 全是这种风格,设计也是按照这个设计的。后来需要单独开发一个 chrome 插件,也用到了这样一个交互,但是仅仅用了这样一个组件,引入整个框架就过于累赘了,所以还是选择直接原生实现,简单方便。

以上就是基于原生CSS JS实现一个标签输入框的详细内容,更多关于JS标签输入框的资料请关注Devmax其它相关文章!

基于原生CSS+JS实现一个标签输入框的更多相关文章

  1. html5 拖拽及用 js 实现拖拽功能的示例代码

    这篇文章主要介绍了html5 拖拽及用 js 实现拖拽,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. 详解通过focusout事件解决IOS键盘收起时界面不归位的问题

    这篇文章主要介绍了详解通过focusout事件解决IOS键盘收起时界面不归位的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5去掉输入框type为number时的上下箭头的实现方法

    这篇文章主要介绍了HTML5去掉输入框type为number时的上下箭头的实现方法,需要的朋友可以参考下

  4. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. HTML5中input输入框默认提示文字向左向右移动的示例代码

    这篇文章主要介绍了HTML5中input输入框默认提示文字向左向右移动,本文通过实例代码给大家介绍的非常详细对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. 详解移动端HTML5页面端去掉input输入框的白色背景和边框(兼容Android和ios)

    本篇文章主要介绍了移动端HTML5页面端去掉input输入框的白色背景和边框,非常具有实用价值,需要的朋友可以参考下。

  7. The Swift Code之UITextField的使用,及事件委托

    id=98

  8. swift皮筋弹动发射飞机ios源码

    这是一个款采用swift实现的皮筋弹动发射飞机游戏源码,游戏源码比较详细,大家可以研究学习一下吧。

  9. Swift开发教程--UITextField输入框如何隐藏软键盘

    对于UITextField如何隐藏输入框,一直是初学者常遇到的问题。在View试图中,点击选中UITextField控件,为其添加DidEndOnExit实践。在弹出软键盘之后,点击return就可以隐藏软键盘了。

  10. swift实现ios类似微信输入框跟随键盘弹出的效果

    http://www.jianshu.com/p/4e755fe09df7

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部