Javascript 插入符号是否位于文本区域的第一行?在最后一行?
给定一个非固定宽度字体的文本区域,我想在输入时知道插入符号(由Javascript 插入符号是否位于文本区域的第一行?在最后一行?,javascript,jquery,html,dom,textarea,Javascript,Jquery,Html,Dom,Textarea,给定一个非固定宽度字体的文本区域,我想在输入时知道插入符号(由元素.selectionEnd给出)是在文本的第一行还是最后一行 为了避免错误答案,以下是一些不起作用的解决方案: 在\n上拆分:一个句子可以分成两行,因为它对于文本区域的宽度来说太长了 测量插入符号之前的文本(例如,通过将文本复制到具有相同样式的div中并测量跨距的高度):插入符号之后的某些字符可能会更改换行点(通常在单词之间) 这里有一个用于测试和消除一些歧义的工具(是的,它是一个textarea元素,而不仅仅是一行,等等)
元素.selectionEnd给出)是在文本的第一行还是最后一行
为了避免错误答案,以下是一些不起作用的解决方案:
- 在
\n
上拆分:一个句子可以分成两行,因为它对于文本区域的宽度来说太长了
- 测量插入符号之前的文本(例如,通过将文本复制到具有相同样式的div中并测量跨距的高度):插入符号之后的某些字符可能会更改换行点(通常在单词之间)
这里有一个用于测试和消除一些歧义的工具(是的,它是一个textarea
元素,而不仅仅是一行,等等):
注:
- 我不喜欢Internet Explorer 9或移动浏览器
- 我需要一个可靠的解决方案,适用于插入符号的所有位置
- 有很多棘手的细节使得大多数想法在实践中无法使用,请在回答之前准备一把工作小提琴
您可以通过将文本放入div并获取div的宽度来测量文本的长度
简而言之,看看这个。每次更改文本框中的文本时,都会提醒您文本宽度
因此,我建议采取以下措施:
- 查找textarea内容的第一行和最后一行。接下来的步骤适用于任一行
- 要查看一行是否因为textarea的宽度而中断,请使用我建议的代码段检查文本宽度是否大于textarea的宽度
- 如果更长,您可以迭代地开始检查行的子字符串。如果你找到一个与你的文本区宽度相匹配的,你可以很确定那就是换行符所在的地方
我不确定你想采取什么行动,但你可以使用这个方法来近似你的插入符号所在的位置但它可能不是像素完美的,因为div宽度与文本宽度略有不同
下面是测量文本宽度的代码段:
$(document).ready(function() {
$("#txtbox").keyup(function() {
var the_Text = $("#txtbox").val();
var width = $("#testdiv").text(the_Text).width();
alert("The text width is : " + width + " px");
});
});
$(“#testdiv”)
是页面上的隐藏div。没有什么奇怪的,唯一使用的CSS是确保用户看不到它。目前最好的解决方案:
$.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;
}
- 创建一个具有两个跨距的临时div,并使用CSS样式模拟文本区域的换行行为(字体、换行、滚动条)
- 用插入符号前的文本填充第一个跨距
- 用插入符号后的文本填充第二个跨距
- 使用跨距的offset.top和元素高度来确定是在第一行还是在最后一行
我能看到它工作吗?
我做了一把小提琴,很明显它是如何工作的:
如何使用它:
$.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;
}
我制作了一个jQuery插件:
以下是相关的演示页面:
代码:
$.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;
}
如您所见,可能的插入符号位置比字符间位置多。更具体地说,在C和D之间有两个不同的插入符号位置,但是DOM没有提供任何方法来区分它们
这意味着,有时,如果单击行末尾的右侧,库将无法判断它是行的结尾还是下一行的开始 有几种方法可以获取文本区域内插入符号的位置(以像素为单位):
小心,不同的浏览器可能会出现问题。
您可以设置预定义的行高或字体大小,稍后用于获取插入符号位置
我没有测试任何方法,但假设用于获取插入符号位置(以像素为单位)的函数返回相对于插入符号底部的y分量。
您指定的行高度为15像素。
假设方法返回(20,45)。当前线路=y/15=45/15=3
JS Fiddle演示了如何基于Dan的解决方案实现此功能:
我添加了一个显示当前行的范围。可悲的是,我在Chrome上的测试表明,这并不是100%准确:当你用鼠标选择第三行时,它表示你在第四行
Line:
<span id="line">0</span>
下面是一个使用jQuery插件()获取插入符号位置(y位置是您需要的):
不幸的是,正如您将看到的,需要进行一些调整。这只是一个想法。另一个解决方案基于@Flater所说的增加文本宽度。这个想法(概括地说)是:
获取文本区域的宽度
在光标位置之前获取文本,并计算其宽度
获取光标位置后的文本,并计算其宽度
如果文本区域宽度之前的或不包含换行符(如果第一行上的文本较少),则光标位于第一行上的非
如果文本区域的后文本>宽度或不包含换行符,则光标不在最后一行
代码:
#holder是一个创建并隐藏的div
(用于查找文本宽度)
如果您认为这应该有效,您能否尝试调整您的解决方案以适应?注意,我不关心像素位置,只关心插入符号的精确行位置。我认为纯textarea
不可能(在我看来)但是,如果你能使用一些编辑器来解析纯html,那么你就可以定义哪一行是最后一行,哪一行是第一行。我还没来得及看看它们是否容易修复,但有两个问题:1)如果你把插入符号放在第二行的开头,它就不会给出正确的答案2)它在第一行的末尾不起作用,还有另一个问题:如果你在文本区域键入一些html,它就会中断(在我的解决方案中,我通过使用text
和一些css设置解决了这个问题)。@dystroy我稍微更正了一下
$('#t').keyup(function(e){
first_line="true";
last_line="true";
text = $(this).val();
width = $(this).width();
var cursorPosition = $(this).prop("selectionStart");
txtBeforeCaret = text.substring(0, cursorPosition);
txtAfterCaret = text.substring(cursorPosition);
widthBefore = $('#holder').text(txtBeforeCaret).width();
widthAfter = $('#holder').text(txtAfterCaret).width();
match1 = txtBeforeCaret.match(/\n/);
if(txtAfterCaret!==null){match2=txtAfterCaret.match(/\n/g);}
if(widthBefore>width || match1){first_line="false";}
if(widthAfter>width || (match2!==null && match2.length)) {last_line="false";}
$('#f').html(first_line);
$('#l').html(last_line);
});