资讯专栏INFORMATION COLUMN

JavaScript DOM2和DOM3——“范围”的注意要点

happyhuangjinjin / 480人阅读

摘要:级遍历和范围模块定义了范围接口。折叠范围方法折叠就是指范围中未选择文档的任何部分。表示折叠到范围的起点,参数表示折叠到范围的终点。常量指定比较当前范围的点和指定范围的点。下节再讨论及更早版本中的范围

“DOM2级遍历和范围”模块定义了“范围”接口。通过范围可以选择文档中的一个区域,而不必考虑节点的界限(选择在后台完成,对用户是不可见的)。

DOM中的范围

DOM2级在Document类型中定义了createRange()方法,可以用来创建DOM范围,如下所示:

var range = document.createRange();

每个范围由一个Range类型的实例表示,这个实例有很多属性和方法:

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

startOffset:范围在startContainer中起点的偏移量;

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

endOffset:范围在endContainer中终点的偏移量;

commonAncestorContainer:startContainer和endContainer共同的祖先节点在文档树中位置最深的那个;

用DOM范围实现简单选择 selectNode()selectNodeContents()

前者选择整个节点,包括子节点;后者选择节点的子节点。如:


    

Hello world!

在调用selectNode()时,startContainer、endContainer和commonAncestorContainer等都等于传入节点的父节点,也就是其中的document.body。而startOffset属性等于给定节点在其父节点的childNodes集合中的索引。endOffset等于startOffset加上1;

在调用selectNodeContents()时,startContainer、endContainer和commonAncestorContainer等于传入的节点。而startOffset属性始终等于0.最后,endOffset等于子节点的数量(node.childNodes.length);

更精细的选择

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

setStartBefore(refNode):将范围的起点设置在refNode之前;

setStartAfter(refNode):将范围的起点设置在refNode之后;

setEndBefore(refNode):将范围的终点设置在refNode之前;

setEndAfter(refNode):将范围的终点设置在refNode之后;

如下html:

Hello world!

hello

js:

var range1 = document.createRange(),
    range2 = document.createRange(),
    p1 = document.getElementById("p1");
range1.selectNode(p1);
range1.setStartAfter(p1);

console.log(range1.startContainer); //document.body
console.log(range1.startOffset); //2 有1个空格和一个p元素
console.log(range1.endContainer); //document.body
console.log(range1.endOffset); //2 选择了一个元素,所以是startOffset加1
console.log(range1.commonAncestorContainer); //document.body

range2.setStartAfter(p1); //结果与上面的相同
console.log(range2.startContainer); //document.body
console.log(range2.startOffset); //2
console.log(range2.endContainer); //document.body
console.log(range2.endOffset); //2
console.log(range2.commonAncestorContainer); //document.body
用DOM范围实现更加复杂的选择 setStart()setEnd()方法

这两个方法都接受两个参数:一个参照节点和一个偏移量值。对前者来说,参照节点会变成startContainer,偏移值则会变成startOffset。对于后者来说,参照节点会变成endContainer,偏移值会变成endOffset。

html:

Hello world!

js:

var p1 = document.getElementById("p1"),
    helloNode = p1.firstChild.firstChild,
    worldNode = p1.lastChild;
var range = document.createRange();
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3);

这样就完成了对“llo wo”的选择,但仅仅完成对该选区的选择意义不大,重要的是对其进行操作。

操作DOM范围中的内容 deleteContents()删除范围所包含的内容

如:

Hello world!

举例:

var p1 = document.getElementById("p1");
var hello = p1.firstChild.firstChild;
var world = p1.lastChild;
var range = document.createRange();

range.setStart(hello, 1);
range.setEnd(world, 2);

console.log(range.toString()); //ello w
console.log(p1.outerHTML); //

Hello world!

range.deleteContents(); //刪除範圍內的內容 console.log(p1.outerHTML); //

Horld!

又如:

  • thi is a list No.1
  • thi is a list No.2
  • thi is a list No.3
  • thi is a list No.4
  • thi is a list No.5

举例:

var list = document.getElementById("list");
var starting = list.getElementsByTagName("li")[1];
var ending = list.getElementsByTagName("li")[3];
var range = document.createRange();
range.setStart(starting, 0);
range.setEnd(ending, 0);
console.log(range.toString());
console.log(list.outerHTML);
range.deleteContents();
console.log(list.outerHTML);
extractContents()移除范围所包含的内容并返回文档片段

如:

Hello world!

举例:

var p1 = document.querySelector("#p1");
var helloNode = p1.firstChild.firstChild,
    worldNode = p1.lastChild;
var range = document.createRange();
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3);
var fragment = range.extractContents();
p1.parentNode.insertBefore(fragment, p1);

又如:

  • thi is a list No.1
  • thi is a list No.2
  • thi is a list No.3
  • thi is a list No.4
  • thi is a list No.5

举例:

var list = document.getElementById("list");
var range = document.createRange();

