什么时DOM?
DOM是Document Object Model的缩写(文档对象模型),是W3C组织推荐的处理可扩展标志语言的标准编程接口。
当创建好一个页面并加载到浏览器时,DOM就悄然而生,它会把网页文档转换为一个文档对象,主要功能是处理网页内容,在这个文档对象里,所有的元素呈现出一种层次结构,就是说除了顶级元素html外,其他所有元素都被包含在另外的元素中。
假如有这么一段HTML代码:
<html>
<head>
<title>文档标题</title>
</head>
<body>
<a href="">我的链接</a>
<h1>我的标题</h1>
</body>
</html>
那么它的树就应该是下面这样的一颗倒长的树。一颗家谱树,而家谱树本身就是一种模型,其典型用法是表示人类家族谱系。它很容易表明家族成员之间的关系,把复杂的关系简明地表示出来,因此这种模型非常适合表示一份html的文档:
Node类型
DOM1级定义了 Node 接口,该接口将由 DOM 中的所有节点类型实现。这个 Node 接口在 JavaScript 中是作为 Node 类型实现的;除了 IE 之外,在其他所有浏览器中都可以访问到这个类型。JavaScript 中的所有节点类型都继承自 Node 类型,因此所有节点类型都共享着相同的基本属性和方法。
常量名 | 常量值 | 节点类型 | 描述 |
---|---|---|---|
Node.ELEMENT_NODE | 1 | Element | 代表元素 |
Node.ATTRIBUTE_NODE | 2 | Attr | 代表属性 |
Node.TEXT_NODE | 3 | Text | 代表元素或属性中的文本内容 |
Node.CDATA_SECTION_NODE | 4 | CDATASection | 代表文档中的 CDATA 部(不会由解析器解析的文本) |
Node.ENTITY_REFERENCE_NODE | 5 | EntityReference | 代表实体引用 |
Node.ENTITY_NODE | 6 | Entity | 代表实体 |
Node.PROCESSING_INSTRUCTION_NODE | 7 | ProcessingInstruction | 代表处理指令 |
Node.COMMENT_NODE | 8 | Comment | 代表注释 |
Node.DOCUMENT_NODE | 9 | Document | 代表整个文档(DOM 树的根节点) |
Node.DOCUMENT_TYPE_NODE | 10 | DocumentType | 向为文档定义的实体提供接口 |
Node.DOCUMENT_FRAGMENT_NODE | 11 | DocumentFragment | 代表轻量级的 Document 对象(文档的某个部分) |
Node.NOTATION_NODE | 12 | Notation | 代表 DTD 中声明的符号 |
加粗的是常用的节点
nodeName 属性与 nodeValue 属性
要具体了解节点的信息,就得使用到nodeName和nodeValue两个属性;
-
nodeName 属性含有某个节点的名称。
-
元素节点的 nodeName 是标签名称
-
属性节点的 nodeName 是属性名称
-
文本节点的 nodeName 永远是 #text
-
文档节点的 nodeName 永远是 #document
-
对于文本节点,nodeValue 属性包含文本。
-
对于属性节点,nodeValue 属性包含属性值。
-
nodeValue 属性对于文档节点和元素节点是不可用的。
常用的DOM操作
节点查找API
document.getElementById :根据ID查找元素,大小写敏感,如果有多个结果,只返回第一个;
document.getElementsByClassName :根据类名查找元素,多个类名用空格分隔,返回一个 HTMLCollection 注意兼容性为IE9+(含)。另外,不仅仅是document,其它元素也支持 getElementsByClassName 方法;
document.getElementsByTagName :根据标签查找元素,表示查询所有标签,返回一个 HTMLCollection 。
document.getElementsByName :根据元素的name属性查找,返回一个 NodeList 。
document.querySelector :返回单个Node,IE8+(含),如果匹配到多个结果,只返回第一个。
document.querySelectorAll :返回一个 NodeList ,IE8+(含)。
document.forms :获取当前页面所有form,返回一个 HTMLCollection ;
节点创造API
- createElement创建元素
var elem = document.createElement("div");
elem.id = 'xxx';
elem.style = 'background-color: red';
elem.innerHTML = '我是新的节点';
document.body.appendChild(elem);
通过createElement()方法先创建了一个<div>,id为"xxx",背景颜色为红色,内容为我是新的节点,然后通过appendChild()方法添加到文档树中.
- createTextNode创建文本节点
var node = document.createTextNode("我是文本节点");
document.body.appendChild(node);
- cloneNode 克隆一个节点
克隆节点接受一个布尔值:是否采用深度克隆,如果为true,则该节点的所有后代节点也都会被克隆,如果为false,则只克隆该节点本身.
var from = document.getElementById("test");
var clone = from.cloneNode(true);
clone.id = "test2";
document.body.appendChild(clone);
节点修改API
- appendChild()方法
parent.appendChild(child);
- insertBefore()方法
操作如果需要把节点放在ChildNodes列表的某个特定位置而不是放在末尾就要用到insertBefore()方法
这个方法只接受两个参数:要插入的节点和作为参照节点
被插入的节点就成了参照节点的前一个同胞节点.
parentNode.insertBefore(newNode, refNode);
- removeChild()方法
只接受一个参数就是要移除的节点
var deletedChild = parent.removeChild(node);
- replaceChild()方法
接受两个参数,要插入的节点和要替换的节点,要替换的节点将有这个新节点替换,并移除
parent.replaceChild(newChild, oldChild);
元素属性型API
- setAttribute()方法
接受两个参数:即要设置的特性名和值,如果特性名存在则会替换特性名;如果不存在则会设置特性名
element.setAttribute(name, value);
- getAttribute()方法
getAttribute返回指定的特性名相应的特性值,如果不存在,则返回null.
var value = element.getAttribute("id");
- removeAttribute()方法
removeAttribute()这个方法用于彻底删除元素的特征.调用这个方法不仅会清除值,而且会从元素中完全删除特性.
div.removeAttribute("class");
警惕文档遍历中的空格 bug
在遍历DOM元素时候,空格的存在很容易造成误解,因为DOM把空格也作为一个节点进行解析(换行符也算)
可以定义一个函数用来清除所有包括包含文本节点。这样当执行文档遍历的时候,就不存在元素之间的空格影响。函数要在文档结构加载完后在执行。
function clean(el) {
var el = el || document,
f = el.firstChild;
while (f != null) {
if (f.nodeType === 3 && /\s/.test(f.nodeValue)) {
e.removeChild(f);
} else if (f.nodeType === 1) {
arguments.callee(f);
}
f = f.nextSibling;
};
}
DOM由各节点构成
- 最基本的节点类型是Node,用于抽象的表示文档中的一个独立的部分;所有其他类型都继承自Node
- Document类型表示整个文档,是一组分层节点的根节点.在JavaScript中,document对象是Document的一个实例.使用document对象,有很多方式可以查询或取得节点
最后用<<JavaScript高级程序设计>>的一段话结束:理解DOM的关键,就是理解DOM对性能的影响.DOM操作往往是JavaScript程序中开销最大部分.而因访问NodeList导致的问题为最多.NodeList对象都是"动态的",这就意味着每次访问NodeList对象,都会运行一次查询.有鉴于此,最好的办法就是尽量减少DOM操作