DOM(文档对象模型)是针对HTML和XML的文档的一个API ,DOM描绘了一个层次化的节点树,允许开发人员添加,修改和删除页面中的一部分。
DOM1定义了一个Node接口,该接口由DOM中所有的节点类型实现。节点类型由在Node类型中定义的12个数值常量来表示,任何节点类型必居其一:
每个节点都有一个nodeType
属性,通过比较上面这些常量可以很容易知道节点的类型,但是由于IE浏览器并没有公开Node类型,因此最好还是将nodeType与数字值进行比较:
if (someNode.nodeType === 1) {
console.log('this is a element');
}
JavaScript中的每个节点都继承自Node类型,因此每个节点都有相同的基本属性和方法。
可以使用nodeName
和nodeValue
来了解节点的具体信息。这两个属性值完全取决于节点的类型,在使用之前最好先像下面这样进行检测一下:
if (someNode.nodeType === 1) {
let value = someNode.nodeName; // nodeName的值是元素的标签名
}
像上面这样,首先检测这个节点的类型,看它是不是一个元素,如果是便获取它的nodeName
的值,对于元素类型的节点来说,nodeName
的值是这个元素的标签名,而nodeValue
的值始终是null
。
每个节点都有一个childNodes
属性,这个属性里面保存着一个NodeList对象
。NodeList
是一个类数组的对象,里面保存着一组有序的节点。可以通过位置来访问这些节点。这个NodeList
虽然也有length
属性,但是它并不是Array
的实例。NodeList
的独特之处在于,它实际上是根据当前DOM结构进行查询的结果。因此DOM结构的变化可以在NodeList中反应出来。下面的例子展示了如何获取NodeList中保存的节点:
let firstChild = someNode,childNodes[0];
let secondChild = someNode.childNodes.item(1);
let count = someNode.childNodes.length;
在访问NodeList
中保存的节点时,使用[]
或者是item()
方法都可以,由于使用[]
比较像数组的语法,所以更受青睐。
childNodes
列表中的每个节点相互之间都是同胞节点。通过使用列表中的previousSibling
和nextSibling
属性可以访问列表中的其他节点。列表中的第一个节点的previousSibling属性值是null,最后一个节点的nextSibling属性值为null。如下所示:
if (someNode.nextSibling === null ) {
console.log('this.is the last node');
} else if (someNode.previousSibling === null) {
console.log('this is the first node');
}
每个节点都有一个parentNode
属性,这个属性指向文档树中的父节点。包含着childNodes
中的所有节点都有一个相同的父节点,因此它们的parentNode属性指向同一个节点。父节点与childNodes列表中的第一个节点和最后一个节点也有存在着特殊关系。父节点的firstChild
和lastChild
属性分别指向列表中的第一个子节点和最后一个字节点。其中someNode.fristNode的值等于someNode.childNodes[0]。而someNode.lastNode的值等于someNode.childNodes[someNode.childNodes.length - 1]的值。在只有一个子节点的情况下,firstChild和lastChild属性指向同一个值,在没有子节点的情况下,firstChild和lastChild属性值都为null。下图向我们表明了各节点之间的关系:
所有节点拥有的最后一个属性是ownerDocument
属性,该属性指向表示整个文档的文档节点。
hasChildNodes()
方法在节点拥有子节点的情况下会返回true
,这比查询childNodes的length属性更方便快捷。
因为关系指针都是只读的,所以DOM提供了一些操作节点的方法。
appendChild()
用于向childNodes
列表的末尾添加一个节点。添加成功后,childNodes
列表中新增的节点,父节点以及以前的最后一个节点的关系指针都会进行更新,更新完成后,appendChild()返回新增的节点。
let returnedNode = someNode.appendChild(newNode);
console.log(returnedNode === newNode);// true
console.log(someNode.lastChild === newNode); // true
如果appendChild()操作的节点本身是文档树的一部分,那么这个节点就会从当前位置移动到childNodes列表的最后一位。
如果想把节点插到特定的位置,此时就需要使用insertBefore()
方法,这个方法接受两个参数:要插入的节点和作为参照的节点。insertBefore()会将节点插入到参照节点的前面。同时返回新插入的节点。
// 当参照节点是null的时候,插入成为最后一个节点。
let returnedNode = someNode.insertBefore(newNode, null);
console.log(someNode.lastChild === returnedNode); // true
// 插入成为第一个节点
let returnedNode = someNode.insertBefor(newNode, someNode.firstChild);
console.log(someNode.firstChild === returnedNode); // true
replaceChild()
方法用来替换节点,它接受两个参数:要插入的节点和要替换的节点。并返回要替换的节点,而这个要替换的节点会被从DOM树上删除。// 替换第一个节点
let returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
// 替换最后一个节点
let returnedNode = someNode.replaceChild(newNode, someNode.lastChild);
removeChild()
方法。这个方法接受一个值,就是要移除的节点,这个要移除的节点会被作为该方法的返回值进行返回。// 移除第一个节点
let returnedNode = someNode.removeChild(someNode.firstChild);
// 移除最后一个节点
let returnedNde = someNode,removeChild(someNode.lastChild)
这个方法是所有的节点都有的,用于创建调用这个方法的节点的一个副本。cloneNode()
方法接受一个布尔值参数,在参数是true
的时候,表示执行深复制,也就是复制节点本身和整个子节点树。值为false
,表示执行浅复制,即只复制这个节点本身。复制后返回的节点副本属于文档所有,但是并没有给它指定父元素,因此这个副本就变成了一个“孤儿”。除非将它通过appendChild()
, insertBefore()
,replaceChild()
将它插入到文档树中。
假如有以下的HTML结构:
- item1
- item2
item3-
假设我们以及把ul元素的引用储存在了myList
变量中,那么通过下面代码就可以看到cloneChild()
两种模式的区别。
let deepList = myList.cloneChild(true);
console.log(deepList.childNodes.lengh); //3 (IE < 9) 或 7(其他浏览器)
let shallowList = myList.cloneChild(false);
console.log(shallowList.childNodes.length); // 0
说到常见的DOM应用,恐怕就要数取得特定的几个或某个元素的引用,从而进行操作了。取得元素的方法可以使用定义在document对象中的一些方法。
getElementById()
接受一个参数,这个参数是要取得的元素的id值**。这里的id值必须与元素的id属性值一模一样**。以下面的元素为例:
item1
// 可以使用下面的方法获取到这个div元素
let element = document.getElementById('myDiv');
如果页面中有多个id值一样的元素,getElementById()只会返回第一次出现的元素。
这个方法接受一个参数,即要获取的元素的标签名,而返回的是零个或多个元素的NodeList。
// 获取页面中的所有的img元素,并将返回的集合保存咋images变量中
let images = document.getElementsByTagName('img');
// 此时的images变量和NodeList很类似,可以使用[]或item()来访问其中的项
console.log(images.length); //img元素的数量
console.log(images[0].src); // 第一个img元素的src属性值
这个方法会返回带有给定name
属性的所有元素。最常使用该方法来获取单选按钮,不过要求所有的单元按钮具备相同的name属性值
-
-
-
// 获取name值为color的单选按钮元素
var radio = document.getElementsByName("color");
querySelector()
接受一个css选择符,返回与该模式匹配的第一个元素,如果没有,就返回null
。
// 获取body 元素
var body = document.querySelector("body");
// 获取id为#myDiv的元素
var div = dosument.querySelector("#myDiv")
// 获取类为selector的元素
var element = document.querySelector(".selector")
// 获取类为button的第一个ing元素
var img = document.querySelector("img.button")
querySelectorAll()
方法接受的参数与querySelector()一样,但返回的是所有匹配的元素,而不是第一个元素。
// 获取类为selector的元素
var elements = document.querySelectorAll(".selector")
// 获取p元素中的所有strong元素
var strongs = document.querySelectorAll("p strong");