10.29更新:
原文中有个错误,childNodes在非IE浏览器中获得的不只是元素节点还会有文本节点,用childNodes去获取元素节点往往会得不到自己想要的结果,所以建议少用childNodes。多用children,children只会获取元素节点。
DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)
DOM描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分
10.1 节点层次
节点分为几种不同的类型,每种类型分别表示文档中不同的信息及标记
每个节点都拥有自己的特点、数据和方法,另外也与其他节点存在某种关系
10.1.1 Node类型
DOM1级定义了一个Node接口,该接口将由DOM中的所有节点类型实现
这个Node接口在JavaScript中是作为Node类型实现的
JavaScript中的所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法。每个节点都有一个nodeType属性,用于表明节点的类型
(12个节点类型的数值常量见书p248)
if(someNode.nodeValue == 1){
//也可使用someNode.nodeValue == Node.ELEMENT_NODE,但是这个不适用IE浏览器
alert("Node is an element);
}
1. nodeName和nodeValue属性
这两个属性可了解节点的具体信息,在使用这两个属性之前最好先判断一下节点的类型
if(nodeType == 1){
var value = someNode.nodeName;
}
元素的nodeName是标签名,nodeValue是null
2.节点关系
<html>
<head>
<style>
</style>
</head>
<body>
<div id="container">
<ul id="list">
<li></li>
<li></li>
</ul>
<img src="#" />
<a></a>
</div>
</body>
</html>
以上html代码作为例子用来分析节点关系
所以可得关系图
每个节点都有一个childNodes属性,其中保存着一个NodeList对象。NodeList是一种类数组对象,用于保存一组有序的节点,可通过位置来访问这些节点。(这个对象不是Array实例)
访问保存在NodeList中的节点,可通过数组的方法也可通过item(),但是推荐使用数组方法
var firstChild = parentNode.childNodes[0];
//也可用var firstChild = parentNode.childNodes.item(0);
var count = parentNode.childNodes.length;
//返回子节点个数
且parentNode.childNodes[0];可用parentNode.firstChild;代替
parentNode.childNodes[parentNode.childNodes.length-1]可用parentNode.lastChild代替
若父节点下只有一个子节点,则parentNode.firstChild和parentNode.lastChild的值相等
没有子节点,则它两个的值都为0
每个节点都有一个parentNode属性,指向该节点的父节点
还有两个属性previousSibling和nextSibling,前者指向该节点的前一个同胞节点,后者指向该节点的后一个同胞节点
上面的例子中ul,img,a三个元素所代表的节点就互为同胞节点,两个li也是互为同胞节点
hasChildNodes()方法可查询一个节点是否有子节点,有则返回true
ownerDocument属性指向表示整个文档的文档节点
3.操作节点
appendChild()方法:向childNodes列表末尾添加一个节点
若添加的节点是原有节点,那么就将该原有节点调换到列表的最后一个位置
insertBefore()方法:将节点插入到childNodes列表中某个特定位置上
接收两个参数,第一个是被插入的节点,第二个是参考节点。被插入节点会插入到参考节点前面一位。
replaceChild()方法:将原有节点替换成另一个节点
接受两个参数,第一个是要替换上去的节点,第二个是要被替换的节点。
removeChild()方法:移除某个节点
接受一个参数,要被移除的节点
前面的四个方法,都是操作某个父节点的子节点,所以说使用方法前要先取得父节点。例如父节点.appendChild(新的子节点);
4.其他方法
cloneNode()方法:创建调用这个方法的节点的副本
接受一个布尔值参数,true执行深复制(赋值节点及其整个子节点树),false执行浅复制,只复制该节点
这个副本在文档中,但它没有父节点,所以就像个“孤儿”一样没有自己的位置,如果想让他有自己的位置,就要用到前面的一些方法了
normalize()方法:处理文档树中的文档节点
本章后面会进一步讨论该方法
(未完待续)
10.1.2 Document类型
跳转到最常用的Document类型1
跳转到最常用的Document类型2
JavaScript通过Document类型表示文档
在浏览器中,document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面
document对象是window对象的一个属性,因此可以将其作为全局对象来访问
(Document节点的特征见书上p253)
1.文档的子节点
documentElement属性:该属性始终指向<html>元素
document.documentElement、document.childNodes[0]、document.firstChild都是指向<html>元素
body属性:直接指向<body>元素
var body = document.body; //取得对<body>的引用
2.文档信息
titile属性:包含着<title>元素中的文本(显示在浏览器窗口的标题栏或标签栏上)
修改title属性的值可改变<title>元素的文本内容
var title = document.title;
document.title = "yuan"; //修改标题,那么变量title的值也会跟着修改
URL属性:包含页面完整的URL
完整的URL:http://www.wrox.com/WileyCDA/
domain属性:只包含页面域名
页面域名:www.wrox.com
referrer属性:保存着链接到当前页面的那个页面的URL
在没有来源页面的情况下,该属性会包含空字符串
在这三个属性中只有domain是可以设置的,但是不能将这个属性设置为URL中不包含的域
//页面来自p2p.wrox.com域
document.domain = wrox.com;
document.domain = baidu.com; //错误
3.查找元素
getElementById()方法:按照元素的ID查找元素
不存在则返回null。若页面中有多个拥有相同ID的元素,则只返回文档中第一次出现的元素
getElementsByTagName()方法:根据元素标签查找元素
返回的是一个类似数组的动态集合对象HTMLCollection(下面的几个方法都会返回这样一个对象),和前面的childNodes有点像
var images = document.getElementsByTagName("img");
consolo.log(images[0].src); //输出images下第一个img元素的src特性
console.log(images.item(0).src); //用item()方法也是可以的
HTMLCollection对象下有一个方法namedItem(),使用这个方法可以通过元素的name特性取得集合中的项
console.log(images.namedItem("myImage")); //在HTMLCollection对象取得name为myImage的元素
console.log(images["myImage"]); //更简单的方法
因为在JavaScript和CSS中 * 通常表示全部
//访问文档中的所有元素
var allElements = document.getElementsByTagName("*");
getElementsByName()方法:返回带有给定name特性的所有的元素
最常使用此方法的情况是取得单选按钮
getElementsByClassName()方法:返回给定的class特性的元素
4.特殊集合(p258)
5.DOM一致性检测(p259)
6.文档写入
document.write();将方法中的字符串内容原样写入
document.writeln();将字符串内容写入后再添加一个换行符
两种方法还可动态地添加外部资源
document.write("<script type=\"text/javascript\" src=\"file.js\">" + "<\/script>");
10.1.3 Element 类型
用于表现HTML和XML元素,提供了对元素标签名、子节点及特性的访问。
Element节点特性(p261)
访问元素标签名,可使用nodeName属性或是tagName属性,两属性返回相同的值,但鉴于理解性,最好用后者
var div = document.getElementById("myDiv");
console.log(div.tagName); //DIV
返回DIV而不是div是因为再HTML中标签名是用大写字母表示,所以
if(div.tagName == "div"){ } //不能这样比较,要用下面这种
if(div.tagName.toLowerCase() == "div"){ }
1.HTML元素
一个特殊且有用的标准特性:
title 有关元素的附加说明信息,把鼠标停留再这个元素上一会儿他会自动显现出来
(其余部分见 p262-p264)
2.取得特性
getAttribute()方法:取得元素的特性
var div = document.getElementById("myDiv");
console.log(div.getAttribute("id")); //取得mydiv这个元素的ID属性
通过此方法也可取得自定义属性(自定义属性应该加上data-前缀以便验证)
自定义属性不会自动成为元素得特性;
开发人员不常用getAttribute(),而是只使用对象的属性。只有在取得自定义特性值得情况下才会使用getAttribute()方法
3.设置特性
setAttribute()方法:设置元素得特性,公认特性和自定义属性均可设置
接受两个参数,要设置得特性名和值。若特性已存在则会替换原有特性得值,不存在则重新创建
div.setAttribute("id","yuan");
div.id = "yuan"; //两者效果相同
4.attributes属性(没太看懂,但也用的不多)
Element类型是使用attributes属性得唯一一个DOM节点类型。attributes属性中包含一个NamedNodeMap,与NodeList类似,也是一个”动态“的集合
5.创建元素
createElement()方法可创建新元素,这个方法接受一个参数,即要创建的元素的标签名
var div = document.createElement("div");
div.id = "myNewDiv";
div.className = "boxContainer";
document.body.appendChild(div);
以上分为三步,创建一个新的元素,为这个元素添加一些特性,再将这个元素添加进文档树中
那么这个元素就真的进入文档树之中了,就能再网页中显示出来了
6.元素的子节点
不同浏览器对一个元素到底有多少子节点的定义不同,详见p269-p270
10.1.4 Text类型
文本节点由Text类型表示,包含的是纯文本内容
nodeName的值是"#text",nodeValue的值为节点所包含的文本
开始与结束标签之间有文本才算有文本节点,一个空格也算文本节点
1.创建文本节点
createTextNode()方法可创建新文本节点,接受一个参数,即要插入的节点的文本
//创建一个div标签的新元素
var element = document.createElement("div");
var text = document.createTextNode("Hello yuan");
//将这个文本节点放到元素下,这样才能在网页中正常显示
element.appendChild(text);
//将新建的元素节点放到body中
document.body.appendChild(element);
2.合并多个文本节点
normalize()方法:父元素调用normalize()方法可将其下面的多个文本节点合并到一起
var element = document.createElement("div");
var text = document.createTextNode("Hello");
element.appendChild(text);
var anotherText = document.createTextNode(" yuan");
elemnt.appendChild(anotherText);
document.body.appendChild(element);
console.log(element.childNodes.length); //1(合并为一个了)
console.log(element.firstChild.nodeValue); //Hello yuan
3.splitText()方法:此方法由文本节点调用,接受一个参数(从哪个位置开始分割),并且返回一个新的文本节点,此节点与原节点有同样的父节点
分割文本节点是一种常用的DOM解析技术
var element = document.createElement("div");
var text = document.createTextNode("Hello yuan");
element.appendChild(text);
document.body.appendChild(element);
//从第5个位置即空格开始分割文本节点
var newText = element.firstChild.splitText(5);
10.1.5 Comment类型
注释在DOM中通过Comment类型来表示
10.1.6 ——10.1.9
(p274-p277)
10.2 DOM 操作技术
(p277-p284)
10.3 小结
DOM是语言中立的API,用于访问HTML文档,DOM1将HTML看成一个层次化的节点树,可使用js来操作这个节点树,进而改变底层文档的外观和结构。
理解DOM的关键就是理解DOM对性能的影响。DOM操作往往是js程序中开销最大的部分,因此访问NodeList导致的问题最多。NodeList对象都是”动态的”,这就意味着每次访问NodeList对象,都会运行一次查询,所以最好减少DOM操作。