0%

DOM-节点层级

Node类型

DOM Level 描述为名为Node的接口,Node接口在JavaScript中被实现为Node类型,所有结点都继承Node类型,因此所有类型都共享相同的基本属性和方法。

节点类型可通过与这些常量比较来确定

1
2
3
4
5
6
7
8
//节点类型可通过与这些常量比较确定,如果两者相等,则意味着someNode是一个元素节点
if(someNode.nodeType==Node.ELEMENT_NODE){
alert("Node is an element");
}
//nodeName和nodeValue保存着有关节点的信息
if(someNode.nodeType==1){
value=someNode.nodeName;//会显示元素的标签名
}

节点关系

节点与其他节点的关系可形容为家族关系,每个节点有一个childNodes属性其中包含一个NodeList的实例,NodeList是一个类数组对象,它是DOM结构的查询,DOM结构的变化会自动地在NodeList中反映出来,用于存储可以按位置存取的有序节点。可以使用中括号或者item()方法访问它的值

1
2
3
4
let firstChild=someNode.childNodes[0];
let secondChild=someNode.childNodes.item(1);
let count=someNode.childNodes.length;
let arrayofNodes=Array.from(someNode.childNodes);

parentNode指向DOM树中的父元素,childNode中所有节点都有同一个父元素,parentNode指向同一个节点,childNodes列表中每个结点都是同一列表中其他节点的同胞节点,使用previousSibling和nextSibling可以在这个列表的节点间导航。

hasChildNodes()节点返回true则说明节点有一个或多个子节点。

ownerDocument属性是一个指向代表整个文档的文档节点的指针

操纵节点

appendChild():用于在childNodes列表末尾添加节点,返回新添加的节点。

1
2
3
let returnedNode=someNode.appendChild(newNode);
alert(returnedNode==newNode);//true
alert(someNode.lastChild==newNode);//true

inserBefore():接收两个参数,要插入的节点和参照节点。要插入的节点会变成参照节点的前一个同胞节点,并被返回

1
2
3
4
5
6
7
8
9
10
returnedNode=someNode.insertBefore(newNode,null);
alert(newNode==someNode.lastChild);//true
//作为新的第一个子节点插入
retunedNode=someNode.insertBefore(newNode,someNode.firstChild);
alert(returnedNode==newNode);//true
alert(newNode==someNode.fiestChild);//true
//插入最后一个子节点的前面
returnedNode==someNode.insertBefore(newNode,someNode.lastChild);
alert(newNode==someNode.childNodes[someNode.childNodes.length-2]);//true

replaceChild():接收两个参数,要插入的节点和要替换的节点。要替换的节点被返回并从文档中被移除

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

removeChild():接收一个参数,即要被移除的节点,被移除的节点会被返回

1
let formerFirstChild=someNode.removeChild(someNode.firstChild);

cloneNode():传入true参数会进行深复制,即复制节点和整个子DOM树;传入false进行浅复制,只会复制该方法的节点。复制返回的节点属于文档所有,但未指定父节点,称为孤儿节点,通过appendChild()和insertBefore(),replaceChild()方法把孤儿节点添加到文档中

normalize():处理文本节点,如果发现空文本节点则将其删除否则如果两个同胞节点相邻则将其合并为一个文本节点

Document类型

表示文档节点的类型,document是HTMLDocument的实例(HTMLDocument继承Document),表示整个HTML页面,document是window对象的属性是一个全局对象。

  • nodetype等于9

  • nodeName值为“#document”

  • nodevalue值为null

  • parentNode值为null

  • ownerDocument值为null

  • 子节点可以使DocumentType(最多一个),Element(最多一个),ProcessingInstruction或Comment类型

文档子节点

documentElement:始终指向HTML页面中的元素

1
2
3
4
5
6
7
<html>
<body>
</body>
</html>
let html=document.documentElement;//取得对<html>的引用
alert(html===document.childNodes[0]);
alert(html===document.firstChild);

document.body:直接指向body元素,取得对body的引用

文档信息

title:显示浏览器窗口或标签页的标题栏

URL:包含当前页面的完整URL

domain:包含页面的域名

referrer:包含空字符串

1
2
3
//document.URL="http://www.wrox.com/WileyCDA/",document.domain就是www.wrox.com
document="wrrox.com";//成功
document="nczonline.net";//出错,不能给这个属性设置URL中不包含的值

