2018-12-18

10.1 节点层次

DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构。
节点分为几种不同的类型,每种类型分别表示文档中不同的信息及(或)标记。每个节点都拥有各自的特点、数据和方法,另外也在其他节点存在某种关系。
节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的树形结构。例:

<html>//文档元素,是最外层元素
      <head>
              <title>Sample</title>
      </head>
      <body>
                <p>Hello world</p>
       </body>
</html>
image.png

每一段标记都可以通过树中的一个节点来表示:HTML元素通过元素节点表示,特性(attribute)通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示。

10.1.1 Node类型

DOM1级定义了一个Node接口,该接口将由DOM中的所有节点类型实现。这个Node接口在Javascript中时作为Node类型实现的;除了IE之外,在其他所有浏览器中都可以访问到这个类型。
Javascript中的所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法。
每个节点都有一个nodeType属性,用于表明节点的类型。
下面有定义的12个数值常量来表示,任何节点必居其一:

◆ NODE.ELEMENT_NODE(1);
◆ NODE.ATTRIBUTE_NODE(2);
◆ NODE.TEXT_NODE(3);
◆ NODE.CDATA_SECTION_NODE(4);
◆ NODE.ENTITY_REFERENCE_NODE(5);
◆ Node.ENTITY_NODE(6);
◆ Node.PROCESSING_INSTRUCTION_NODE(7);
◆ Node.COMMENT_NODE(8);
◆ Node.DOCUMENT_NODE(9);
◆ Node.DOCUMENT_TYPE_NODE(10)
◆ Node.DOCUMENT_FRAGMENT_NODE(11);
◆ Node.NOTATION_NODE(12)

if(someNode.nodeType == Node.ELEMENT_NODE){//在IE中无效
    alert("Node is an element.");
}
//这个例子比较了someNode.nodeType和Node.ELEMENT_NODE常量。
//如果二者相等,则意味着someNode确实是一个元素

然而IE没有公开Node类型的构造函数,因此上面的代码在IE中会导致错误。
为了确保浏览器兼容,最好还是将nodeType属性与数字值进行比较:

if(someNode.nodeType == 1){
    value = someNode.nodeName;  //nodeName的值是元素的标签名
}

//首先检查节点类型,看它是不是一个元素
//如果是则取得并保存nodeName的值
//对于元素节点,nodeName中保存的始终都是元素的标签名
//而nodeValue的值则始终为null
1.nodeName和nodeValue属性

要了解节点的具体信息,可以使用nodeName和nodeValue这两个属性。
这两个属性的值完全取决于节点的类型。在使用之前,最好先检测一下节点的类型:

if(someNode.nodeType == 1){
    value = someNode.nodeName;   //nodeName 的值是元素的标签名
//先检查节点类型是不是一个元素
//是的话取得并保存nodeName值
}

nodeName中保存的始终都是元素的标签名,而nodeValue的值则始终为null

2.节点关系

每个节点都有一个childNodes属性,其中保存着一个NodeList对象。
NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。
NodeList对象的独特之处在于,它实际上是基于DOM结构动态执行查询的结构,因此DOM结构的变化能够自动反应在NodeList对象中。
NodeList是有生命、有呼吸的对象,而不是在我们第一次访问它们的某一瞬间拍摄下来的一张快照

下面的例子展示了如何访问保存在NodeList中的节点——可以通过方括号,也可以使用item()方法;

var firstChild=someNode.childNodes[0];
var secondChild = someNodes.item(1);
var count = someNode.childNodes.length;

要注意length属性表示的是访问NodeList的那一刻,其中包含的节点数量。

可以将NodeList对象转换为数组:

//在IE8及之前版本中无效
// 因为IE8 及更早版本将NodeList实现为一个COM对象
var arrayofNodes = Array.prototype.slice.call(someNode.childNodes,0);

