一、背景

测试提出气泡要能跟随光标的位置移动
二、气泡方案
旧方案
input上波浪线由覆盖在input上面的span显示,span绑定点击事件,显示对应的气泡。
问题:
- 点击span后光标在input中的位置需要额外计算,容易出错
- 无法拖动选中
新方案
- 波浪线方案保持一致,但不覆盖input,只作为样式存在,不关心事件
- 使用input特有的属性selectionStart,兼容性表现也很好
- 复用波浪线的位置数据,代替通过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/…
相关资料: