马黑黑 发表于 2026-5-27 20:43

textarea移动行代码示例

<style>
    .artBox { margin: 20px auto; font: normal 18px/26px sans-serif; }
</style>

<div class="artBox">
    <p>在 textarea 编辑器中上下移动光标所在行或选中的多行,应该有多种实现方式。由于个人偏好使用JS数组,以下实现机制主要通过数组达成,整体思路和实现步骤应该可以在代码注释中得以充分展现:</p>
    <div class="codebox" data-prev="1">
&lt;style&gt;
    #ta { width: 600px; height: 300px; padding: 10px; display: block; margin: 20px auto; }
&lt;/style&gt;

&lt;textarea id="ta"&gt;
眼儿媚

石孝友

愁云淡淡雨潇潇,
暮暮复朝朝。
别来应是,
眉峰翠减,
腕玉香销。

【注】

①萱草,又名谖草,谖就是忘的意思。《诗经·卫风·伯兮》:“焉得谖草,言树之背”。朱熹注曰:“谖草,令人忘忧。”
②杜甫《佳人》:“天寒翠袖薄,日暮倚修竹。”
③张说《戏草树》:“戏问芭蕉叶,何愁心不开。”
&lt;/textarea&gt;
&lt;div style="text-align: center"&gt;(点击任意行或选中多行,然后按 alt+↑/↓ 上下移动行)&lt;/div&gt;

&lt;script&gt;
    ta.onkeydown = (e) =&gt; moveLines(ta, e); // 编辑器按键按下时运行移动行函数

    // 函数 moveLines : 移动textarea中的单行/多行
    //    textarea - 编辑器DOM实体
    //    event - 事件对象
    //   
    //    函数通过 ALT + ↑/↓ 触发
    //
    function moveLines(textarea, event) {
      if (!event.altKey) return; // 由Alt键触发
      event.preventDefault(); // 组着默认行为
      // 光标位置
      let start = textarea.selectionStart, end = textarea.selectionEnd;
      let len = 0,      // 字符串累加长度(用于 begins 和 ends)
            begins = [],// 选中行索引数组(相对于 start)
            ends = [],    // 选中行行索引数组(相对于 end)
            s1 = [],      // 分割数组1(选中行上方行数组)
            s2 = [],      // 分割数组2(选中行数组)
            s3 = [],      // 分割数组3(选中行下方行数组)
            exchangeline; // 交换行
      const ar = textarea.value.split('\n'); // 编辑器内容按行拆分存入数组

      // 遍历所有行获取 begins、ends 行号索引值 :
      // beings是选中行第一行,ends是选中行最后一行
      for (let i = 0; i &lt; ar.length; i ++) {
            len += ar.length + 1;
            // 基于 start 获取 begins 行索引
            if (len &gt; start) {
                begins.push(i);
            }
            // 基于 end 获取 ends 行索引
            if (len &gt;= end) {
                ends.push(i);
                break;
            }
      }

      // 根据 begins、ends 确定选中行上方、选中行、选中行下方行数组
      s1 = ar.filter((item, key) =&gt; key &lt; begins);
      s2 = ar.filter((item, key) =&gt; key &gt;= begins && key &lt;= ends);
      s3 = ar.filter((item, key) =&gt; key &gt; ends);

      // 如果按下的是 Alt+↑
      if (event.key === 'ArrowUp') {
            if (begins === 0) return; // 选中行第一行是编辑器的第一行时退出操作
            exchangeline = s1; // 交换行是 s1 的最后一行
            s1.pop(); // s1 删除最后一行元素
            s3.unshift(exchangeline); // s3 接收交换行到第一行
      // 如果按下的是 Alt + ↓
      } else if(event.key === 'ArrowDown') {
            if (ends === ar.length - 1) return; // 选中行最后一行是编辑器最后一行时退出操作
            exchangeline = s3; // 交换行是 s3 第一行
            s1.push(exchangeline); // s1 接收交换行到最后一行
            s3.shift(); // s3 剔除第一行
      }

      
      textarea.value = [...s1, ...s2, ...s3].join('\n'); // 重新组装编辑器的内容
      // 重新确定编辑框选中的文本(选中文本是编辑框第一行时做特殊处理以确保正行文本被选中)
      textarea.selectionStart = s1.join('\n').length + (s1.length === 0 ? 0 : 1);
      textarea.selectionEnd = s1.join('\n').length + s2.join('\n').length + 1;
    }
&lt;/script&gt;
    </div>
    <p>核心在 moveLines() 函数中,里面的设计是将编辑器里的内容分成三部分:选中的行、选中行前边的行和后边的行,以数组方式存储并对之进行处理,最后整合为新的编辑器文本 Value 值。本方案去掉注释后代码量已经相当简洁,至少代码量比 AI 推荐的方法少很多。</p>
</div>

<script type="module">
    import linenumber from 'https://638183.freep.cn/638183/web/helight/linenumber.js';
    linenumber();
</script>

马黑黑 发表于 2026-5-27 20:58

一楼移动行的实现方案已经应用到 mhta.js,应用实例:

http://mhh.52qingyin.cn/api/pencilcode/simple-editor.html

杨帆 发表于 2026-5-27 22:01

马黑黑 发表于 2026-5-27 20:58
一楼移动行的实现方案已经应用到 mhta.js,应用实例:

http://mhh.52qingyin.cn/api/pencilcode/simple- ...

感谢马老师开发出很实用的功能,辛苦了{:4_190:}

红影 发表于 2026-5-27 22:20

用ALT加上上下键,可以让选中的行整体移动呢。这个太神奇了{:4_199:}

马黑黑 发表于 2026-5-27 22:27

红影 发表于 2026-5-27 22:20
用ALT加上上下键,可以让选中的行整体移动呢。这个太神奇了

绝大多数代码编辑器都支持移动单行/多行功能,各自定义的组合键不一样。Textarea也可以通过JS做到。

马黑黑 发表于 2026-5-27 22:27

杨帆 发表于 2026-5-27 22:01
感谢马老师开发出很实用的功能,辛苦了

{:4_180:}
页: [1]
查看完整版本: textarea移动行代码示例