===== 介绍 =====
Range标识了一定范围Document,DocumentFragment或Attr的内容。它是连续的,可以通过选择一对边界点内的内容描述。
并不是每一个Range都对应一个选择,而每一次选择都会返回一个Range。
Range接口提供了比DOM对节点操作更高层次的接口,当然这些最后都转化成了节点的操作,这意味着Range接口可以直接由节点操作完成。
===== 定义和表示 =====
==== 位置(Position) ====
文档的两种表达方式,包括标记的源码表示和DOM树结构表示。以下是与Position相关概念的定义。
Range是由边界点(boundary-point)组成的,而边界点由容器(container)和偏移(offset)定义。容器的父节点是边界点的父容器(ancestor container)。如果容器是Attr, Document, DocumentFragment, Element或EntityReference节点,那么偏移就在容器的子节点中。如果容器是CharacterData, Comment或ProcessingInstruction,那么偏移是容器中字符串间隙。
一个Range的两个边界点必须拥有相同的父容器,即是Document, DocumentFragment或Attr。共同的父容器称为Range的根容器(root container),包含Range根容器的DOM树称为Range的内容树(context tree)
边界点不能在标签内部。
{{:tech:rangeexample.gif?|}}
Range与容器和偏移相关的属性
readonly attribute Node startContainer;
readonly attribute long startOffset;
readonly attribute Node endContainer;
readonly attribute long endOffset;
==== 选择和部分选择(Selection and Partial Selection) ====
选择的内容可以包括连续节点或者是文本。
当节点被部分选择时,它仅仅是一个边界点的父容器。
==== 规范 ====
本文中document都是通过文本方式表示,通过粗体表示被Range选中的内容。
<FOO>A**BC<BAR>DEF**</BAR></FOO>
如果边界点重合,则使用^表示。
<FOO>A^BC<BAR>DEF</BAR></FOO>
===== 构建Range ====
Range可以通过DocumentRange的接口createRange创建。
interface DocumentRange {
Range createRange();
}
初始的Range两个边界点都指向文档的起始点。被特定文档创建的Range只能选择该文档的内容。
===== 重设位置 =====
Range提供以下接口重设边界点。
void setStart(in Node parent, in long offset)
raises(RangeException);
void setEnd(in Node parent, in long offset)
raises(RangeException);
下面方式可以通过相对位置重设边界点,此时容器成为了node的父节点。
void setStartBefore(in Node node);
raises(RangeException);
void setStartAfter(in Node node);
raises(RangeException);
void setEndBefore(in Node node);
raises(RangeException);
void setEndAfter(in Node node);
raises(RangeException);
以下方法可以设置Range在起始边界点还是在结束边界点collapse
void collapse(in boolean toStart);
以下属性检测Range是否发生collapse
readonly attribute boolean collapsed;
以下方法选定特定节点或其内容
void selectNode(in Node n);
void selectNodeContents(in Node n);
===== 比较边界点 =====
short compareBoundaryPoints(in CompareHow how, in Range sourceRange) raises(RangeException);
CompareHow只能是以下四个值
* START_TO_START
* START_TO_END
* END_TO_END
* END_TO_START
结果返回-1,0,1分别对应位置在前面,等于,后面
对于边界点位置的比较可能有几种情况
* 容器相同
* 它们的容器不在节点树同一个高度上,同时也不是包含关系
* 它们的容器在节点树上存在包含关系
针对不同情况,先后关系的比较有不同定义。同时需要注意的是,在文本表示的文档上具有相同位置的边界点,可能在节点树中有不同的含义。
===== 删除内容 =====
void deleteContents();
以下是示例
* <FOO>A**B<MOO>CD</MOO>**CD</FOO> ⇒ <FOO>A^CD</FOO>
* <FOO>A<MOO>B**C</MOO>D**E</FOO> ⇒ <FOO>A<MOO>B</MOO>^E</FOO>
* <FOO>X**Y<BAR>Z**W</BAR>Q</FOO> ⇒ <FOO>X^<BAR>W</BAR>Q</FOO>
* <FOO><BAR1>A**B</BAR1><BAR2/><BAR3>C**D</BAR3></FOO> ⇒ <FOO><BAR1>A</BAR1>^<BAR3>D</BAR3>
===== 提取内容 =====
DocumentFragment extractContents();
* <FOO>A**B<MOO>CD</MOO>**CD</FOO> --> B<MOO>CD</MOO>
* <FOO>A<MOO>B**C</MOO>D**E</FOO> --> <MOO>C<MOO>D
* <FOO>X**Y<BAR>Z**W</BAR>Q</FOO> --> Y<BAR>Z</BAR>
* <FOO><BAR1>A**B</BAR1><BAR2/><BAR3>C**D</BAR3></FOO> --> <BAR1>B</BAR1><BAR2/><BAR3>C</BAR3>
===== 复制内容 =====
DocumentFragment cloneContents();
===== 插入内容 =====
void insertNode(in Node n) raises(RangeException);
在text节点插入节点会导致text节点的分裂
===== 装饰内容 =====
void surroundContents(in Node newParent);
示例
Before:
<BAR>AB<MOO>C</MOO>DE</BAR>
After surroundContents(FOO):
<BAR>A<FOO>B<MOO>C</MOO>D</FOO>E</BAR>
当Range包含部分选择的非文本节点时,会产生异常
===== 其他成员 =====
克隆Range对象
Range cloneRange();
获得边界点的最近父容器
readonly attribute Node commonAncestorContainer;
获得选中对象的字符表示
DOMString toString();
===== 文档变化时Range的修改 =====
文档变化时Range所作的变化依照以下两个原则
* 所有的Range依然有效
* 尽可能选择相同的区域
事实上,伴随文档改变导致的Range改变可以看成是一系列的Range操作,包括插入和删除。
==== 插入 ====
仅当插入节点和边界点拥有相同容器并且偏移小于边界点偏移时,才产生Range边界点的修改
==== 删除 ====
详细见[[http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Deletions]]示例
===== 相关资料 =====
W3C DOM-Level-2-Traversal-Range ranges [[http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html]]
Range标识了一定范围Document,DocumentFragment或Attr的内容。它是连续的,可以通过选择一对边界点内的内容描述。
并不是每一个Range都对应一个选择,而每一次选择都会返回一个Range。
Range接口提供了比DOM对节点操作更高层次的接口,当然这些最后都转化成了节点的操作,这意味着Range接口可以直接由节点操作完成。
===== 定义和表示 =====
==== 位置(Position) ====
文档的两种表达方式,包括标记的源码表示和DOM树结构表示。以下是与Position相关概念的定义。
Range是由边界点(boundary-point)组成的,而边界点由容器(container)和偏移(offset)定义。容器的父节点是边界点的父容器(ancestor container)。如果容器是Attr, Document, DocumentFragment, Element或EntityReference节点,那么偏移就在容器的子节点中。如果容器是CharacterData, Comment或ProcessingInstruction,那么偏移是容器中字符串间隙。
一个Range的两个边界点必须拥有相同的父容器,即是Document, DocumentFragment或Attr。共同的父容器称为Range的根容器(root container),包含Range根容器的DOM树称为Range的内容树(context tree)
边界点不能在标签内部。
{{:tech:rangeexample.gif?|}}
Range与容器和偏移相关的属性
readonly attribute Node startContainer;
readonly attribute long startOffset;
readonly attribute Node endContainer;
readonly attribute long endOffset;
==== 选择和部分选择(Selection and Partial Selection) ====
选择的内容可以包括连续节点或者是文本。
当节点被部分选择时,它仅仅是一个边界点的父容器。
==== 规范 ====
本文中document都是通过文本方式表示,通过粗体表示被Range选中的内容。
<FOO>A**BC<BAR>DEF**</BAR></FOO>
如果边界点重合,则使用^表示。
<FOO>A^BC<BAR>DEF</BAR></FOO>
===== 构建Range ====
Range可以通过DocumentRange的接口createRange创建。
interface DocumentRange {
Range createRange();
}
初始的Range两个边界点都指向文档的起始点。被特定文档创建的Range只能选择该文档的内容。
===== 重设位置 =====
Range提供以下接口重设边界点。
void setStart(in Node parent, in long offset)
raises(RangeException);
void setEnd(in Node parent, in long offset)
raises(RangeException);
下面方式可以通过相对位置重设边界点,此时容器成为了node的父节点。
void setStartBefore(in Node node);
raises(RangeException);
void setStartAfter(in Node node);
raises(RangeException);
void setEndBefore(in Node node);
raises(RangeException);
void setEndAfter(in Node node);
raises(RangeException);
以下方法可以设置Range在起始边界点还是在结束边界点collapse
void collapse(in boolean toStart);
以下属性检测Range是否发生collapse
readonly attribute boolean collapsed;
以下方法选定特定节点或其内容
void selectNode(in Node n);
void selectNodeContents(in Node n);
===== 比较边界点 =====
short compareBoundaryPoints(in CompareHow how, in Range sourceRange) raises(RangeException);
CompareHow只能是以下四个值
* START_TO_START
* START_TO_END
* END_TO_END
* END_TO_START
结果返回-1,0,1分别对应位置在前面,等于,后面
对于边界点位置的比较可能有几种情况
* 容器相同
* 它们的容器不在节点树同一个高度上,同时也不是包含关系
* 它们的容器在节点树上存在包含关系
针对不同情况,先后关系的比较有不同定义。同时需要注意的是,在文本表示的文档上具有相同位置的边界点,可能在节点树中有不同的含义。
===== 删除内容 =====
void deleteContents();
以下是示例
* <FOO>A**B<MOO>CD</MOO>**CD</FOO> ⇒ <FOO>A^CD</FOO>
* <FOO>A<MOO>B**C</MOO>D**E</FOO> ⇒ <FOO>A<MOO>B</MOO>^E</FOO>
* <FOO>X**Y<BAR>Z**W</BAR>Q</FOO> ⇒ <FOO>X^<BAR>W</BAR>Q</FOO>
* <FOO><BAR1>A**B</BAR1><BAR2/><BAR3>C**D</BAR3></FOO> ⇒ <FOO><BAR1>A</BAR1>^<BAR3>D</BAR3>
===== 提取内容 =====
DocumentFragment extractContents();
* <FOO>A**B<MOO>CD</MOO>**CD</FOO> --> B<MOO>CD</MOO>
* <FOO>A<MOO>B**C</MOO>D**E</FOO> --> <MOO>C<MOO>D
* <FOO>X**Y<BAR>Z**W</BAR>Q</FOO> --> Y<BAR>Z</BAR>
* <FOO><BAR1>A**B</BAR1><BAR2/><BAR3>C**D</BAR3></FOO> --> <BAR1>B</BAR1><BAR2/><BAR3>C</BAR3>
===== 复制内容 =====
DocumentFragment cloneContents();
===== 插入内容 =====
void insertNode(in Node n) raises(RangeException);
在text节点插入节点会导致text节点的分裂
===== 装饰内容 =====
void surroundContents(in Node newParent);
示例
Before:
<BAR>AB<MOO>C</MOO>DE</BAR>
After surroundContents(FOO):
<BAR>A<FOO>B<MOO>C</MOO>D</FOO>E</BAR>
当Range包含部分选择的非文本节点时,会产生异常
===== 其他成员 =====
克隆Range对象
Range cloneRange();
获得边界点的最近父容器
readonly attribute Node commonAncestorContainer;
获得选中对象的字符表示
DOMString toString();
===== 文档变化时Range的修改 =====
文档变化时Range所作的变化依照以下两个原则
* 所有的Range依然有效
* 尽可能选择相同的区域
事实上,伴随文档改变导致的Range改变可以看成是一系列的Range操作,包括插入和删除。
==== 插入 ====
仅当插入节点和边界点拥有相同容器并且偏移小于边界点偏移时,才产生Range边界点的修改
==== 删除 ====
详细见[[http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Deletions]]示例
===== 相关资料 =====
W3C DOM-Level-2-Traversal-Range ranges [[http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html]]