第十二章 DOM2和DOM3

元素大小

偏移量

offsetHeight: 元素在垂直方向上占用的空间大小,包括元素的高度,水平滚动条的高度,上边框高度和下边框高度。

offsetWidth: 元素在水平方向上占用的空间大小,包括元素的宽度度,垂直滚动条的高度,左边框高度和右边框高度。

offsetLeft: 元素的左外边框至包含元素的左内边框之间的像素距离。

offsetRight: 元素的左外边框至包含元素的左内边框之间的像素距离。

offsetTop: 

offsetParent: 属性返回一个对象的引用,这个对象是距离调用offsetParent的元素最近的(在包含层次中最靠近的),并且是已进行过CSS定位的容器元素。

如果这个容器元素未进行CSS定位, 则offsetParent属性的取值为根元素

 

客户区大小

元素内容及其内边距占据的空间大小。

clientWidth

clientHeight

 

滚动大小

包含滚动内容的元素大小。

scrollHeight: 再没有滚动的情况下,元素内容的总高度。

scrollWidth: 在没有滚动的情况下,元素内容的总宽度。

scollLeft: 被隐藏再内容区域左侧的像素。通过设置这个属性可以改变元素的滚动位置。

scollTop: 隐藏再内容区域上方的像素。通过设置这个属性可以改变元素的滚动位置。

 

确定元素大小

getBoundingClientRect():  为每个元素返回一个矩形对象,包含4个属性: left, top, right bottom。这些属性给出了元素再页面中相对视口的位置。

 

function getElementLeft(element) {
    //获取形参的元素的左外边框指包含元素的左内边框之间的像素差
     var actualLeft = element.offsetLeft; 
   //获取包含块的内边距
     var current = element.offsetParent;
    //当包含块不是空的时候
     while(current !== null) {
       //左偏移量 + 包含框的做偏移量 并赋值
        actualLeft += current.offsetLeft;
       //获取包含块的父级
        current = current.offsetParent;
    } 
   把值返回出去
    return actualLeft;
}
 
function getElementTop(element) {
    var actualTop = element.offsetTop;
    var current = element.offsetParent;

   while(current !== null) {
      actualTop += current.offsetTop;
      current = current.offsetParent;
   }
   return actualTop;
 }