//要想在IE中将NodeList转换为数组,必须手动枚举所有成员
function convertToArray(nodes){
        var array = null;
        try{
                array = Array.prototype.slice.call(nodes.0);//针对非IE浏览器
        }catch(ex){
              array = new Array();
              for(var i=0;len=nodes.length;i++){
                  array.push(nodes[i]);
              }
        }
      return array;
}
//所有浏览器中都可以运行
//如果导致了错误,则通过try-catch块来捕获错误,然后手动创建数组。

每个节点都有一个parentNode属性,该属性指向文档数中的父节点。
包含在chileNodes列表中的所有节点都具有相同的父节点,因此他们的parentNode属性都指向同一节点。
此外,包含在childNodes列表中的每个节点相互之间都是同胞节点。

image.png

在反应这些关系的所有属性中,childNodes属性与其他属性相比更方便一些。因为只需使用简单的关系指针,就可以通过它访问文档树中的任何节点。
另外,hasChildNodes()也是一个非常有用的方法,这个方法在节点包含一或多个子节点的情况下返回true。

3 操作节点

因为关系指针都是只读的,所以DOM提供了一些操作节点的方法。
其中,最常用的方法是appendChild(),用于向childNodes列表的末尾添加一个节点。添加节点后——新增节点(父节点、子节点)都会得到相应的更新。
更新完成之后——返回新增的节点:

var returnedNode = someNode.appendChild(newNode);
alert(returnedNode == newNode);//true
alert(someNode.lastChild = newNode);/true

如果需要把节点放在childNodes列表中某个特定的位置上,而不是放在末尾,那么可以使用insertBefore()方法。
insertBefore()方法有两个参数:出入的节点和作为参照的节点。
插入节点后,被插入的节点会变成参照节点的前一个同胞节点,同时被方法返回,如果参照节点是null,则insertBefore()与appendChild()执行相同的操作:

//插入后成为最后一个子节点
returnedNode = someNode.insertBefore(newNode,null);
alert(newNode == someNode.lastChild);//true

//插入后成为第一个子节点
var returnedNode = someNode.insertBefore(newNode,someNode.firstChild);
alert(returnedNode == newNode);//true
alert(newNode == someNode.firstChild);//true

//插入到最后一个子节点前面
returnedNode = someNode.insertBefore(newNode,someNode.firstChild);
alert(newNode=someNode.childNodes[someNode.childNodes.length-2]);

appendChild()和insertBefore()方法都只插入节点,不会移除节点

replaceChild()方法接收两个参数:要插入的节点和要替换的节点。要替换的节点将由这个方法返回并从文档树中被移除,同时由要插入的节点占据其位置

//替换第一个子节点
var returnedNode = someNode.replaceChild(newNode,someNode.firstChild);

//替换最后一个子节点
returnedNode = someNode.replaceChild(newNode,someNode.lastChild);

如果只想移除而非替换节点,可以使用removeChild()方法。这个方法接收一个参数,即要移除的节点。被移除的节点将成为方法的返回值:

//移除第一个子节点
var formerFirstChild = someNode.removeChild(someNode.firstChild);

//移除最后一个节点
var formerLastChild = someNode.removeChild(someNode.lastChild);
4.其他方法

有两个方法是所有类型的节点都有的。
1)cloneNode():用于创建调用这个方法的节点的一个完全相同的副本。
cloneNode()方法接收一个布尔值参数,表示是否执行深复制。
参数为true执行深复制;false情况下,执行浅复制。
复制后返回的节点副本属于文档所有,但并没有为它指定父节点,因此它是“孤儿”,除非通过append()、inserBefore()或replaceChild()将它添加到文档中。

<ul>
      <li>item1</li>
      <li>item2</li>
      <li>item3</li>
</ul>
//将<ul>元素的引用保存在了变量myList中,使用下列代码就可以看出使用cloneNode()方法的两种模式:

var deepList = myList.cloneNode(true);
alert(deepList.childNodes.length);
image.png

最后一个方法normalize():处理文档树中的文本节点。
如果找到空文本节点,则删除它。
如果找到相邻的文本节点,则将它们合并为一个文本节点。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容