<textarea>: 允许使用TAB键进行缩进
现状
默认情况下,<textarea> 元素本身并不处理TAB键,一旦你按下TAB键,输入焦点就会被浏览器切换到下一个元素,导致你无法在其中输入TAB键。
要想插入TAB键的话,也就只能通过JavaScript来手动处理按键消息了。
需求
通常,按下TAB的效果有以下几种:
- 仅按下 TAB 键
- 如果没有选中文本,在当前光标处插入一个TAB字符,光标后移。
- 如果只选中一行文本,则选中的文本被替换为一个TAB字符,光标后移一个。
- 如果选中了多行文本,则所有选中文本的行前面被插入一个TAB字符,整体后移一个TAB字符宽。
- 按下了Shift+TAB 键
- 如果没有选中文本,如果光标前面有TAB字符,则删除光标前面最近的那个TAB。
- 如果有选中文本,这个没有固定的操作,看实现者。
- 如果选中多行文本,则多行文本中行首字符是TAB的行最前面的那个TAB字符被删除,整体前移。
实现
大致的操作就是上面所列出的,以下是新手我的实现:
function enableTabIndent(t,e){
if(e.keyCode === 9){
var start = t.selectionStart;
var end = t.selectionEnd;
var that = jq(t);
var value = that.val();
var before = value.substring(0, start);
var after = value.substring(end);
var selArray = value.substring(start, end).split('\n');
var isIndent = !e.shiftKey;
if(isIndent){
if(start === end || selArray.length === 1){
that.val(before + '\t' + after);
t.selectionStart = t.selectionEnd = start + 1;
} else {
var sel = '\t' + selArray.join('\n\t');
that.val(before + sel + after);
t.selectionStart = start + 1;
t.selectionEnd = end + selArray.length;
}
} else {
var reduceEnd = 0;
var reduceStart = false;
if(selArray.length > 1) {
selArray.forEach(function(x, i, a){
if(i>0 && x.length>0 && x[0]==='\t'){
a[i] = x.substring(1);
reduceEnd++;
}
});
sel = selArray.join('\n');
} else {
sel = selArray[0];
}
var b1 = '',b2 = '';
if(before.length){
var npos = before.lastIndexOf('\n');
if(npos !== -1){
b1 = before.substring(0, npos+1);
b2 = before.substring(npos+1);
} else {
b1 = '';
b2 = before;
}
sel = b2 + sel;
}
if(sel.length && sel[0]==='\t'){
sel = sel.substring(1);
reduceStart = true;
}
that.val(b1 + sel + after);
t.selectionStart = start + (reduceStart ? -1 : 0);
t.selectionEnd = end - (reduceEnd + (reduceStart ? 1 : 0));
}
return true;
}
return false;
}
效果
对于下面的代码:
<div>
<textarea style="width: 50%; height: 100px;"></textarea><br>
<textarea style="width: 50%; height: 100px;" id="tabbed"></textarea>
</div>
<script type="text/javascript">
document.getElementById('tabbed').onkeydown = function(e){
if(enableTabIndent(this, e)){
e.preventDefault();
}
};
</script>
所产生的效果如下,可以输入点文本,然后感受下: