如何获取Input中光标的位置?

1,339 阅读2分钟

一、背景


测试提出气泡要能跟随光标的位置移动

二、气泡方案

旧方案

input上波浪线由覆盖在input上面的span显示,span绑定点击事件,显示对应的气泡。
问题:
  • 点击span后光标在input中的位置需要额外计算,容易出错
  • 无法拖动选中

新方案

  • 波浪线方案保持一致,但不覆盖input,只作为样式存在,不关心事件
  • 复用波浪线的位置数据,代替通过span的点击事件确定位置

三、实现

确定了新方案之后,主要的问题就变成了解决如何获取光标所在的位置。
想要获取光标相对于屏幕的位置信息,大概可以分三步走:
  • input相对于屏幕的位置
  • 光标相对于input的位置
  • 累加位置信息的得出光标相对屏幕的位置


难点主要在第二步,如何获取光标相对于屏幕的位置。
其实我们反过来想一下,获取光标位置 ≈ 获取光标后面的元素的位置信息(为什么是≈,后面会解释)
这个过程大概也可以分为三步走
  • mock出一个于input一模一样DOM
  • 更具selectionStart的信息把input文字分为两部分
  • 获取后一部分的元素的位置信息即为光标相对于input的位置


有了思路之后,就可以着手实现了:
  • 为了方便可以直接获取​getComputedStyle().cssText​,作为mock input的style,当然最好是获取和位置相关的css就好。
  • mock两个dom,储存input的文字信息。
  • 根据selectionStart把input截断为两段,像这样:


最后就可以通过offset来获取位置信息

{
    left: mockSpanNext.offsetLeft + parseInt(originStyle.getPropertyValue('border-left-width'), 10),
    top: mockSpanNext.offsetTop + parseInt(originStyle.getPropertyValue('border-top-width'), 10),
    bottom: mockSpanNext.offsetTop + lineHeight
}

四、问题

对于这种情况,1,2的位置selectionStart是一样的,按照我们上面的方法,我们只能获取到2的位置信息。这也是目前没有解决的问题之一(也是≈的原因)。

大家有什么好的方案欢迎提出探讨。


不对之处欢迎指正,附上demo地址:codepen.io/lastnigtic/…

相关资料:

github.com/component/t…