本文是W3C Selection Api的阅读笔记。

一个文档可以带有一个全局共享的选段(selection)。一个选段可以关联有一个范围(range),如果范围为空,则选段为空。初始的时候选段都是为空。

如果选段范围为空,且范围是闭合的(collapsed),则光标就是在范围边界上。

选段可以有方法:前向(forwards)、后向(backwards),也可以没有方向(directionless)。前向意味着用户用光标选择范围的时候,开头位置在结束位置的前面;后向意味着开头位置在结束位置的后面。一般情况下,从左到右选是前向,反之后向。

选段有一个锚点(anchor)和一个焦点(focus)。如果选段范围为空,那么这两者都为空。否则的话,对于前向选择而言,开头为锚点,结尾为焦点;后向选择开头为焦点,结尾为锚点。

用户代理(浏览器)必须根据用户的行为来将选段设置成合适的结果。用户代理不能主动清楚选段(比如点击了不可编辑的区域)。

为什么要区分选段和范围,而不是将范围的属性直接纳入选段?我的思考是选段是document的属性,而范围是文档上层对象的属性。范围不属于文档,文档直接添加到范围的引用。范围可以通过document.createRange()创建

Selection接口

Selection的WebIDL描述:

[Exposed=Window]
interface Selection {
  readonly attribute Node? anchorNode;
  readonly attribute unsigned long anchorOffset;
  readonly attribute Node? focusNode;
  readonly attribute unsigned long focusOffset;
  readonly attribute boolean isCollapsed;
  readonly attribute unsigned long rangeCount;
  readonly attribute DOMString type;
  Range getRangeAt(unsigned long index);
  void addRange(Range range);
  void removeRange(Range range);
  void removeAllRanges();
  void empty();
  void collapse(Node? node, optional unsigned long offset = 0);
  void setPosition(Node? node, optional unsigned long offset = 0);
  void collapseToStart();
  void collapseToEnd();
  void extend(Node node, optional unsigned long offset = 0);
  void setBaseAndExtent(Node anchorNode, unsigned long anchorOffset, Node focusNode, unsigned long focusOffset);
  void selectAllChildren(Node node);
  [CEReactions]
  void deleteFromDocument();
  boolean containsNode(Node node, optional boolean allowPartialContainment = false);
  stringifier DOMString ();
};

其中:

  • anchorNode和anchorOffset定义了范围锚点的Boundary points
  • focusNode和focusOffset定义了范围焦点的Boundary points
  • isCollapsed用来说明范围是否闭合(锚点和焦点在一个位置,或者两者都为空)
  • rangeCount,0表示无范围(可能是文档还没有关联上层对象),1表示有范围。
  • type,文档还没有关联上层对象的时候为“none”,“Caret”表示选段范围闭合,其他情况下为“Range”
  • getRangeAt(),返回选段范围,其参数index必须为0
  • addRange(),添加文档的选段范围,必须在没有rangeCount为0的时候才可以
  • removeRange(),删除范围,rangeCount变为0
  • removeAllRanges(),删除所有范围
  • empty,和removeAllRanges()等效
  • collapse() ,闭合范围到参数指定到节点上
  • setPosition() ,和collapse()等效
  • collapseToStart() ,闭合到开始位置
  • collapseToEnd(),闭合到结束位置
  • extend(),扩展范围
  • setBaseAndExtent(),双头扩展范围
  • selectAllChildren() ,以某个节点的所有节点做范围
  • deleteFromDocument() ,将范围之内的文档删除
  • containsNode(),判断某节点是否在范围之内

对其他接口的扩展

partial interface Document {
  Selection? getSelection();
};

partial interface Window {
  Selection? getSelection();
};

partial interface mixin GlobalEventHandlers {
  attribute EventHandler onselectstart;
  attribute EventHandler onselectionchange;
};
  • document.getSelection()返回当前选段
  • window.getSelection()返回当前选段
  • 增加selectstart事件和相应的处理器onselectstart
    • 如果当前选段为空,或者选段为闭合状态,当用户代理准备更新选段的范围时,必须触发selectstart事件(可回溯并可以取消),事件目标设置在新范围的开始位置所在的节点。
    • 如果selectstart被撤销时,用户代理不能修改既有选段。
    • 当selection被设为空时,用户代理不需要触发此事件。
  • 增加selectionchange事件和相应的处理器onselectionchange
    • 当需要替换当前选段的范围时,用户代理必须放置一个selectionchange事件在事件队列中。
    • 此事件目标是document,且不可回溯不可撤销

(完)