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

如何从Slate.js编辑器中获取不受文档结构影响的绝对文本选区

解决Slate.js中不受文档结构影响的选区位置计算问题

我用React和TypeScript实现基于Slate.js的协作文本编辑器,需要获取用户修改样式的精确文本选区,自定义的选区类型定义如下:

type Cursor = {
  line: number;
  column: number;
};

type Selection = {
  start: Cursor;
  end: Cursor;
};

当前实现受Slate文档树结构(文本样式)影响,无法获取不受结构影响的选区,且列数计算错误。现有代码:

function getSelection(editor: Editor): Selection {
  const { selection } = editor;
  if (!selection) {
    return {
      start: { line: 0, column: 0 },
      end: { line: 0, column: 0 },
    };
  }
  const [start, end] = Range.edges(selection);
  return {
    start: pointToCursor(start),
    end: pointToCursor(end),
  };
}

function pointToCursor(point: Point): Cursor {
  return {
    line: point.path[0],
    column: point.offset, // 错误:offset是当前文本节点内的偏移,不是整行累计偏移
  };
}

问题示例

  • 当整行是单一文本节点abcdef,选中def时,返回列数[0, 3],不符合预期的[3, 6]
  • 当abc和def分属不同样式的文本节点时,返回列数[3, 6],符合预期

解决方案

核心是计算整行的累计文本长度,而非仅当前文本节点内的偏移。修改pointToCursor函数,遍历当前行的所有前置文本节点,累加长度后加上当前节点的offset,得到全局列数:

import { Editor, Point, Node, Text } from 'slate';

function pointToCursor(editor: Editor, point: Point): Cursor {
  const lineIndex = point.path[0];
  // 获取当前行节点
  const lineNode = Node.get(editor, [lineIndex]) as any;
  let totalOffset = 0;
  const currentTextNodeIndex = point.path[1];

  // 遍历当前行的所有子节点,累加前置文本节点的长度
  for (let i = 0; i < currentTextNodeIndex; i++) {
    const child = lineNode.children[i];
    if (Text.isText(child)) {
      totalOffset += child.text.length;
    }
  }

  // 加上当前文本节点内的偏移,得到整行的列数
  return {
    line: lineIndex,
    column: totalOffset + point.offset,
  };
}

// 同时更新getSelection函数,传入editor到pointToCursor
function getSelection(editor: Editor): Selection {
  const { selection } = editor;
  if (!selection) {
    return {
      start: { line: 0, column: 0 },
      end: { line: 0, column: 0 },
    };
  }
  const [start, end] = Range.edges(selection);
  return {
    start: pointToCursor(editor, start),
    end: pointToCursor(editor, end),
  };
}

说明

  1. 通过Node.get获取当前行节点,确保拿到完整的行内容
  2. 遍历当前文本节点之前的所有子节点,累加文本长度(只处理Text类型节点)
  3. 将累计长度与当前Point的offset相加,得到不受文档结构影响的全局列数
  4. 无论一行是单一文本节点还是多个样式节点,都能返回正确的整行列数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:52:47