HOME
NAVIGATION

DOM2范围(3)——复杂选择、操作

☞dom2、3相关合集

0.用DOM范围实现复杂选择

setStart()和setEnd()

要创建复杂的范围就得使用setStart()和setEnd()方法。这两个方法都接受两个参数:一个参照节点和一个偏移量值。

对setStart()来说,参照节点会变成startContainer。 而偏移量值会变成startoffset。对于setEnd()来说,参照节点会变成endContainer,而偏移量值会变成endOffset。 可以使用这两个方法来模仿selectNode()和selectNodeContents(),但是这没意义,它的强大之处在于能够选择节点的一部分。

var range1 = document.createRange();
var p1 = document.getElementById("p1");
var b = p1.children[0];
var span = p1.children[1];
range1.setStart(b.firstChild,1);
range1.setEnd(span.firstChild,5);
alert(range1);//ello worl

具体关于为什么最后range1显示ello worl,我在上一篇的博客中已经写了详细的原因

☞此处应有链接

1.操作DOM范围中的内容

在创建范围时,内部会为这个范围创建一个文档片段,范围所属的全部节点都被添加到了这个文档片段中。

为了创建这个文档片段,范围内容的格式必须正确有效。 在前面的例子中,创建的选区分别开始和结束于两个文本节点的内部,因此不能算是格式良好的DOM结构,也就无法通过DOM来表示。 但是,范围知道自身缺少哪些开标签和闭标签,它能够重新构建有效的DOM结构以便对其进行操作.

对于前面的例子而言,范围经过计算知道选区中缺少一个开始的<\b>标签,因此就会在后台动态加入一个该标签, 同时还会在前面加入一个表示结束的<\/b>标签以结束"H"。于是,修改后的DOM就变成了如下所示

<\b>ello<\/b><\span> worl<\/span>

像这样创建了范围之后,就可以使用各种方法对范围的内容进行操作了 (注意!!!表示范围的内部片段中的所有节点,都只是指向文档中相应节点的指针!)。

deleteContents()方法

从文档中删除范围所包含的内容。

var range1 = document.createRange();
var p1 = document.getElementById("p1");
var b = p1.children[0];
var span = p1.children[1];
range1.setStart(b.firstChild,1);
range1.setEnd(span.firstChild,5);
alert(range1);//ello worlv range1.deleteContents();// hd!

HTML代码显示

<\b>H<\/b><\span>d!<\/span>

由于范围选取在修改底层DOM结构时能够保证格式良好,因此即使内容被删除了,最终的DOM结构依旧是格式良好的。

extractContents()方法

和deleteContents()方法相似,也会从文档中移除范围选取,但是extractContents方法会返回范围的文档片段。 利用这个返回的值,可以将范围的内容插入到文档中的其他地方。

var fragment = range1.extractContents();
p1.parentNode.appendChild(fragment);
//hd!
//ello worl

cloneContents()

cloneContents()创建范围对象的一个副本,然后再文档的其他地方插入该副本。 cloneContents()返回的文档片段包含的是范围中节点的副本,而不是实际的节点.

var fragment = range1.cloneContents();
p1.parentNode.appendChild(fragment);
//hello world!
//ello worl

PS:在将文档片段传入appendChild()方法中时,添加到文档中的只是片段的子节点,而非片段本身。

注意!在调用上面介绍的方法之前,拆分的节点并不会产生格式良好的文档片段。换句话说,原始的HTML在DOM被修改之前会始终保持不变。

个人理解

就是在使用这些方法之前,HTML还是完整的,像这样

<\b>hello<\/b><\span> world!<\/span>

而不会变成

<\b>he<\/b><\b>llo<\/b><\span> world!<\/span>

2.插入DOM范围中的内容

insertNode()方法

向范围选区的开始处插入一个节点

惯例写一个小例子

var range1 = document.createRange();
var p1 = document.getElementById("p1");
var b = p1.children[0];
var span = p1.children[1];
range1.setStart(b.firstChild,1);
range1.setEnd(span.firstChild,5);
var sp = document.createElement("span");
sp.style.color = "red";
sp.appendChild(document.createTextNode("Inserted text"));
range1.insertNode(sp);

效果

hInserted textello world!

HTML代码显示:

<\p id="p1"><\b>h<\span style="color: red;">Inserted text<\/span>ello<\/b><\span> world!<\/span><\/p>

注意:"span"元素正好被插入到了h之后,而被拆分的hello并没有多出一对b元素来, 是因为这里没有使用我之前说的(小标题1.操作DOM范围中的内容)那些方法。

surroundContents()方法

环绕范围插入内容,这个方法接受一个参数,即环绕范围内容的节点。

  • 提取出范围中的内容(类似于执行extractContent());
  • 将给定节点插入到文档中原来范围所在的位置上;
  • 将文档片段的内容添加到给定节点中.

例子

var range1 = document.createRange();
var p1 = document.getElementById("p1");
var b = p1.children[0];
var span = p1.children[1];
range1.setStart(b.firstChild,1);
range1.setEnd(b.firstChild,4);
var sp = document.createElement("span");
sp.style.color = "red";
range1.surroundContents(sp);

效果

hello world!

HTML显示:

<\p id="p1"><\b>h<\span style="color: red;">ell<\span>o<\/b><\span> world!<\/span><\/p>

书上说:为了插入span,范围必须包含整个DOM选区(不能仅仅包含选中的DOM节点)

并不明白这句话的意思,那就试一下呗。

经过测试,整个方法不能跨标签使用,也就是说,如果我这么写代码

range1.setStart(b.firstChild,1);
range1.setEnd(span.firstChild,4);

马上就能美滋滋的获得一个报错!

InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable

然后百度了一下,说是这个方法和selectNode()方法更配!

但是测试下来就算不是一个完整的标签也可以用这个surroundContents()方法呀!美滋滋的实践出真知,只是不能跨标签,可惜了。