HOME
NAVIGATION

DOM2范围(1)

☞dom2、3相关合集

0.范围

DOM2级在Document类型中定义了createRange()方法

var support = document.implementation.hasFeature("Range","2.0"); var alsoSupport = typeof document.createRange === "function";//书上写的是var alsoSupport = (typeof document.createRange == "function")

测试一下浏览器是否兼容,除了IE8及以下以外,alert一下都返回true,IE有自己实现的方法,之后写小玩意儿用到了再说

1.创建范围

var range1 = document.createRange();

与节点类似,新创建的范围也直接和创建它的文档关联在一起,不能用于其他文档。

每个范围由一个Range类型的实例表示,这个实例拥有许多方法和属性,以下属性提供了当前范围在文档中的位置信息。

startContainer:

startContainer:包含范围起点的节点(即选区中第一个节点的父节点)。

startOffset:

startOffset:范围在startContainer中起点的偏移量。如果startContainer是文本节点、注释节点或CDATA节点,那么startOffset就是范围起点之前跳过的字符数量。否则,startOffset就是范围中第一个子节点的索引(注意索引是从0开始算的)。

endContainer:

endContainer:包含范围终点的节点(即选区中最后一个节点的父节点)。

endOffset:

endOffset: 范围在endContainer中终点的偏移量。(与startOffset遵循同样的取值规则)。

commonAncestorContainer:

commonAncestorContainer:startContainer和endContainer共同的祖先节点在文档树种位置最深的那个。(p是深,body是浅)

2.用DOM范围实现简单选择

要使用范围来选择文档的一部分,最简单的方法就是使用selectNode()或selectNodeContents()。 这两个方法都接受一个参数,即一个DOM节点,然后使用该节点中的信息来填充范围。

selectNode()

selectNode()选择整个节点,包括其子节点。

selectNodeContexts()

selectNodeContexts()方法,只选择节点的子节点

一个小例子

html

<\body>
<\p id="p1"><\b>Hello<\/b> world!<\/p>
<\/body>

js

var range1 = document.createRange();
var range2 = document.createRange();
var p1 = document.getElementById("p1");
var r1 = range1.selectNode(p1);
var r2 = range2.selectNodeContents(p1);

range1包含了P元素及其所有的子元素,而range2包括了b元素及其子节点(Hello)以及文本节点world!。

在调用selectNode()时,startContainer,endContainer ,commonAncestorContainer:startContainer都等于传入节点的父节点, 也就是整个例子中的document.body, 而startOffset属性等于给定节点在其父节点childNodes集合中的索引(在和这个例子中是1,因为空格节点也是文本节点,它是0索引,所以p节点就是1索引), endOffset等于startOffset加1(这是书上写的,个人理解,可以把endOffset的值理解为子节点的数量,那么一个空格文本节点+一个p节点就是2了)

在调用selectNodeContents()时,startContainer,endContainer ,commonAncestorContainer:startContainer都等于传入节点的父节点, 也就是整个例子中的p元素,而startOffset属性始终等于0,因为b元素是p元素的第一个子节点,索引为0。 endOffset等于子节点的数量(node.childNodes.length),在这个例子中是2(一个元素节点b,一个文本节点world!,Hello是个孙元素,不算的)

alert(range1.startOffset);//1
alert(range1.endOffset)//2
alert(range2.startOffset);//0
alert(range2.endOffset)//2

注意!有startOffset等等属性的是range,不是range.selectNode()

为了更精确的控制将哪些节点包含在范围中,还可以使用下列方法。

setStartBefore(refNode):

setStartBefore(refNode):将范围的起点设置在refNode之前,因此refNode也就是范围选区中的第一个子节点。同时会将startContainer属性设置为refNode.prentNode,将startOffset属性设置为refNode在其父节点的childNodes集合中的索引。

setStartAfter(refNode):

setStartAfter(refNode): 将范围的起点设置在refNode之后,因此refNode也就不在范围之内了,其下一个同辈节点才是范围选区中的第一个子节点。同时会将startContainer属性设置为refNode.prentNode,将startOffset属性设置为refNode在其父节点的childNodes集合中的索引加1。(因为第一个节点的索引是refNode的索引+1)。

setEndBefore(refNode):

setEndBefore(refNode):将范围的终点设置在refNode之前,因此refNode也就不在范围内了,上一个同辈节点才是范围选取中的最后一个子节点。同时会将endContainer属性设置为refNode.prentNode,将endOffset属性设置为refNode在其父节点的childNodes集合中的索引。

setEndAfter(refNode):

setEndAfter(refNode):将范围的终点设置在refNode之前,因此refNode也就是范围选区中的最后一个子节点。同时会将endContainer属性设置为refNode.prentNode,将endOffset属性设置为refNode在其父节点的childNodes集合中的索引加1(记成子元素的数量也可以)。

一些测试,和之前学的selectNode()以及selectNodeContexts()方法联合起来用

html(注意有很多换行符,这在dom中是算作文本节点的)

<\div id="outer">
<\p id="outerP">outer paragraph<\/p>
<\/div>
<\div id="inner">
<\p id="p0">inner paragraph<\/p>
<\p id="p1">some paragraphs Hello world!<\/p>
<\/div>

js

var range1 = document.createRange();
var p1 = document.getElementById("p1");
var p0 = document.getElementById("p0");
var b = document.getElementById("b")
var pOuter = document.getElementById("pOuter");
alert(range1);//啥都没有
range1.selectNode(p1);
alert(range1);//some paragraphs Hello world!
alert(range1.startContainer);//[object HTMLDivElement]
range1.setStartBefore(b);
alert(range1.startContainer);//[object HTMLParagraphElement]
alert(range1.endContainer);//[object HTMLDivElement]
alert(range1);//Hello world!
range1.setStartAfter(b);
alert(range1.startContainer)//[object HTMLParagraphElement]亲测就算把world!这个文本节点删除了,还是返回一样的结果,原因setStartAfter的介绍说明了。
alert(b.nextSibling);//[object Text],删除world!显示null
alert(range1);//world!亲测如果把world!这个文本节点删除了,就什么都不alert了。
range1.setStartBefore(p1);
alert(range1.startContainer);//[object HTMLDivElement]
alert(range1)//some paragraphs Hello world!
range1.setEndAfter(p1);
alert(range1.endOffset)// 4。 因为有很多个空格算作文本节点,所以是4;如果把换行都删除,则是2,是父元素div的子节点数量。
range1.setStartBefore(pOuter);
alert(range1.startContainer)// Argument 1 of Range.setStartBefore is not an object.

单独使用这几个方法的测试

var range1 = document.createRange();
var p1 = document.getElementById("p1");
var p0 = document.getElementById("p0");
var b = document.getElementById("b")
var pOuter = document.getElementById("pOuter");
range1.setStartBefore(p1);
range1.setEndBefore(p1);
alert(range1);//alert空
range1.setEndAfter(p1);
alert(range1);//some paragraphs Hello world!
alert(range1.endOffset);//4。 因为有很多个换行符也被dom算作文本节点,所以是4;如果把换行都删除,则是2,是父元素div的子节点数量。
alert(range1.startOffset)//3。因为算上换行符和第一个文本节点,所以是3,如果把换行符都删除,则是1(第一个p0子节点是索引0,p1是索引1)