在 Twitter 发推输入框中,有一个字数限制的逻辑,超出字数限制部分的文字会设置背景颜色提示,以便用户进行调整。这是一个很好的交互设计,在 Ant Design 中也有提到这一点。
本文将介绍如何实现这一字数限制输入框,效果访问:Codepen
超出限制文字设置背景提示
实现这个输入框关键在于如何实现对超出字数限制部分的文字设置背景颜色,对于输入框一般有两种选择:
textarea
多行文本输入div
设置contenteditable="true"
contenteditable="true"
的 DIV 节点可以操作其中的 DOM 节点,那么我们可以监听输入区域,用户输入时,获取其中的 innerText
,然后进行字数限制判断,设置其 innerHTML
,划分两部分,超出部分设置背景颜色,代码大致如下:
在每次输入后,都重新设置 innerHTML
,会导致每次输入后,光标位置都跑到输入框起始位置了,看来这种方式不可行 😤
👉 解决方案:用两层 DIV 重叠
- 上层 DIV 节点用于文字输入,背景颜色透明
- 下层 DIV 节点用于高亮超出部分文字,文字颜色设置为透明,超出部分节点设置背景颜色
输入框 placeholder
contenteditable="true"
的 DIV 设置 placeholder 可以通过 CSS 来解决:
通过选择器 :empty
判断输入框中内容是否为空,其实存在一些问题。点击回车的时候,会插入 <div><br></div>
或者 <br>
,这部分会影响 :empty
的判断,譬如 DIV 中没有文字,但是存在一个换行时,这样 :empty
的判断就不会生效,placeholder 也就没有显示,所以我们可以通过另一种方式进行判断,通过 JS 手动添加、移除 class 类处理 placeholder 的显示和隐藏:
|
|
还有一种解决方式,第一层输入 DIV 节点使用 textarea
替换,textarea
中有 placeholder
属性
中文输入字数统计
在中文输入是,中文还未输入到输入框,字数就在统计了;合理的是,中文输入 composing 组合过程中不应进行字数统计,在中文输入到输入框后,才进行字数统计。
解决这个问题需要用到 compositionstart
和 compositionend
这两个事件;前者表示输入组合开始,后者表示输入组合结束,在 compositionend
事件中就是我们字数统计的合理时机。
🎏 如需考虑 emoji 字符长度计算的话,参考:探究 emoji 字符长度
完整代码
效果访问:Codepen