格式化输入框内容后定位光标位置

编辑于2018年10月19日

这段时间进行项目升级工作,期间遇到一个需求:针对十六进制数输入框(输入框内只能输入十六进制数),输入时在每一个字节间插入空格,便于阅读。基本效果如下图所示。

hexinput

这个功能倒不是很难,只用将原始数据格式化后重新设置到输入框中即可。但是,这里却有一个问题:如果从数据中间某处开始编辑,编辑一次后光标就会跳转到最右,在修改时体验不是很好。

hexinput_cursor

这个问题的原因也很容易理解,当我们把光标移到中间部分开始编辑时,数据的内容会因重新格式化导致出现差异,此时把数据设置到输入框中,浏览器无法得知光标应该定位到哪里,所有就只好设置到最右边。

想要修正这个问题,我们就得根据编辑时的光标位置计算出编辑并格式化之后期望光标出现的位置,然后手动设置。这里主要有两个问题:

  1. 如何获取/设置输入框光标的位置?
  2. 如何计算期望的位置?

获取/设置光标的位置

浏览器给我们提供了输入框的选中控制 API:

  • setSelectionRange():设置输入框选中区域,只有起始和结束在同一个位置,就可以设置光标位置。
  • selectionStart:选取区域的起始位置。
  • selectionEnd:选取区域的结束位置。

浏览器的支持情况还不错。

selection

计算光标的期望位置

有了浏览器提供的 API,我们现在已经可以获取和设置光标的位置,那么如何计算出光标的期望位置呢?

起初的我设想的是在 keydown 事件中,获取当前光标的位置。如果是键入,那么光标位置 +1,如果是删除,那么光标位置不变
但是,并不是这么简单,应该格式化的原因我们需要把空格考虑进去,并不是每次键入都需要 +1,也并不是每次删除都不变。考虑到这个思路需要考虑的因素较多,最终放弃。

转变思路后,我开始想:我是如何判断光标的位置呢?我是根据字符来判断的。当输入一个字符后,光标应该在此字符的后面,无论进行了什么样的格式化操作;同理,当删除一个字符后,光标应该在此字符前一个字符的后面。
这个思路就比较简单,减少了可能出现的变量。

具体计算规则

  1. 监听 keydown 事件,获取当前光标的位置。
  2. 根据输入框的内容和光标位置,计算出当前光标位置的前一个字符的下标(不计算空格)。
  3. 判断用户按了哪个键,是退格还是[0-9a-f]。如果是退格,光标应该定位在前一个字符,否则定位到后一个字符,从而计算出期望光标定位在哪个字符后面(不计算空格)。
  4. 格式化数据,根据字符位置计算出光标位置(计算空格)。

这里需要注意几点:

  1. 当进行选中删除操作时,光标应该不需要前移。
  2. 其他输入框不支持的字符需要处理,例如:ctrl等功能键。

具体的实现见下方 codepen,示例代码只实现了基本的功能,没有处理其他字符的情况。

See the Pen 输入框光标定位 by Sylvanass (@hezhou) on CodePen.

希望对您能有帮助,打赏随意