我有HTML textarea。我想修改它,以便它实现自动缩进,即插入NEWLINE后,我想在新行的开头自动插入空格(空格数取决于前一行的缩进)。我想通过注册一个听'keypress'事件的处理程序来做到这一点。现在我有一个选择:(a)保留默认处理程序并在浏览器将换行符添加到textarea.value之后插入空格,或者(b)使用preventDefault()并自己插入整个内容(即换行符和空格)。
在下面的代码所示的情况(a)中,我的处理程序在浏览器添加换行符之前执行,因此空格(或“ - ”用于说明)最终在行的末尾,而不是在新的开始。
在情况(b)中,如下面代码中的注释所示,文本被正确修改,但如果它导致光标离开textarea视图,则内容不会滚动(很可能是因为内容滚动是一部分默认处理),所以光标消失在textarea边界后面,只有当我发送另一个击键(即不是换行符)时才会重新出现。
如何在不丢失默认滚动的情况下实现自动缩进效果?
我知道这个效果可以通过延迟插入空格(例如使用setTimeout())来近似,这样运行时就有足够的时间来完成默认处理(即插入换行符和垂直滚动),但是对我来说这似乎是一个巨大的障碍并引入竞争条件,恐怕会在最不期望的情况下打击我(大量复制粘贴,由于其他操作导致运行时缓慢,键盘重复率高等)。理想情况下,我希望(i)在默认处理之后调用我的代码,或者(ii)能够阻止默认处理,运行我的代码,并显式调用默认处理。如何实现呢?
谢谢!
格雷格
PS:我对整合复杂的textarea替代品不感兴趣,例如: Editarea(我使用一个,它在浏览器中非常脆弱)。
在FF3上测试。
<html>
<head>
<script type="text/javascript">
function onKeyPressHandler(e) {
if (e.which == 13) // ASCII newline
{
var start = this.selectionStart;
var end = this.selectionEnd;
var v = this.value;
this.value = v.slice(0, start) + '--' + v.slice(end); // (a)
// (b): this.value = v.slice(0, start) + '\n--' + v.slice(end);
// (b): e.preventDefault();
}
}
onload = function() {
var editor = document.getElementById("editor");
editor.addEventListener('keypress', onKeyPressHandler, false);
}
</script>
</head>
<body>
<textarea rows="20" cols="80" id="editor"></textarea>
</body>
</html>
答案 0 :(得分:2)
我修改了Leo修复延迟问题的答案(通过使用按键而不是带有setTimeout的keyup),以及导致编辑文本中间不起作用的错误。
$("textarea").keydown(function(e)
{
if (e.which == 9) //ASCII tab
{
e.preventDefault();
var start = this.selectionStart;
var end = this.selectionEnd;
var v = $(this).val();
if (start == end)
{
$(this).val(v.slice(0, start) + " " + v.slice(start));
this.selectionStart = start+4;
this.selectionEnd = start+4;
return;
}
var selectedLines = [];
var inSelection = false;
var lineNumber = 0;
for (var i = 0; i < v.length; i++)
{
if (i == start)
{
inSelection = true;
selectedLines.push(lineNumber);
}
if (i >= end)
inSelection = false;
if (v[i] == "\n")
{
lineNumber++;
if (inSelection)
selectedLines.push(lineNumber);
}
}
var lines = v.split("\n");
for (var i = 0; i < selectedLines.length; i++)
{
lines[selectedLines[i]] = " " + lines[selectedLines[i]];
}
$(this).val(lines.join("\n"));
}
});
$("textarea").keypress(function(e)
{
if (e.which == 13) // ASCII newline
{
setTimeout(function(that)
{
var start = that.selectionStart;
var v = $(that).val();
var thisLine = "";
var indentation = 0;
for (var i = start-2; i >= 0 && v[i] != "\n"; i--)
{
thisLine = v[i] + thisLine;
}
for (var i = 0; i < thisLine.length && thisLine[i] == " "; i++)
{
indentation++;
}
$(that).val(v.slice(0, start) + " ".repeat(indentation) + v.slice(start));
that.selectionStart = start+indentation;
that.selectionEnd = start+indentation;
}, 0.01, this);
}
});
&#13;
<textarea rows="20" cols="40"></textarea>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
&#13;
答案 1 :(得分:0)
检查出来:http://thelackthereof.org/JQuery_Autoindent
以及http://plugins.jquery.com/content/optional-auto-indent-setting
答案 2 :(得分:0)
这是很多借来的代码(谢谢,stackoverflow!),还有一些小的调整。第一部分只是创建一个mirrow,这样你就可以知道你在哪一行(与你的问题没有关系),但它包含了设置当前缩进的东西,这很重要。
$(document).keypress(function(e) {
if (e.keyCode ==13){
e.preventDefault();
var start = $('textarea').get(0).selectionStart;
var end = $('textarea').get(0).selectionEnd;
// set textarea value to: text before caret + tab + text after caret
var spaces = "\n"
for (i = 0; i < start; i++) {
spaces += " "
}
$('textarea').val($('textarea').val().substring(0, start)
+ spaces
+ $('textarea').val().substring(end));
// put caret at right position again
console.log(spaces.length)
$('textarea').get(0).selectionStart =
$('textarea').get(0).selectionEnd = start + spaces.length;
}
})
答案 3 :(得分:0)
虽然这篇文章已有近六年的历史,但您可以通过以下方式自动缩进textarea
:
$("textarea").keydown(function(e)
{
if (e.which == 9) //ASCII tab
{
e.preventDefault();
var start = this.selectionStart;
var end = this.selectionEnd;
var v = $(this).val();
if (start == end)
{
$(this).val(v.slice(0, start) + " " + v.slice(start));
return;
}
var selectedLines = [];
var inSelection = false;
var lineNumber = 0;
for (var i = 0; i < v.length; i++)
{
if (i == start)
{
inSelection = true;
selectedLines.push(lineNumber);
}
if (i >= end)
inSelection = false;
if (v[i] == "\n")
{
lineNumber++;
if (inSelection)
selectedLines.push(lineNumber);
}
}
var lines = v.split("\n");
for (var i = 0; i < selectedLines.length; i++)
{
lines[selectedLines[i]] = " " + lines[selectedLines[i]];
}
$(this).val(lines.join("\n"));
}
});
$("textarea").keyup(function(e)
{
if (e.which == 13) // ASCII newline
{
var start = this.selectionStart;
var v = $(this).val();
var thisLine = "";
var indentation = 0;
for (var i = start-2; i >= 0 && v[i] != "\n"; i--)
{
thisLine = v[i] + thisLine;
}
for (var i = 0; i < thisLine.length && thisLine[i] == " "; i++)
{
indentation++;
}
$(this).val(v.slice(0, start) + " ".repeat(indentation) + v.slice(start));
}
});
&#13;
<textarea rows="20" cols="40"></textarea>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
&#13;
不幸的是,由于它被绑定到keyup
,当您按住Enter键时,光标将位于下一行的开头。它只会在您释放回车时缩进新行。这意味着如果您点击回车,则在缩进之前会有延迟: