请马上登录,朋友们都在花潮里等着你哦:)
您需要 登录 才可以下载或查看,没有账号?立即注册
x
在 textarea 编辑器中上下移动光标所在行或选中的多行,应该有多种实现方式。由于个人偏好使用JS数组,以下实现机制主要通过数组达成,整体思路和实现步骤应该可以在代码注释中得以充分展现:
<style>
#ta { width: 600px; height: 300px; padding: 10px; display: block; margin: 20px auto; }
</style>
<textarea id="ta">
眼儿媚
石孝友
愁云淡淡雨潇潇,
暮暮复朝朝。
别来应是,
眉峰翠减,
腕玉香销。
【注】
①萱草,又名谖草,谖就是忘的意思。《诗经·卫风·伯兮》:“焉得谖草,言树之背”。朱熹注曰:“谖草,令人忘忧。”
②杜甫《佳人》:“天寒翠袖薄,日暮倚修竹。”
③张说《戏草树》:“戏问芭蕉叶,何愁心不开。”
</textarea>
<div style="text-align: center">(点击任意行或选中多行,然后按 alt+↑/↓ 上下移动行)</div>
<script>
ta.onkeydown = (e) => 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[0]是选中行第一行,ends[0]是选中行最后一行
for (let i = 0; i < ar.length; i ++) {
len += ar[i].length + 1;
// 基于 start 获取 begins 行索引
if (len > start) {
begins.push(i);
}
// 基于 end 获取 ends 行索引
if (len >= end) {
ends.push(i);
break;
}
}
// 根据 begins[0]、ends[0] 确定选中行上方、选中行、选中行下方行数组
s1 = ar.filter((item, key) => key < begins[0]);
s2 = ar.filter((item, key) => key >= begins[0] && key <= ends[0]);
s3 = ar.filter((item, key) => key > ends[0]);
// 如果按下的是 Alt+↑
if (event.key === 'ArrowUp') {
if (begins[0] === 0) return; // 选中行第一行是编辑器的第一行时退出操作
exchangeline = s1[s1.length - 1]; // 交换行是 s1 的最后一行
s1.pop(); // s1 删除最后一行元素
s3.unshift(exchangeline); // s3 接收交换行到第一行
// 如果按下的是 Alt + ↓
} else if(event.key === 'ArrowDown') {
if (ends[0] === ar.length - 1) return; // 选中行最后一行是编辑器最后一行时退出操作
exchangeline = s3[0]; // 交换行是 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;
}
</script>
核心在 moveLines() 函数中,里面的设计是将编辑器里的内容分成三部分:选中的行、选中行前边的行和后边的行,以数组方式存储并对之进行处理,最后整合为新的编辑器文本 Value 值。本方案去掉注释后代码量已经相当简洁,至少代码量比 AI 推荐的方法少很多。
|