当页面中包含来自某个不同子域的窗格()或内嵌窗格(

1
2
document.domain="wrox.com";//放松,成功
document.doman="p2p2.wrox.com";//收紧,失败,一旦放松就不能收紧

定位元素

getElementById():接收一个要获取元素的ID,如果找到这个元素则返回,没找到返回null。参数I必须跟元素在页面中大的id属性完全匹配,包括大小写

1
2
<div id="myDiv">ome text</div>
let div=document.getElementById("myDiv");//取得对<div>的引用,如果存在多个相同ID的元素则返回在文档中的第一个元素

getElementsByTagName():接收一个参数,即要获取元素的标签名,返回包含0个或多个元素的NodeList,在HTML文档中返回一个HTMLCollection对象

1
2
3
4
5
6
7
8
9
10
let images=document.getElementsByTagName("img");
alert(images.length);//图片数量
alert(images[0].src);//第一张图片的src属性
alert(images.item(0).src);
//通过name属性获得引用
<img src="myImage.gif" name="myImage">;
let myImage=images.namedItem("myImage");
//images["myImage"]
//取得文档的所有元素
let allElements=document.getElementsByTagName("*");

getElementsByName():返回具有给定name属性的所有元素,常用于单选按钮

1
2
3
4
5
6
7
8
9
10
<fieldset>
<legend>Which color do you prefer?</legend>
<ul>
<li>
<input type="radio" value="red" name="color" id="colorRed"><label for="colorRed">Red</label>
</li>
<li> <input type="radio" value="blue" name="color" id="colorBlue"><label for="colorBlue">Blue</label>
</li>
let radios=document.getElementsByName("color");

Element类型

  • nodeType=1

  • nodeName值为元素的标签名

  • nodeValue的值为null

  • parentNode值为Document或Element对象

  • 子节点可以是Element,Text,Comment,ProcessingInstruction等类型

通过nodeName或tagName属性获得元素的标签名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//使用对象属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="myDiv"></div>
<script>
let div=document.getElementById("myDiv");
alert(div.tagName);//"DIV"
alert(div.tagName==div.nodeName);//true
if(element.tagName.toLowerCase()=="div"){
//,HTML中,元素标签名以答谢表示,XML中标签名与代码中的大小写一致,不确定脚本是HTML还是XML运行,推荐将标签名转换为小写形式,适合所有文档
</script>
</body>
</html>

HTML元素

  • id:元素在文档中的唯一标识符

  • title:包含元素的额外信息,通常以提示条形式展示

  • lang:元素内容的语言代码

  • dir:语言的书写方向(ltr从左到右,rtl从右到左)

  • className:相当于class属性,用于指定元素的CSS类

取得属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//使用对象属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr">2</div>
<script>
var div=document.getElementById("myDiv");
alert(div.id);
alert(div.className);
alert(div.title);
alert(div.lang);
alert(div.dir);
</script>
</body>
</html>
//使用getAttribute()方法
alert(div.getAttribute("class"));

getAttribute()主要用于取得自定义属性的值,其他情况使用对象属性

设置属性

setAttribute():接收两个参数,要设置的属性名和属性值,如果属性存在则用指定的值替换原来的值

1
2
3
4
5
6
7
//直接给对象属性赋值
div.id="someOtherId"
//在对象属性上添加自定义属性,不会让它变成元素的属性
div.mycolor="red";
alert(div.getAttribute("mycolor"));//null
//使用setAttribute赋值
div.setAttribute("id","someOtherId");
attributes属性

attributes属性包含一个NamedNodeMap实例,是一个类似NodeList的“实时”集合,元素的每个属性都表示为一个Attr节点,并保存在NamedNodeMap对象中

attributed属性中的每个节点的nodeName是对应属性的名字,nodeValue是属性的值

1
2
3
4
5
6
7
8
function outputAttributes(element){
let pairs=[];
for(let i=0,len=element.attributes.length;i<len;++i){
const attribute=element.attributes[i];
pairs.push(`${attribute.nodeName}=${attribute.nodeValue}`);
return pairs.join(" ");
}
}
创建元素

document.createElement():一个参数,即要创建元素的标签名

1
2
3
4
let div=document.createElement("div");
div.id="myNewDiv";
div.className="box";
document.body.appendChild(div);

Text 类型

Text节点由Text类型表示,包含按字面解释的纯文本,也可能包含转义后的HTML字符,Text节点中包含的文本可以通过nodeValue或者data属性访问

  • nodetype=3

  • nodeName=”#text”

  • nodeValue值为节点中包含的文本

  • parentNode值为Element对象

  • 不支持子节点

  • appendData(text):向节点末尾添加文本text

  • deleteData(offset,count),从位置offset开始删除count个字符

  • insertData(offset,text),在位置offset插入text;

  • replaceData(offset,count,text),用text替换从位置offset到offset+count大的文本

  • splitText(offset),在位置offset将当前文本节点拆分为两个文本节点

  • substringData(offset,count),提取从位置offset到offset+count的文本

包含文本内容的每个元素最多只能有一个文本节点

创建文本节点

document.createTextNode():创建新文本节点,接收一个参数,即要插入节点的文本

1
2
3
4
5
6
7
8
9
let element=document.createElement("div");
element.className="message";

let textNode=document.createTextNode("Hello world!");
element.appendChild(textNode);
let anotherTextNode=document.createTextNode("Yippee");
element.appendChild(anotherTextNode);
document.body.appendChild(element);

规范化文本节点

合并文本节点
1
2
3
4
5
6
7
8
9
10
11
let element=document.createElement("div");
element.className="message";
let textNode=document.createTextNode("Hello World");
element.appendChild(textNode);
let anotherTextNode=document.createTextNode("Yippee");
element.appendChild(anotherTextNode);
document.body.appendChild(element);
alert(element.childNodes.length);//2
element.normalize();
alert(element.childNodes.length);//1
alert(element.firstChild.nodeValue);
拆分文本节点
1
2
3
4
5
6
7
8
9
10
let element=document.createElement("div");
element.className="message";
let textNode=document.createTextNode("Hello World");
element.appendChild(textNode);
document.body.appendChild(element);
let newNode=element.firstChild.splitText(5);
alert(element.fiestChild.nodeValue);//"Hello"
alert(newNode.nodeValue);//"world"
alert(element.chileNodes.length);//2

Comment类型

  • nodeType=8

  • nodeName=”#comment”

  • nodeValue值为注释内容

  • parentNode值为Document或Element对象

  • 不支持子节点

Comment类型与Text类型继承自同一个基类(CharacterData),因此拥有除splitText之外的Text节点所有的字符串操作方法

CDATASection类型

继承Text类型,拥有除splitText之外的Text节点所有的字符串操作方法

DocumentType类型

  • 在DOM Level1中不支持动态创建,只能在解析文档代码时创建,DocumentType对象保存在document.doctype属性中.

  • DocumentType对象有3个属性:name,entities,notations.

  • name是文档名称,entities是这个文档类型描述实体的NameNodeMap,而notations是这个文档类型描述的表示法的NamedNodeMap.

  • 浏览器文档通常是HTML或XHTML类型,所以entities和notations列表为空,只有name属性有用,包含文档类型的名称

DocumentFragment类型

  • nodeType=11

  • nodeName=”#document-fragment”

  • nodeValue=null

  • parentNode=null

  • 子节点可以是Element,ProcessingInstruction,Comment,Text,CDATASection

充当其他要被添加的文档节点的仓库

1
2
3
4
5
6
7
8
9
<ul id="myList"></ul>
let fragment=document.createDocumentFragment();
let ul=document.getElementById("myList");
for(let i=0;i<3;i++){
let li=document.createElement("li");
li.appendChild(document.createTextNode(`Item ${i+1}`));
fragment.appendChild(li);
}
ul.appendChild(fragment);

Attr类型

属性是存在于元素attributes属性中的节点

  • nodeType=2

  • nodeName值为属性名

  • nodeValue值为属性值

  • parentNode值为null

Attr对象上3个属性

  • name包含属性名

  • value包含属性值

  • specified是一个布尔值,表示属性使用的是默认值和还是被指定的值

1
2
3
4
5
6
7
let attr=document.createAttribute("align");//创建新的Attr节点,参数为属性名
attr.value="left";
element.setAttributeNode(attr);//添加属性节点
alert(element.attributes["align"].value);//返回对应属性节点
alert(element.getAttributeNode("align").value);//返回对应属性节点
alert(element.getAttribute("align"));//只返回属性值