马黑黑 发表于 2023-1-3 10:13

textarea智能缩进

<p>作为轻量级的多行文本编辑控件,textarea&nbsp;非常经济实惠,但它原生的属性不多,智能自动缩进需要通过编程实现。本文,提供一个自研的自动缩进功能,即,按下回车键后,根据上一行是否有缩进、缩进多少个&nbsp;tab&nbsp;和空格来实现下一行也拥有相同的缩进形式。</p><p><br></p><p>思路是,监测文本框的&nbsp;keyup(键位弹起)事件,如果&nbsp;keyCode === 13,可判断操作的键位是回车键,则运行预设的处理缩进函数。</p><p><br></p><p>代码如下:</p><p><br></p>
<pre>&lt;style&gt;
<span style="color: red;">#txtbox </span>{
&nbsp; &nbsp;<span style="color: blue;">margin</span>: 50px auto;
&nbsp; &nbsp;<span style="color: blue;">width</span>: 600px;
&nbsp; &nbsp;<span style="color: blue;">height</span>: 400px;
&nbsp; &nbsp;<span style="color: blue;">display</span>: block;
&nbsp; &nbsp;<span style="color: blue;">padding</span>: 10px;
}
&lt;/style&gt;

&lt;<span style="color:darkred">textarea</span> <span style="color: red">id</span><span style="color: blue">=</span><span style="color: magenta">"txtbox"</span>&gt;&lt;<span style="color: darkred">/textarea</span>&gt;

&lt;script&gt;

<span style="color: green">//智能缩进函数 参数ele 文本框元素
</span><span style="color: blue">let</span> insetIndent = (ele) =&gt; {
&nbsp; &nbsp;<span style="color: green">//获取 start - 选择区起始值 end - 选择区结束值 selected - 被选择的字符串
</span>&nbsp; &nbsp;<span style="color: green">//注:没有被选择文本时就是光标所在的pos值,此时 start = end
</span>&nbsp; &nbsp;<span style="color: blue">let</span> start = ele.selectionStart, end = ele.selectionEnd, selected = ele.value.substring(start,end);
&nbsp; &nbsp;<span style="color: green">//获取 str1 - 选择区上半部分文本 str2 - 选择区下半部分文本
</span>&nbsp; &nbsp;<span style="color: blue">let</span> str1 = ele.value.substring(0, start), str2 = ele.value.substring(end);
&nbsp; &nbsp;<span style="color: green">//将上半部分按行拆分为 strAr 数组
</span>&nbsp; &nbsp;<span style="color: blue">let</span> strAr = str1.split(<span style="color: magenta">'\n'</span>);
&nbsp; &nbsp;<span style="color: green">//获得目标行 :回车按下后倒数第二行
</span>&nbsp; &nbsp;<span style="color: blue">let</span> targetLine = strAr;
&nbsp; &nbsp;<span style="color: green">//通过匹配行首空格(tab也被视为空格)获取待处理缩进字符数组
</span>&nbsp; &nbsp;<span style="color: blue">let</span> tmpAr = targetLine.match(/^[\s]+/g);
&nbsp; &nbsp;<span style="color: green">//声明缩进字符变量
</span>&nbsp; &nbsp;<span style="color: blue">let</span> indent = <span style="color: magenta">''</span>;
&nbsp; &nbsp;<span style="color: green">//若缩进字符数组不为空 :将缩进字符加入到 indent 变量
</span>&nbsp; &nbsp;<span style="color: blue">if</span> (tmpAr !== null) indent += tmpAr;
&nbsp; &nbsp;<span style="color: green">//重组文本框文本
</span>&nbsp; &nbsp;ele.value = str1 + indent + str2;
&nbsp; &nbsp;<span style="color: green">//设置光标位置
</span>&nbsp; &nbsp;ele.setSelectionRange(start + indent.length, start + indent.length);
}

<span style="color: green">//键盘键位弹起事件
</span>txtbox.onkeyup = (e) =&gt; {
&nbsp; &nbsp;<span style="color: green">//如果键位 keyCode 值等于 13 表明按下的是回车键,运行智能缩进函数
</span>&nbsp; &nbsp;<span style="color: blue">if</span>(e.keyCode === 13) insetIndent(txtbox,e);
}

