You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在jQuery Terminal中获取DOM文本选区的起始与结束索引?

jQuery Terminal 选区索引API实现方案

实现思路

基于你提供的DOM结构特点实现:

  • 提示符统一在.cmd-prompt节点下,用户输入内容拆分到两个节点:历史输入行存放在.cmd-end-line,当前输入行存放在.cmd-cursor-line
  • 所有可渲染字符都挂载了data-text属性,直接读取该属性即可拿到原始字符,无需处理HTML实体转义问题

核心实现代码

function getTerminalSelection() {
  const cmdEl = document.querySelector('.cmd');
  const selection = window.getSelection();
  // 无选中内容直接返回
  if (!selection.rangeCount) return null;

  const range = selection.getRangeAt(0);
  // 选区不在终端命令区域内直接返回
  if (!cmdEl.contains(range.commonAncestorContainer)) return null;

  // 计算提示符总长度,用户输入偏移需要扣除该值
  const promptEl = cmdEl.querySelector('.cmd-prompt');
  const promptLength = Array.from(promptEl.querySelectorAll('[data-text]'))
    .reduce((len, node) => len + node.dataset.text.length, 0);

  // 按顺序收集所有用户输入字符节点,包含换行符
  const inputNodes = [];
  // 上一行输入内容
  const endLine = cmdEl.querySelector('.cmd-end-line');
  inputNodes.push(...Array.from(endLine.querySelectorAll('[data-text]')));
  // 插入换行符虚拟节点,匹配实际输入的换行
  inputNodes.push({ dataset: { text: '\n' } });
  // 当前行输入内容
  const cursorLine = cmdEl.querySelector('.cmd-cursor-line');
  inputNodes.push(...Array.from(cursorLine.querySelectorAll('[data-text]')));

  // 计算选中位置相对于用户输入开头的偏移
  function calculateOffset(node, offsetInNode) {
    // 查找当前节点对应的带data-text属性的父节点
    let targetNode = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
    while (targetNode && !targetNode.dataset?.text) {
      targetNode = targetNode.parentElement;
    }
    // 选中位置在提示符区域
    if (promptEl.contains(targetNode)) {
      return Math.max(0, offsetInNode - promptLength);
    }
    // 累计计算输入区域的偏移
    let totalOffset = 0;
    for (const n of inputNodes) {
      if (n === targetNode) {
        totalOffset += offsetInNode;
        break;
      }
      totalOffset += n.dataset.text.length;
    }
    // 边界处理:偏移不小于0,不超过输入总长度
    const maxInputLength = inputNodes.reduce((len, n) => len + n.dataset.text.length, 0);
    return Math.min(Math.max(0, totalOffset), maxInputLength);
  }

  let startOffset = calculateOffset(range.startContainer, range.startOffset);
  let endOffset = calculateOffset(range.endContainer, range.endOffset);

  // 处理反选情况,保证返回的索引从小到大
  if (startOffset > endOffset) {
    [startOffset, endOffset] = [endOffset, startOffset];
  }

  // 选区完全在提示符区域返回null,也可根据需求改为返回[0, 0]
  return startOffset === 0 && endOffset === 0 ? null : [startOffset, endOffset];
}

规则匹配说明

  • 规则1:选中> He|lo wor|d时,提示符长度为2,计算后起始偏移为2,结束偏移为8,返回[2, 8]
  • 规则2:选区左端点在提示符区域时,起始偏移自动取0,右端点超出输入长度时自动截断为最大输入长度,符合[0, 5]的输出要求
  • 规则3:选区完全位于提示符区域时,计算后起止偏移均为0,返回null,可自行修改为返回[0, 0]

内容的提问来源于stack exchange,提问作者jcubic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 09:00:00