登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  前端

JavaScript Range.compareBoundaryPoints 怎样比较两个范围的端点

来源:17golang原创

时间:2026-10-27 14:25:28 300浏览 收藏

Range.compareBoundaryPoints(how, otherRange) 用来比较两个范围的边界点,结果只有三类:当前范围的指定边界在对方边界之前返回 -1,相同返回 0,之后返回 1。真正容易出错的地方不是返回值,而是四个 how 常量的配对方向,尤其是 END_TO_START。

文档入口:https://developer.mozilla.org/en-US/docs/Web/API/Range/compareBoundaryPoints。下面用同一文本节点建立两个可读的范围,先得到一组稳定的比较基线,再说明偏移单位和适用边界。

要点速览
  • 比较方向始终是“当前 Range 对 otherRange”,不是把两个 Range 交换后再猜结果。
  • START_TO_END 比较当前范围的终点与对方范围的起点;常量名要和映射表一起看。
  • 这个方法只比较边界点,不能单独回答两个范围是否重叠或是否包含。

先把四种边界配对写成表

可以把调用理解成“从当前 Range 取一个端点,再从 otherRange 取一个端点”。返回值比较的是这两个端点在文档树中的顺序:

how 常量当前 Range 取值otherRange 取值适合表达的关系
START_TO_STARTstartstart两个范围从哪里开始
START_TO_ENDendstart当前范围末端与对方起点
END_TO_STARTstartend当前范围起点与对方末端
END_TO_ENDendend两个范围在哪里结束
JavaScript Range compareBoundaryPoints 四种常量对应起点终点的静态关系图
图1:Range 边界配对说明图,展示四种常量如何从当前范围和对方范围取起点或终点;这是静态结构图,不是浏览器截图。

表中最值得单独记住的是:常量名的前半段对应当前范围,后半段对应对方范围,但实际比较的端点名称遵循 DOM API 的固定映射,不能凭英文直觉交换。遇到复杂逻辑时,先在代码旁写出“当前端点 → 对方端点”,再调用方法。

用一个可复核的文本节点建立比较基线

下面的两个范围都来自字符串 0123456789。当前范围是 [1, 6),对方范围是 [1, 4);方括号表示包含起点、不包含终点,便于把偏移和字符位置对应起来。

const text = new Text("0123456789");

const currentRange = new Range();
currentRange.setStart(text, 1);
currentRange.setEnd(text, 6);

const otherRange = new Range();
otherRange.setStart(text, 1);
otherRange.setEnd(text, 4);

// 四次调用分别比较起点、交叉端点和终点
const results = {
  startToStart: currentRange.compareBoundaryPoints(
    Range.START_TO_START, otherRange
  ),
  startToEnd: currentRange.compareBoundaryPoints(
    Range.START_TO_END, otherRange
  ),
  endToStart: currentRange.compareBoundaryPoints(
    Range.END_TO_START, otherRange
  ),
  endToEnd: currentRange.compareBoundaryPoints(
    Range.END_TO_END, otherRange
  )
};

// 预期为 { startToStart: 0, startToEnd: 1,
//          endToStart: -1, endToEnd: 1 }
console.log(results);

这里 START_TO_START 返回 0,因为两个起点都在偏移 1;START_TO_END 实际比较当前范围终点 6 与对方起点 1,所以返回 1。END_TO_START 比较当前范围起点 1 与对方终点 4,因此返回 -1;最后两个终点是 6 和 4,返回 1。

返回值只说明边界顺序,不直接说明重叠

把返回值翻译成业务判断时,始终使用“当前端点相对于对方端点”的方向。-1 表示当前端点在前,0 表示两个端点相同,1 表示当前端点在后。它类似比较函数的返回约定,不应被理解成距离或重叠长度。

JavaScript Range 比较端点后得到 -1 0 1 的关系说明图
图2:比较结果说明图,把端点关系映射到 -1、0、1 三种结果;它表达的是静态关系,不是执行流程或运行截图。

例如两个范围完全分离时,当前范围的终点与对方范围的起点可以用 START_TO_END 观察;但一个可靠的“是否重叠”判断仍需要同时考虑两个范围的起止关系。只看一次比较,无法区分“包含”“被包含”和“部分相交”等情况。

偏移单位和使用边界要先核对

Range 的边界点由节点和偏移组成。对 Text 节点,偏移是文本节点内部的位置;对元素节点,偏移表示子节点序号。不能把一个页面全局字符下标直接当成任意节点的 offset,也不要把 children.length 当作 childNodes.length。

function compareRanges(currentRange, otherRange, how) {
  if (!(currentRange instanceof Range) || !(otherRange instanceof Range)) {
    // 先拒绝不属于当前文档模型的输入,避免错误藏在比较结果里
    throw new TypeError("两个参数都必须是 Range");
  }
  if (![Range.START_TO_START, Range.START_TO_END,
        Range.END_TO_START, Range.END_TO_END].includes(how)) {
    // how 不是四个常量之一时,浏览器会抛出 NotSupportedError
    throw new TypeError("how 必须是 Range 的比较常量");
  }
  return currentRange.compareBoundaryPoints(how, otherRange);
}

这个封装只做参数边界说明,不会把返回值改成布尔值,因为调用方还需要知道“前、同、后”。如果目标是 input 或 textarea 内的选区,应使用控件自己的选择接口;如果 DOM 被框架重渲染,旧节点和旧 offset 也可能失效,不能把一次 Range 比较结果当成长期书签。

写判断代码时的检查清单

  • 先写清楚当前 Range 和 otherRange,不要在调用前后交换变量。
  • 把 how 展开成“当前端点 → 对方端点”,尤其检查 START_TO_END 和 END_TO_START。
  • 比较前确认两个 Range 的节点和 offset 仍然来自有效的 DOM 状态。
  • 需要判断重叠、包含或相邻时,同时检查起点和终点,不用单次返回值替代完整关系判断。

常见问题

返回 0 是不是代表两个 Range 完全相同?

不是。它只代表本次选择的两个边界点相同,例如两个范围的起点相同;终点、包含关系和范围长度仍可能不同。

为什么 END_TO_START 的直觉容易反?

因为 API 的映射固定为当前范围起点对比对方范围终点。把常量名直接当成“当前终点对方起点”会把这一次比较写反,应该以四行对照表为准。

compareBoundaryPoints 能替代重叠检测吗?

不能。它提供端点排序原语;重叠检测还要结合两组起止边界,并考虑范围相邻、包含和折叠等情况。

参考资料:https://developer.mozilla.org/en-US/docs/Web/API/Range/compareBoundaryPoints;方法语义以 DOM Range 规范为准。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>