function getBoundingClientRect(element) {
  //获取形参的顶部滚动距离
   var scrollTop = document.documentElement.scrollTop;
   //获取形参的左边滚动距离
   var scrollLeft = document.documentElement.scrollLeft;
   

    //如果形参的getBoundingClientRect可以用的话
    if(element.getBoundingClientRect) {
        //检测这个函数的形参的自定义属性offset不是数字的时候
        if(typeof arguments.callee.offset != "number") {
           //创建一个div
           var temp = document.createElement("div");
           //给这个div绝对定位 
           temp.style.cssText = "position: absolute; left: 0; top: 0;";
          //把这个元素丢进文档树
           document.body.appendChild(temp);
           //用getboundingClientRect方法获取这个div的高度,-减去滚动的距离,的到这个元素的top值。
           arguments.callee.offset =-temp.getBoundingClientRect().top - scrollTop;
           //从文档树中删除这个div
           document.body.removeChild(temp);
          //解除引用
           temp = null;
         }
        //获取这个形参的bottom.top,left,和right
         var rect = element.getBoundingClientRect();
        // 把这个对象的自定义属性赋给它自己
         var offset = arguments.callee.offset;
        
        //把值返回出去
         return {
           left: rect.left + offset,
           right: rect.right + offset,
           top: rect.top + offset,
           bottom: rect.bottom + offset
         }
     } else {
         var actualLeft = getElementLeft(element);
         var actualTop = getEementTop(element);
         return {
           left: actualLeft - scrollLeft,
           right: actualLeft + element.offsetWidth - scrollLeft,
           top: actualTop - scrollTop,
           bottom: actualTop + elementoffsetHeifht - scrollTop
         }
} 

 

遍历

DOM遍历是深度优先的DOM结构遍历,移动的方向至少有俩个,遍历以给定节点为根,不可能超出DOM树的根节点。

任何节点都可以作为遍历的根节点。即可以向下遍历,或者向上遍历。

NodeIterator:   

document.createNodeIterator()
//创建新实例

接受4个参数.

root:作为搜索起点的树中的节点。 

whatToShow: 表示要访问那些节点的数字代码。

filter:NodeFilter对象。一个表示应该接受还是拒绝某种特定节点的函数。

每个NodeFilter对象只有一个方法,即accept-Node();如果应该访问给定节点返回NodeFilter.FILTER_ACCEPT,不应该访问返回NodeFilter.FILTER_SKIP;

NodeFilter的俩个主要方法:

nextNode() 下一个节点, previousNode(),上一个节点。

例如一个展示《p》元素的节点迭代器

var filter = {
   acceptNode: function(node) {
        // 如果形参的标签名等于p 就返回 NodeFilter.FILTER_ACCEPT,
        // 不然返回NodeFilter.FILTER.SKIP;
       return node.tagName.toLowerCase() == "p" ?
       NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER.SKIP;
   }
};

var iterator = document.createNodeIterator(root, Nodefilter.SHOW_ELEMENT, filter, false);

遍历div元素中的所有元素

var oDiv = document.getElementById("div1");
var iterator = document.createNodeIterator(oDiv, NodeFilter.SHOW_ELEMENT, null, false);

var node = iterator.nextNode();
while(node !== null) {
   console.log(node.tagName);
   node = iterator.nextNode();
 }
// DIV
// P
// B
// UL
// LI(3)

如果只想返回遍历中遇到的li元素,只要使用一个过滤器

var oDiv = document.getElementById("div1");
var filter = function(node) {
   return node.tagName.toLowerCase() == "li" ? 
   NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
// NodeFilter.FILTER_ACCEPT 和 NodeFilter.FILTER_SKIP都是跳过指定的节点 }
var iterator = document.createNodeIterator(oDiv, NodeFilter.SHOW_ELEMENT, filter, false); var node = iterator.nextNode(); while(node !== null) { console.log(node.tagName); node = iterator.nextNode(); } //li(3)

 

TreeWalker

TreeWalker是NodeIterator的高级版本,提供了不同方向上的遍历DOM结构的方法

parentNode():遍历到当前节点的父节点;

firstChild(): 遍历到当前节点的第一个子节点。

lastChild(): 遍历到当前节点的最后一个子节点。

nextSiblings(): 遍历到当前节点的下一个同辈节点节点。

previousSiblings(): 遍历到当前节点的上一个同辈节点。

TreeWalker和NodeIterator一样接受4个参数, 作为遍历起点的根节点、要显示的节点类型、过滤器。一个表示是否扩展 实例引用的布尔值。

var oDiv = document.getElementById("div1");
var walker = document.createTreeWalker(oDiv,NodeFilter.SHOW_ELEMENT, filter, false);

var filter = function (node) {
    return node.tagName.toLowerCase() == "li" ? 
     NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
     //  使用walker时NodeFilter.FILTER_REJECT跳过相应节点及该整个字树
 }

var node = walker.nextNode();
if( node !== null) {
   console.log(node.tagName);
   node = walker.nextNode();
} 
// LI

使用TreeWalker遍历DOM树,即使不定义过滤器,也可以取得所有<li>元素。

var oDiv = document.getElementById("div1");
var walker = document.createTreeWalker(oDiv, NodeFilter.SHOW_ELEMENT, null, false);

walker.firstChild();          //div的第一个子元素即,定位到<p>元素
walker.nextSibling();     //p元素下一个同辈元素,即定位到<ul>元素

var node = walker.firstChild(); //  转到uil的第一个子元素
while(node !== null) {           .//  当 node不为空的时候,
  console.log(node.tagName);  //   弹出标签名
  node = walker.nextSibling(); //  保存walk的下一个同辈元素
}

 

范围

为了方便控制页面,"DOM二级遍历和范围" 定义了“范围”接口。通过范围可以选择文档中的一个区域,而不比考虑节点的界限。

var range = document.createRange();

新创建的范围直接与创建它的文档关联,不能用于其他文档。创建范围之后,接下来就可以使用它再后台选择文档中的特定部分。设置位置之后,可以针对范围的内容进入很多操作。

每个范围由一个range类型的实例表示

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

startOffset: 范围在startContainer中的偏移量。

endContainer: 包含范围终点的节点。

endOffset: 包含范围在endContainer终点的偏移量=。

commonAncestorContainer: startContainer和endContaine共同祖先节点再文档树中位置最深的那个。

 

1用DOM范围实现简单选择

用范围选择文档中的一部分。

有俩种方法 selectNode() 或 selectNodeContents()。都接受一个参数,即DOM节点,然后使用这个DOM节点信息来填充范围。

selectNode()选择整个节点,包括子节点。selectNodeContents()只选择节点的子节点。

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

可以使用下列的代码创建范围:

var range1 = document.createRange();
var range2 = document.createRange();

     p1 = document.getElementById("p1");

range1.selectNode(p1);

range2.selectNodeContents(p1);

 

2、用DOM范围实现复杂选择

使用setStart() ,setEnd()可以实现更复杂的范围选择接受一个参照节点和一个偏移量。

setStart(): 参照节点变成startContainer,偏移量变成startOffset。

setEnd():  参照节点endContainer, 偏移节点endOffset。

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

 

var p2 = document.getElementById("p1");
helloNode = p1.firstChild.firstChild;
worldNode = p1.lastChild;

var range3 = document.createRange();
//传入helloNode,并设置偏移量2 (也就是e的位置)
range3.setStart(helloNode, 2);
////传入helloNode,并设置偏移量3  (也就是r的位置)
range3.setEnd(worldNode, 3)

3 操作DOM范围中的内容

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

deleteContents(): 可以从文档中删除范围所包含的内容。

extractContents(): 也可以从文档中移除范围内容,但是会返回文档片段。

var text = document.getElementById("p2");
var _this = text.firstChild.firstChild;
var _is = text.lastChild;

var range = document.createRange();
range.setStart(_this, 2);
range.setEnd(_is, 3);

var fragment = range.extractContents();
text.parentNode.appendChild(fragment);

 

4、插入DOM范围中的内容

insertNode(): 可以向范围选区开始处插入一个节点。

<body>
   <span style="color: red">Inserted text</span>
</body>
var p1 = document.getElementById("p2");
var hNode = p1.firstChild.firstChild;
var wNode = p1.firstChild;

var range = document.createRange();
range.setStart(hNode, 2);
range.setEnd(wNode, 3);
var eSpan = document.createElement("span");
eSpan.style.color = "red";
eSpan.appendChild(document.createNodeText("Inserted text"));
range.insertNode(eSpan);

 

 

 

 

 

 

startContainer

posted @ 2016-06-22 15:53  岳夏铭心  阅读(185)  评论(0编辑  收藏  举报