当前位置:首页 > 文章列表 > 文章 > 前端 > JavaScript Selection.setBaseAndExtent 怎样设置带方向的文本选区

JavaScript Selection.setBaseAndExtent 怎样设置带方向的文本选区

来源:17golang原创 2026-10-27 14:19:30 0浏览 收藏

Selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset) 用两组边界点设置选区。第一组是锚点,第二组是焦点;焦点在文档顺序中位于锚点之前时,得到反向选区。要保留方向,就不能先把这两组参数按大小重新排序。

文档入口:https://developer.mozilla.org/en-US/docs/Web/API/Selection/setBaseAndExtent。下面用同一文本节点说明 API 语义,再讨论恢复选区的边界。这是既有 Web API 的用法解析,不是新的语言提案;示例按文档编写,未在本文环境执行。

用最小例子建立反向选区

在已有页面上添加一个文本容器和按钮。通过按钮触发设置,避免页面初始化时无条件抢占用户选区:


red green blue

// 在上方HTML之后运行,保证元素已存在
const text = document.getElementById("sample").firstChild;
const button = document.getElementById("select-word");
button.addEventListener("click", () => {
  const selection = window.getSelection();
  if (!selection || typeof selection.setBaseAndExtent !== "function") {
    // 由产品提供不支持方向恢复时的提示
    return;
  }
  // green占据[4, 9),锚点在词尾,焦点在词首
  selection.setBaseAndExtent(text, 9, text, 4);
});

这里的字符串位置可由原文直接推导:red 后有一个空格,green 从偏移4开始、在偏移9之前结束。交换为 (text, 4, text, 9) 会覆盖相同文字,但锚点和焦点角色不同。不要把“选中文字相同”当成“选区状态完全相同”。

分清锚点焦点与范围起止

anchor 表达选择的基点,focus 表达另一端。Range 的 start 与 end 则按文档顺序组织,反向选择并不意味着 start 大于 end。因此,只保存 getRangeAt(0) 的起止位置,并不能完整保存锚点与焦点的角色。

Selection锚点焦点与Range起点终点在反向选择中的关系
原创静态结构图:反向选择中anchor对应范围较后端,focus对应较前端;图中连线说明角色关系,不是脚本执行流程。

方向描述的是文档边界顺序,不等同于屏幕上的左右方向。包含双向文字或复杂布局时,更不能仅凭视觉上的“向左拖动”推断 DOM 端点。本文例子限于普通文档中的单一文本节点。

按节点类型计算偏移

Text 节点的偏移按 UTF-16 代码单元计数;Element 节点的偏移按子节点位置计数。空白文本节点也属于子节点,所以 children 的长度不能直接当作 childNodes 的长度使用。跨元素选择时,每一端都必须有自己的节点和该节点内偏移。

// 示例只接受明确的Text节点,避免把元素偏移误当字符偏移
function selectTextPart(textNode, anchor, focus) {
  if (!textNode || textNode.nodeType !== Node.TEXT_NODE) {
    throw new TypeError("需要文本节点");
  }
  for (const offset of [anchor, focus]) {
    // 先限制输入为非负整数,再检查节点内上界
    if (!Number.isInteger(offset) || offset  textNode.length) {
      throw new RangeError("偏移超出文本节点范围");
    }
  }
  if (!textNode.isConnected || textNode.ownerDocument !== document) {
    throw new Error("节点必须位于当前文档");
  }
  const selection = window.getSelection();
  if (!selection || typeof selection.setBaseAndExtent !== "function") {
    return false; // 将不支持情况交给调用方处理
  }
  selection.setBaseAndExtent(textNode, anchor, textNode, focus);
  return true;
}

这段封装有意只处理当前文档内的文本节点,不是可覆盖 Shadow DOM 或所有编辑器模型的通用库。不要把后端的字节偏移直接传进来;emoji 也可能占据两个代码单元,组合字符还可能由多个代码点构成。面向用户字符的索引需要先映射到文本节点偏移。

Text节点代码单元偏移与Element子节点偏移的不同计数边界
原创静态结构图:两种节点有不同偏移单位,anchorOffset与focusOffset均依附各自节点,不能共享一套页面全局字符索引。

保存方向时保留两端角色

旧写法常把范围起止当成选区全部状态。对于需要恢复用户选择方向的编辑工具,可以先保存 anchorNode、anchorOffset、focusNode、focusOffset,再在节点仍然有效时调用 setBaseAndExtent。调用会替换当前选择范围,无须为了这一次设置先 removeAllRanges。

// 只适用于DOM节点身份与文本内容都未改变的短期保存
function captureSelection() {
  const s = window.getSelection();
  if (!s || s.rangeCount === 0 || !s.anchorNode || !s.focusNode) return null;
  return {
    anchorNode: s.anchorNode, anchorOffset: s.anchorOffset,
    focusNode: s.focusNode, focusOffset: s.focusOffset
  };
}
// 在受控DOM更新后,应先重建有效端点,不能盲用旧节点引用
function restoreSelection(saved) {
  const s = window.getSelection();
  if (!saved || !s || typeof s.setBaseAndExtent !== "function") return false;
  if (!saved.anchorNode.isConnected || !saved.focusNode.isConnected) return false;
  try {
    s.setBaseAndExtent(
      saved.anchorNode, saved.anchorOffset,
      saved.focusNode, saved.focusOffset
    );
    return s.anchorNode === saved.anchorNode &&
      s.anchorOffset === saved.anchorOffset &&
      s.focusNode === saved.focusNode && s.focusOffset === saved.focusOffset;
  } catch (error) {
    if (error.name === "IndexSizeError") return false; // 文本缩短导致偏移失效
    throw error;
  }
}

框架重渲染可能替换节点;即便节点没换,文本内容变化也会改变原偏移代表的位置。长期书签应使用编辑器自己的稳定位置模型,并映射回当前 DOM;单纯 JSON 序列化节点引用不能完成这件事。

处理兼容与常见边界

目标合适方式容易忽略的点
普通文档中恢复两端角色setBaseAndExtent不要先排序anchor和focus
只处理文档中的覆盖范围Range边界范围起止不完整表达选择方向
文本输入框内选区setSelectionRange使用控件value的索引

input 与 textarea 应使用各自的文本选择接口。例如 text 类型输入框可以调用 setSelectionRange(start, end, "backward"),并按交互需要让控件获得焦点。不要把输入框的 value 当成可直接选择的子 Text 节点。

偏移超出节点长度会自动截断吗?

不要依赖截断。setBaseAndExtent 的越界偏移会触发 IndexSizeError,封装应提前明确输入范围。

两端相同会报错吗?

同一边界点表示折叠选区,即插入位置;它不包含一段被选中的文字。

接口存在就能覆盖所有编辑器吗?

不能。普通文档、表单控件、嵌套文档和 Shadow DOM 的处理边界不同,特性检测只说明方法存在,不能替代应用自己的节点映射。

参考:MDN方法参考、Selection API规范草案、输入控件选区接口。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Linux systemd.timer FixedRandomDelay 怎样保持随机延迟的稳定性Linux systemd.timer FixedRandomDelay 怎样保持随机延迟的稳定性
上一篇
Linux systemd.timer FixedRandomDelay 怎样保持随机延迟的稳定性
JavaScript Selection.containsNode 怎样判断节点是否处于选区内
下一篇
JavaScript Selection.containsNode 怎样判断节点是否处于选区内
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    734次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    736次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    815次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    776次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    611次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码