如何处理文本区域中的 <tab>?
Posted
技术标签:
【中文标题】如何处理文本区域中的 <tab>?【英文标题】:How to handle <tab> in textarea? 【发布时间】:2011-09-02 16:40:31 【问题描述】:我想要一个文本区域来处理按下 tab 键的情况。
在默认情况下,如果您按下 tab 键,则焦点离开文本区域。但是当用户想要在 textarea 中键入 tab 键的情况下呢?
我可以捕捉这个事件并将焦点返回到 textarea 并将标签添加到 当前 光标位置吗?
【问题讨论】:
Use tab to indent in textarea的可能重复 我查看了一些现有的答案,但它们在某些方面都存在不足(无法撤消、性能不佳、取消缩进后选择不正确)。我最近写了一个可以正确处理这个问题的小模块,叫做indent-textarea
【参考方案1】:
您可以:http://jsfiddle.net/sdDVf/8/。
$("textarea").keydown(function(e)
if(e.keyCode === 9) // tab was pressed
// get caret position/selection
var start = this.selectionStart;
var end = this.selectionEnd;
var $this = $(this);
var value = $this.val();
// set textarea value to: text before caret + tab + text after caret
$this.val(value.substring(0, start)
+ "\t"
+ value.substring(end));
// put caret at right position again (add one for the tab)
this.selectionStart = this.selectionEnd = start + 1;
// prevent the focus lose
e.preventDefault();
);
【讨论】:
@Amine: 阻止浏览器的默认选项卡功能。我现在看到没有必要。我将对此进行搜索。编辑:return false
似乎包括preventDefault
:***.com/questions/1357118/…。
也实现了选择覆盖。
@sergzach:我的解决方案在 IE8 中根本不起作用,因为它不支持 selectionStart
/selectionEnd
。您必须创建文本范围,但恐怕我仍然不明白它是如何工作的......
这会阻止浏览器的撤消功能 (Ctrl+z)
不确定如何/为什么错过了,在最后一个子字符串调用 start 应该作为第一个参数给出:+ value.substring(start, end));
-- 否则在选择文本时使用 tab 键会擦除文本。【参考方案2】:
这是 pimvdb 答案的修改版本,不需要 JQuery:
document.querySelector("textarea").addEventListener('keydown',function(e)
if(e.keyCode === 9) // tab was pressed
// get caret position/selection
var start = this.selectionStart;
var end = this.selectionEnd;
var target = e.target;
var value = target.value;
// set textarea value to: text before caret + tab + text after caret
target.value = value.substring(0, start)
+ "\t"
+ value.substring(end);
// put caret at right position again (add one for the tab)
this.selectionStart = this.selectionEnd = start + 1;
// prevent the focus lose
e.preventDefault();
,false);
我在 Firefox 21.0 和 Chrome 27 中对其进行了测试。不知道它是否适用于其他任何地方。
【讨论】:
要将其应用于所有 textarea 使用 querySelectorAll,枚举返回的列表,并将事件侦听器添加到每个元素。 要使这种方法发挥作用,您需要将 eventListener 附加到 individual DOM 元素。为此:1) 获取所有元素document.querySelectorAll("textarea")
2) 通过数组循环以将事件侦听器附加到每个元素。然后它应该工作
将撤销功能作为接受的答案。【参考方案3】:
天哪,以前的所有答案都未能提供通常体面的(即对于程序员而言)选项卡控件。
也就是说,在选择行时点击 TAB 将使这些行缩进,而 SHIFTTAB 将取消缩进。 p>
_edited(2016 年 11 月):keyCode 替换为 charCode || keyCode,根据KeyboardEvent.charCode - Web APIs | MDN
(function($)
$.fn.enableSmartTab = function()
var $this;
$this = $(this);
$this.keydown(function(e)
var after, before, end, lastNewLine, changeLength, re, replace, selection, start, val;
if ((e.charCode === 9 || e.keyCode === 9) && !e.altKey && !e.ctrlKey && !e.metaKey)
e.preventDefault();
start = this.selectionStart;
end = this.selectionEnd;
val = $this.val();
before = val.substring(0, start);
after = val.substring(end);
replace = true;
if (start !== end)
selection = val.substring(start, end);
if (~selection.indexOf('\n'))
replace = false;
changeLength = 0;
lastNewLine = before.lastIndexOf('\n');
if (!~lastNewLine)
selection = before + selection;
changeLength = before.length;
before = '';
else
selection = before.substring(lastNewLine) + selection;
changeLength = before.length - lastNewLine;
before = before.substring(0, lastNewLine);
if (e.shiftKey)
re = /(\n|^)(\t|[ ]1,8)/g;
if (selection.match(re))
start--;
changeLength--;
selection = selection.replace(re, '$1');
else
selection = selection.replace(/(\n|^)/g, '$1\t');
start++;
changeLength++;
$this.val(before + selection + after);
this.selectionStart = start;
this.selectionEnd = start + selection.length - changeLength;
if (replace && !e.shiftKey)
$this.val(before + '\t' + after);
this.selectionStart = this.selectionEnd = start + 1;
);
;
)(jQuery);
$(function()
$("textarea").enableSmartTab();
)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea rows="10" cols="80">
/* Just some code to edit with our new superTab */
(function($)
$.fn.enableSmartTab = function()
$this = $(this);
$this.keydown(function(e)
if ((e.charCode === 9 || e.keyCode === 9) && !e.metaKey && !e.ctrlKey && !e.altKey)
e.preventDefault();
</textarea>
【讨论】:
我刚刚写了my code 来实现这个功能。 在你不能使用 jQuery 的情况下,考虑使用我的代码。 @K._ 不错的代码,但我建议通过 babel 或 google 闭包运行它以删除 ES6 组件。 ES6 很棒,但是没有使用 ES6 兼容浏览器的用户太多了。event.key
在浏览器中也不是(IIRC)一致的,键在不同的浏览器中可能被称为不同的东西,而 Safari 根本不支持该属性。这是人们使用 jQuery 的other 原因,虽然经常被遗忘,但它是为了保证跨浏览器的兼容性。我不是在批评你的努力,我认为你做得很好,但它必须是跨浏览器的
@K._ 如果你看一下我写的代码,里面实际上并没有太多的 jQuery。排除监听器添加,jQuery 唯一实际使用的是$.fn.val
。处理程序本身已经使用原生事件属性。
~和!~是什么意思?
@1.21gigawatts 它是按位非运算符,这里有一个很好的解释为什么使用它here【参考方案4】:
在 Vanilla(默认)JS 中,这将是:
var textareas = document.getElementsByTagName('textarea');
if ( textareas )
for ( var i = 0; i < textareas.length; i++ )
textareas[i].addEventListener( 'keydown', function ( e )
if ( e.which != 9 ) return;
var start = this.selectionStart;
var end = this.selectionEnd;
this.value = this.value.substr( 0, start ) + "\t" + this.value.substr( end );
this.selectionStart = this.selectionEnd = start + 1;
e.preventDefault();
return false;
);
textarea
border: 1px solid #cfcfcf;
width: 100%;
margin-left: 0px;
top: 0px;
bottom: 0px;
position: absolute;
<textarea>
var x = 10;
var y = 10;
</textarea>
【讨论】:
谢谢,伙计。人们没有意识到并不是每个人都在使用 jQuery。 @Mark 你能减小标签大小吗? 这样更好吗?【参考方案5】:在(多个)textarea 元素内启用制表符
纠正@alexwells 的答案并启用现场演示
var textAreaArray = document.querySelectorAll("textarea");
for (var i = textAreaArray.length-1; i >=0;i--)
textAreaArray[i].addEventListener('keydown',function(e)
if(e.keyCode === 9) // tab was pressed
// get caret position/selection
var start = this.selectionStart;
var end = this.selectionEnd;
var target = e.target;
var value = target.value;
// set textarea value to: text before caret + tab + text after caret
target.value = value.substring(0, start)
+ "\t"
+ value.substring(end);
// put caret at right position again (add one for the tab)
this.selectionStart = this.selectionEnd = start + 1;
// prevent the focus lose
e.preventDefault();
,false);
<textarea rows="10" cols="80"></textarea>
<textarea rows="10" cols="80"></textarea>
【讨论】:
使用原生 javascript 在 textarea 元素中启用制表符【参考方案6】:在谷歌搜索时发现了这个。我做了一个非常短的,也可以缩进和反向缩进选择的文本:
jQ(document).on('keydown', 'textarea', function(e)
if (e.keyCode !== 9) return;
var Z;
var S = this.selectionStart;
var E = Z = this.selectionEnd;
var A = this.value.slice(S, E);
A = A.split('\n');
if (!e.shiftKey)
for (var x in A)
A[x] = '\t' + A[x];
Z++;
else
for (var x in A)
if (A[x][0] == '\t')
A[x] = A[x].substr(1);
Z--;
A = A.join('\n');
this.value = this.value.slice(0, S) + A + this.value.slice(E);
this.selectionStart = S != E ? S : Z;;
this.selectionEnd = Z;
e.preventDefault();
);
【讨论】:
以上是关于如何处理文本区域中的 <tab>?的主要内容,如果未能解决你的问题,请参考以下文章