var starting = list.getElementsByTagName("li")[1];
var ending = list.getElementsByTagName("li")[4];

range.selectNode(list);
range.setStartBefore(starting);
range.setEndBefore(ending);

var fragment = range.extractContents();
document.body.appendChild(fragment);

console.log(document.body.innerHTML);

// 
  • thi is a list No.2
  • //
  • thi is a list No.3
  • //
  • thi is a list No.4
  • console.log(list.innerHTML); //
  • thi is a list No.1
  • //
  • thi is a list No.5
  • cloneContents()创建范围对象的一个副本

    如:

    var list = document.getElementById("list");
    var range = document.createRange();
    
    var starting = list.getElementsByTagName("li")[1];
    var ending = list.getElementsByTagName("li")[4];
    
    range.selectNode(list);
    range.setStartBefore(starting);
    range.setEndBefore(ending);
    
    var fragment = range.cloneContents();
    document.body.appendChild(fragment);
    
    console.log(document.body.innerHTML);
    
    // 
  • thi is a list No.2
  • //
  • thi is a list No.3
  • //
  • thi is a list No.4
  • console.log(list.innerHTML); //
  • thi is a list No.1
  • //
  • thi is a list No.2
  • //
  • thi is a list No.3
  • //
  • thi is a list No.4
  • //
  • thi is a list No.5
  • 插入DOM范围中的内容 insertNode()向范围选区的开始处插入一个节点(范围内部插入内容)

    如:

    • thi is a list No.1
    • thi is a list No.2
    • thi is a list No.3
    • thi is a list No.4
    • thi is a list No.5

    代码:

    
    

    又如:

    Hello world!

    代码:

    var p = document.getElementById("p1");
    var range = document.createRange();
    var starting = p.firstChild.firstChild;
    var ending = p.lastChild;
    
    range.setStart(starting, 5);
    range.setEnd(ending, 0);
    
    var span = document.createElement("span");
    span.appendChild(document.createTextNode(" there in this"));
    
    range.insertNode(span);
    
    console.log(p1.innerText); //Hello there in this world!
    console.log(p1.innerHTML); //Hello there in this world!
    
    surroundContents()向范围选区周围插入一个节点(围绕范围插入内容)

    通常与selectNode()配合,因为范围必须包含整个DOM选区,不能仅仅包含选中的DOM节点。

    如:

    Hello world!

    代码:

    var p = document.getElementById("p1");
    var range = document.createRange();
    
    range.selectNode(p.firstChild);
    
    var span = document.createElement("span");
    span.style.border = "1px solid orange";
    span.style.borderRadius = "3px";
    
    range.surroundContents(span);
    
    console.log(p1.innerHTML); //Hello world! 
    

    为了插入span标签,范围必须包含整个DOM选区,所以推荐使用selectNode()配合。

    折叠DOM范围 collapse()方法

    折叠就是指范围中未选择文档的任何部分。该函数接收一个参数,一个布尔值。true表示折叠到范围的起点,参数false表示折叠到范围的终点。要确定范围已经折叠完毕,可以检查collapsed属性:

    如:

    Hello world!

    代码:

    var p = document.getElementById("p1");
    var range = document.createRange();
    
    range.selectNode(p);
    range.collapse(true);
    console.log(range.collapsed); //True
    

    又如:

    • thi is a list No.1
    • thi is a list No.2
    • thi is a list No.3
    • thi is a list No.4
    • thi is a list No.5

    代码:

    var list = document.querySelector("#list");
    var range = document.createRange();
    range.setStartAfter(list.getElementsByTagName("li")[1]);
    range.setEndBefore(list.getElementsByTagName("li")[2]);
    console.log(range.collapsed); //False 因为还有一个空白节点在这里
    
    var range2 = document.createRange();
    range2.setStartAfter(list.getElementsByTagName("li")[3]);
    range2.setEndBefore(list.getElementsByTagName("li")[4]);
    console.log(range2.collapsed); //True 因为范围没有选中任何部分
    
    比较DOM范围 comopareBoundaryPoints()方法来比较

    该方法涌来比较这些范围是否有公共的边界。接收两个参数:表示比较方式的常量值和要比较的范围。如:

    Range.START_TO_START - 比较两个 Range 节点的开始点

    Range.END_TO_END - 比较两个 Range 节点的结束点

    Range.START_TO_END - 用 sourceRange 的开始点与当前范围的结束点比较

    Range.END_TO_START - 用 sourceRange 的结束点与当前范围的开始点比较

    注意:《高级程序设计》一书中,对后两个的说明太模糊(不正确?);下面是w3school的解释:

    您可能认为,首先需要用参数 how 的范围常量指定当前范围的边界点,然后再用它指定 sourceRange 的边界点。但事实上,

    常量 Range.START_TO_END 指定与当前范围的 end 点和 sourceRange 的 start 点进行比较。

    常量 Range.END_TO_START 指定比较当前范围的 start 点和指定范围的 end 点。

    如果第一个范围中的点位于第二个范围中的点之前,返回-1;如果相等返回0;如果第一个范围中的点位于第二个范围中的点之后,返回1

    如:

    Hello world!

    代码:

    var p = document.getElementById("p1");
    var range1 = document.createRange();
    var range2 = document.createRange();
    
    range1.selectNodeContents(p);
    range2.selectNodeContents(p);
    range2.setEndBefore(p.lastChild);
    
    console.log(range1.toString()); //Hello world!
    console.log(range2.toString()); //Hello
    
    console.log(range1.compareBoundaryPoints(Range.START_TO_START, range2)); //0
    console.log(range1.compareBoundaryPoints(Range.END_TO_END, range2)); //1
    

    又如:

    • thi is a list No.1
    • thi is a list No.2
    • thi is a list No.3
    • thi is a list No.4
    • thi is a list No.5

    代码:

    var list = document.querySelector("#list");
    var range1 = document.createRange();
    var range2 = document.createRange();
    
    range1.selectNodeContents(list);
    range1.setStartAfter(list.firstChild.nextSibling);
    range1.setEndBefore(list.lastChild.previousSibling);
    
    range2.selectNodeContents(list);
    
    console.log(range1.compareBoundaryPoints(Range.START_TO_START, range2)); //1
    console.log(range1.compareBoundaryPoints(Range.END_TO_END, range2)); //-1
    console.log(range1.compareBoundaryPoints(Range.START_TO_END, range2)); //1 注意这里是range1的END与range2的start对比;
    console.log(range1.compareBoundaryPoints(Range.END_TO_START, range2)); //-1 注意这里是range1的START与range2的END对比;
    
    复制DOM范围 cloneRange()方法复制范围;
    var newRange = range.cloneRange();
    
    清理DOM范围 detach()方法清理范围;
    range.detach();
    range = null;
    

    上面的是从文档中分离范围;下面的是解除引用。

    下节再讨论IE8及更早版本中的范围

    文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/78426.html

    相关文章

    • JavaScript DOM2DOM3——“DOM变化”注意要点

      摘要:和级分为许多模块,分别描述了的某个非常具体的子集。这些模块主要有核心视图事件样式遍历和范围以及。另外还有方法和方法框架的变化框架和内嵌框架分别用和表示,它们在级中都有一个新属性这个属性包含一个指针,指向表示框架内容的文档对象。 DOM2和DOM3级分为许多模块,分别描述了DOM的某个非常具体的子集。这些模块主要有核心(Core)、视图(Views)、事件(Events)、样式(Styl...

      骞讳护 评论0 收藏0
    • JavaScript DOM2DOM3——“遍历”注意要点

      摘要:级遍历和范围模块定义了两个用于辅助完成顺序遍历结构的类型和这两个类型能够基于给定的起点对结构执行深度优先的遍历操作。其中的属性,表示任何遍历方法在上一次遍历中返回的接待你。通过设置这个属性也可以修改遍历继续进行的节点。 DOM2级遍历和范围模块定义了两个用于辅助完成顺序遍历DOM结构的类型:NodeIterator和TreeWalker;这两个类型能够基于给定的起点对DOM结构执行深度...

      antz 评论0 收藏0
    • JavaScript DOM2DOM3——“样式”注意要点

      摘要:如计算的样式方法和属性前者是增强了,这个方法接收两个参数计算样式的元素以及一个伪元素字符串如。操作表样式类型表示的是样式表,包括元素包含的样式表和在元素中定义的样式表。 层次:访问style对象: style对象是CSSStyleDeclaration的实例; getComputedStyle方法也返回CSSStyleDeclaration的实例; 访问样式表: 元素包含的样式表...

      whjin 评论0 收藏0
    • JavaScript DOM2DOM3——“样式”注意要点

      摘要:如计算的样式方法和属性前者是增强了,这个方法接收两个参数计算样式的元素以及一个伪元素字符串如。操作表样式类型表示的是样式表,包括元素包含的样式表和在元素中定义的样式表。 层次:访问style对象: style对象是CSSStyleDeclaration的实例; getComputedStyle方法也返回CSSStyleDeclaration的实例; 访问样式表: 元素包含的样式表...

      Jason_Geng 评论0 收藏0
    • DOM扩展,DOM2DOM3

      摘要:扩展选择符的核心是两个方法和。目前已完全支持的浏览器有和。在写模式下,会根据指定的字符串创建新的子树,然后用这个子树完全替换调用元素。在删除带有事件处理程序或引用了其他对象子树时,就有可能导致内存占用问题。删除集合中指定位置的规则。 DOM扩展 选择符API Selectors API Level 1 的核心是两个方法:querySelector()和querySelectorAll(...

      suxier 评论0 收藏0

    发表评论

    0条评论

    happyhuangjinjin

    |高级讲师

    TA的文章

    阅读更多
    最新活动
    阅读需要支付1元查看
    <