目前最好的解决方案:
- 创建一个具有两个跨度的临时 div,以及用于模仿(字体、自动换行、滚动条)文本区域的换行行为的 CSS 样式。
- 用插入符号前的文本填充第一个跨度。
- 用插入符号后面的文本填充第二个跨度。
- 使用跨度的 offset.top 和元素高度来了解我们是在第一行还是在最后一行。
我可以看到它工作吗?
我做了一个小提琴,让它的工作原理一目了然:http://jsbin.com/qifezupu/31/edit
如何使用:
我做了一个 jQuery 插件:https://github.com/Canop/taliner.js
这里是相关的演示页面:http://dystroy.org/demos/taliner/demo.html
代码:
$.fn.taliner = function(){
var $t = this,
$d = $('<div>').appendTo('body'),
$s1 = $('<span>').text('a').appendTo($d),
$s2 = $('<span>').appendTo($d),
lh = $s1.height();
$d.css({
width: $t.width(),
height: $t.height(),
font: $t.css('font'),
fontFamily: $t.css('fontFamily'), // for FF/linux
fontSize: $t.css('fontSize'),
whiteSpace : 'pre-wrap',
wordWrap : 'break-word',
overflowY: 'auto',
position: 'fixed',
bottom: 0,
left: 0,
padding: 0,
zIndex: 666
});
var lh = $s1.height(),
input = this[0],
se = input.selectionEnd,
v = input.value,
res = {};
$s1.text(v);
res.linesNumber = $s1.height()/lh|0;
$s1.text(v.slice(0, se));
$s2.text(v.slice(se));
res.caretOnFirstLine = input.selectionEnd===0
|| ($s1.height()<=lh && $s1.offset().top===$s2.offset().top);
res.caretOnLastLine = $s2.height()===lh;
$d.remove();
return res;
}
真的有用吗?
还是有问题。我们在 JavaScript 中获得的关于插入符号位置的唯一信息是 element.selectionEnd。这很糟糕。
以下是两行文本区域上可能的插入符号位置:
| A | B | C |
| D | E |
如您所见,插入符号的位置比字符间的位置要多。更具体地说,您在 C 和 D 之间有两个不同的插入符号位置,但 DOM 不提供任何方式来区分它们。
这意味着有时,如果您单击行尾的右侧,库将无法判断它是行尾还是下一行的开头。