&lt;/script&gt;

</pre>
<p>效果看楼下,欢迎测试。</p>

马黑黑 发表于 2023-1-3 10:14

<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>

马黑黑 发表于 2023-1-3 10:14

二楼完整代码:
<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>

马黑黑 发表于 2023-1-3 10:18

关于匹配 tab 和空格,用了全局开关 g :

let tmpAr = targetLine.match(/^[\s]+/g);

这个有些浪费资源,不过也没关系,因为匹配的对象只是一行文本,量不会太大。

马黑黑 发表于 2023-1-3 12:49

本帖最后由 马黑黑 于 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”后,按下回车键就有换行符了,然后再根据后面的判断是否加入缩进符。

小辣椒 发表于 2023-1-3 14:56

黑黑又有教程出来,辛苦了。{:4_187:}

马黑黑 发表于 2023-1-3 16:26

小辣椒 发表于 2023-1-3 14:56
黑黑又有教程出来,辛苦了。

这个更多是笔记

红影 发表于 2023-1-3 18:48

没看懂这个是派什么用的,在二楼试了一下,好像第一行没缩进,到后面的回车后出现了缩进。

红影 发表于 2023-1-3 18:50

再试,好像第一行缩进的量,被后面的回车键下的文字自动继承了。

马黑黑 发表于 2023-1-3 19:00

红影 发表于 2023-1-3 18:48
没看懂这个是派什么用的,在二楼试了一下,好像第一行没缩进,到后面的回车后出现了缩进。

智能缩进是根据前面的操作而定,如果本行没有缩进,回车后就继承这个不缩进,有也同样。这个理念是代码编辑器的理念,Windows的记事本没有这个功能。

马黑黑 发表于 2023-1-3 19:00

红影 发表于 2023-1-3 18:50
再试,好像第一行缩进的量,被后面的回车键下的文字自动继承了。

对,就是这个意思

红影 发表于 2023-1-3 22:59

马黑黑 发表于 2023-1-3 19:00
智能缩进是根据前面的操作而定,如果本行没有缩进,回车后就继承这个不缩进,有也同样。这个理念是代码编 ...

哦,word里是可以选择的。

红影 发表于 2023-1-3 23:00

马黑黑 发表于 2023-1-3 19:00
对,就是这个意思

开始没弄明白{:4_173:}

马黑黑 发表于 2023-1-3 23:35

红影 发表于 2023-1-3 23:00
开始没弄明白

正常的,发帖也基本用不上textarea

马黑黑 发表于 2023-1-3 23:36

红影 发表于 2023-1-3 22:59
哦,word里是可以选择的。

word是顶级文档处理软件,这些是小儿科

红影 发表于 2023-1-4 21:32

马黑黑 发表于 2023-1-3 23:35
正常的,发帖也基本用不上textarea

这些都是很有用的工具{:4_204:}

红影 发表于 2023-1-4 21:54

马黑黑 发表于 2023-1-3 23:36
word是顶级文档处理软件,这些是小儿科

它也是代码做的么?真神奇。

马黑黑 发表于 2023-1-4 22:23

红影 发表于 2023-1-4 21:54
它也是代码做的么?真神奇。

你用的APP,包括手机的、电脑的,全部是代码做的。还有,你的洗衣机,电冰箱,烤箱,里面也都有代码。

马黑黑 发表于 2023-1-4 22:24

红影 发表于 2023-1-4 21:32
这些都是很有用的工具

是的,交互的时候,表单就少不了这些

红影 发表于 2023-1-5 18:59

马黑黑 发表于 2023-1-4 22:23
你用的APP,包括手机的、电脑的,全部是代码做的。还有,你的洗衣机,电冰箱,烤箱,里面也都有代码。

嗯,所有的带界面的包括只能控制的,都有代码发挥作用。
页: [1] 2 3 4
查看完整版本: textarea智能缩进