textarea智能缩进
<p>作为轻量级的多行文本编辑控件,textarea 非常经济实惠,但它原生的属性不多,智能自动缩进需要通过编程实现。本文,提供一个自研的自动缩进功能,即,按下回车键后,根据上一行是否有缩进、缩进多少个 tab 和空格来实现下一行也拥有相同的缩进形式。</p><p><br></p><p>思路是,监测文本框的 keyup(键位弹起)事件,如果 keyCode === 13,可判断操作的键位是回车键,则运行预设的处理缩进函数。</p><p><br></p><p>代码如下:</p><p><br></p><pre><style>
<span style="color: red;">#txtbox </span>{
<span style="color: blue;">margin</span>: 50px auto;
<span style="color: blue;">width</span>: 600px;
<span style="color: blue;">height</span>: 400px;
<span style="color: blue;">display</span>: block;
<span style="color: blue;">padding</span>: 10px;
}
</style>
<<span style="color:darkred">textarea</span> <span style="color: red">id</span><span style="color: blue">=</span><span style="color: magenta">"txtbox"</span>><<span style="color: darkred">/textarea</span>>
<script>
<span style="color: green">//智能缩进函数 参数ele 文本框元素
</span><span style="color: blue">let</span> insetIndent = (ele) => {
<span style="color: green">//获取 start - 选择区起始值 end - 选择区结束值 selected - 被选择的字符串
</span> <span style="color: green">//注:没有被选择文本时就是光标所在的pos值,此时 start = end
</span> <span style="color: blue">let</span> start = ele.selectionStart, end = ele.selectionEnd, selected = ele.value.substring(start,end);
<span style="color: green">//获取 str1 - 选择区上半部分文本 str2 - 选择区下半部分文本
</span> <span style="color: blue">let</span> str1 = ele.value.substring(0, start), str2 = ele.value.substring(end);
<span style="color: green">//将上半部分按行拆分为 strAr 数组
</span> <span style="color: blue">let</span> strAr = str1.split(<span style="color: magenta">'\n'</span>);
<span style="color: green">//获得目标行 :回车按下后倒数第二行
</span> <span style="color: blue">let</span> targetLine = strAr;
<span style="color: green">//通过匹配行首空格(tab也被视为空格)获取待处理缩进字符数组
</span> <span style="color: blue">let</span> tmpAr = targetLine.match(/^[\s]+/g);
<span style="color: green">//声明缩进字符变量
</span> <span style="color: blue">let</span> indent = <span style="color: magenta">''</span>;
<span style="color: green">//若缩进字符数组不为空 :将缩进字符加入到 indent 变量
</span> <span style="color: blue">if</span> (tmpAr !== null) indent += tmpAr;
<span style="color: green">//重组文本框文本
</span> ele.value = str1 + indent + str2;
<span style="color: green">//设置光标位置
</span> ele.setSelectionRange(start + indent.length, start + indent.length);
}
<span style="color: green">//键盘键位弹起事件
</span>txtbox.onkeyup = (e) => {
<span style="color: green">//如果键位 keyCode 值等于 13 表明按下的是回车键,运行智能缩进函数
</span> <span style="color: blue">if</span>(e.keyCode === 13) insetIndent(txtbox,e);
}
</script>
</pre>
<p>效果看楼下,欢迎测试。</p> <style>
#txtbox {
margin: 50px auto;
width: 600px;
height: 400px;
display: block;
padding: 10px;
position: relative;
}
</style>
<textarea id="txtbox"></textarea>
<script>
let insetIndent = (ele) => {
let start = ele.selectionStart, end = ele.selectionEnd, selected = ele.value.substring(start,end);
let str1 = ele.value.substring(0, start), str2 = ele.value.substring(end);
let strAr = str1.split('\n');
let targetLine = strAr;
let tmpAr = targetLine.match(/^[\s]+/g);
let indent = '';
if (tmpAr !== null) indent += tmpAr;
ele.value = str1 + indent + str2;
ele.setSelectionRange(start + indent.length, start + indent.length);
}
txtbox.onkeyup = (e) => {
if(e.keyCode === 13) insetIndent(txtbox,e);
}
</script>
二楼完整代码:
<style>
#txtbox {
margin: 50px auto;
width: 600px;
height: 400px;
display: block;
padding: 10px;
position: relative;
}
</style>
<textarea id="txtbox"></textarea>
<script>
let insetIndent = (ele) => {
let start = ele.selectionStart, end = ele.selectionEnd, selected = ele.value.substring(start,end);
let str1 = ele.value.substring(0, start), str2 = ele.value.substring(end);
let strAr = str1.split('\n');
let targetLine = strAr;
let tmpAr = targetLine.match(/^[\s]+/g);
let indent = '';
if (tmpAr !== null) indent += tmpAr;
ele.value = str1 + indent + str2;
ele.setSelectionRange(start + indent.length, start + indent.length);
}
txtbox.onkeyup = (e) => {
if(e.keyCode === 13) insetIndent(txtbox,e);
}
</script>
关于匹配 tab 和空格,用了全局开关 g :
let tmpAr = targetLine.match(/^[\s]+/g);
这个有些浪费资源,不过也没关系,因为匹配的对象只是一行文本,量不会太大。 本帖最后由 马黑黑 于 2023-1-3 12:51 编辑
用 onkeyup 键位弹起事件的实际效果,上屏有延时感,原因在于 onkeyup 事件的上屏有一个等待过程——按下后弹起的过程,JS要等待这个过程结束才会执行指定的功能。
消除上屏延时感现象,应弃用 keyup 事件,改用 onkeydown 事件。如此,有一个地方需要增加、两个地方需要改变:
一,增加:阻止按键的默认功能
函数开头处加一行代码:
e.preventDefault();
这是JS内置的基于DOM元素的阻止键盘、鼠标默认行为的方法。
二,改变:
(一)原来的代码 19 行:
let targetLine = strAr2];
改为:
let targetLine = strAr1];
修改原因是,即使不阻止回车键的默认行为,按下和松开对文本框文本的拆分都需要额外处理,按下未松开之前,输入光标还在原行,松开后则光标在下一行,所以这里获得目标行的处理不能再用行数组总数减去 2,只能减去 1 。
(二)原来代码 21 行:
let indent = '';
改为:
let indent = '\n';
“\n” 是换行的意思。由于修改后的代码中,前面我们阻止了回车键按下的默认换行功能,这里得还给人家,否则文本框将出现按回车键换不了行的严重后果。缩进字符变量 indent 的初始值为“\n”后,按下回车键就有换行符了,然后再根据后面的判断是否加入缩进符。 黑黑又有教程出来,辛苦了。{:4_187:} 小辣椒 发表于 2023-1-3 14:56
黑黑又有教程出来,辛苦了。
这个更多是笔记 没看懂这个是派什么用的,在二楼试了一下,好像第一行没缩进,到后面的回车后出现了缩进。 再试,好像第一行缩进的量,被后面的回车键下的文字自动继承了。 红影 发表于 2023-1-3 18:48
没看懂这个是派什么用的,在二楼试了一下,好像第一行没缩进,到后面的回车后出现了缩进。
智能缩进是根据前面的操作而定,如果本行没有缩进,回车后就继承这个不缩进,有也同样。这个理念是代码编辑器的理念,Windows的记事本没有这个功能。 红影 发表于 2023-1-3 18:50
再试,好像第一行缩进的量,被后面的回车键下的文字自动继承了。
对,就是这个意思 马黑黑 发表于 2023-1-3 19:00
智能缩进是根据前面的操作而定,如果本行没有缩进,回车后就继承这个不缩进,有也同样。这个理念是代码编 ...
哦,word里是可以选择的。 马黑黑 发表于 2023-1-3 19:00
对,就是这个意思
开始没弄明白{:4_173:} 红影 发表于 2023-1-3 23:00
开始没弄明白
正常的,发帖也基本用不上textarea 红影 发表于 2023-1-3 22:59
哦,word里是可以选择的。
word是顶级文档处理软件,这些是小儿科 马黑黑 发表于 2023-1-3 23:35
正常的,发帖也基本用不上textarea
这些都是很有用的工具{:4_204:} 马黑黑 发表于 2023-1-3 23:36
word是顶级文档处理软件,这些是小儿科
它也是代码做的么?真神奇。 红影 发表于 2023-1-4 21:54
它也是代码做的么?真神奇。
你用的APP,包括手机的、电脑的,全部是代码做的。还有,你的洗衣机,电冰箱,烤箱,里面也都有代码。 红影 发表于 2023-1-4 21:32
这些都是很有用的工具
是的,交互的时候,表单就少不了这些 马黑黑 发表于 2023-1-4 22:23
你用的APP,包括手机的、电脑的,全部是代码做的。还有,你的洗衣机,电冰箱,烤箱,里面也都有代码。
嗯,所有的带界面的包括只能控制的,都有代码发挥作用。