当前位置: 首页 > 科技观察

原生CSS+JS实现一个标签输入框

时间:2023-03-20 01:31:09 科技观察

最近在项目中需要做一个标签输入框,比较实用。演示效果如下:主要交互需求如下:点击输入框输入内容。按Enter生成标签。按退格键删除标签。单击标签上的关闭按钮可删除标签。我习惯了各种React框架或UI库。你有多久没有接触原生开发了?有时候页面比较简单,不需要引入完整的框架。本机实现完全令人满意。让我们来看看!1.自适应输入框布局无论是什么组件,布局都是最重要的。这个布局分为标签和输入框两部分。假设HTML如下:CSS

简单修改:.tags-content{display:flex;弹性包装:包装;对齐项目:弹性启动;间隙:6px;宽度:400px;框大小:边框框;填充:8px12px;边框:1px实心#D9D9D9;边界半径:4px;字体大小:16px;行高:24px;#4F46E5;溢出:自动;光标:文本;}标签{显示:弹性;对齐项目:居中;填充:4px04px8px;字体大小:16px;行高:24px;背景:#F5F5F5;rgba(0,0,0,0.85);cursor:default;}tag-close{width:18px;高度:18px;游标:指针;background:url("data:image/svg+xml,%3Csvgwidth='10'height='10'viewBox='001010'fill='none'xmlns='http://www.w3.org/2000/svg'%3E%3Cpathd='M5.5785l2.93-3.493a.089.089000-.068-.146h-.891a.182.182000-.137.064l-2.4172.88-2.416-2.88a.178.178000-.137-.064h-.89a.089.089000-.069.146L4.4135l-2.933.493a.089.089000.068.146h.89a.182.182000.138-.064l2.416-2.882.4172.88c.033.04.083.064-134.69l2.93-3.493z'fill='%23000'fill-opacity='.45'/%3E%3C/svg%3E")centerno-repeat;}.tags-input{flex:auto;border:0;outline:0;padding:4px0;line-height:24px;font-size:16px;}.}注意一些实现技巧:标签之间的空隙可以通过gap来实现。为了使面积inputbox填充剩余空间,这里使用flex:auto。为了让parent保持焦点,这里使用:focus-within。效果如下:但是这里的inputbox还是有一些问题,如如下图:由于input的输入内容不能跟随宽度适配,所以有时文本会被截断:理想情况下,当输入内容较多时,应该作为一个整体换行。如何实现晚上吗?用普通的div就可以实现。CSS
可以通过添加contenteditable或者下面的CSS来实现:.tags-input{-webkit-user-modify:read-write-plaintext-only;}该属性表示只允许输入纯文本,有兴趣的可以参考张新旭的这篇文章:小提示:如何让contenteditable元素只输入纯文本[1]。这允许自适应内容宽度。2.输入框占位符提示由于输入框从input变成了普通的div标签,所以没有占位符功能。但是,我们仍然可以使用其他CSS特性来实现占位符效果。当输入框没有内容时,可以匹配:empty选择器,然后通过伪元素::before动态生成占位符内容。具体实现如下:.tags-input:empty::before{content:attr(placeholder);color:#828282;}效果如下:这个和input的占位符效果差不多。除此之外,还有一种情况。如果只需要在没有标签的情况下显示占位符,如何实现?你可以想象一下,如果没有任何标签,HTML会变成这样:case,输入框只剩下唯一元素,可以通过:only-child匹配得到唯一元素,所以实现如下:.tags-input:only-child:empty::before{content:属性(占位符);color:#828282;}这样加一个伪类就解决了问题。两个要求都符合认知,就看设计怎么决定了。3、标签的输入和删除要实现标签的输入和删除,需要用到JS,只需要监听键盘上的“Enter”和“Backspace”这两个键值即可。需要注意的是,默认情况下,当一个普通的contenteditable元素输入回车时,会出现一个换行符,如下:所以监听键盘事件时,需要阻止default事件,然后动态创建标签element,通过before添加到输入框的最前面,具体实现如下://TagInput是一个输入框TagInput.addEventListener('keydown',function(ev){if(ev.key==='Enter'){ev.preventDefault()if(this.innerText){//input框内容通过innerText获取consttag=document.createElement('TAG');tag.innerHTML=this.innerText+'';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();//输入框需要在任意位置点击时获得焦点})这样就实现了文章开头所示的效果:完整代码可以访问:文章底部原文链接“输入标签[2]。四、选择框架还是原生?总结!整体实现并不复杂,很多交互逻辑CSS也可以轻松实现,而JS也就10行左右的代码。这里总结一下实现要点:可以使用普通div元素输入纯文本-webkit-user-modify:read-write-plaintext-only普通div元素输入可以自适应内容宽度。普通div元素输入框的占位符可以通过:empty结合伪元素实现回车事件。默认事件需要被阻止,否则会回绕。在一个元素前面添加一个元素可以使用before方法删除一个元素的前一个元素。您可以使用previousElementSibling.remove方法将事件绑定到动态生成的元素。您可以在各种框架流行的氛围中使用事件委托。一些原生的属性和方法可能没有引起太多关注。是的,这也是一种损失。当然各种框架我也是会用的,特别是大而复杂的交互页面,一般都是小交互,比如文章的例子,antdesign里面有相关的组件,我也用过,因为整体UI都是这样的,这个款式也是按照这个设计来设计的。后来需要单独开发一个chrome插件,也用到这样的交互,但是只用这么一个组件引入整个框架太麻烦了,所以还是选择直接native实现简单方便.