DOM简介
DOM是Document Object Model(文档对象模型)的简称,根据W3C规范,DOM是一种与浏览器无关,与平台无关,与语言无关的接口,通过DOM,是的开发人员可以很方便的来访问页面当中的其他组件。简单的理解,DOM它解决了NetScape Javascript和Microsoft Javascript之间的冲突,给予了web设计师和开发者一个标准的跨越平台跟语言的方法,让他们方便的来访问站点的信息和操作页面的组件元素。
DOM它是以层次结构组织的节点或者信息片段的一个集合,这个集合允许开发人员在树状结构中导航寻找到特定的信息,分析该结构通常需要加载整个的文档结构,然后才能继续往下做进一步的工作。由于它是基于信息层次的,因此DOM是被认为基于树或者基于对象的。
我们可以先从下面的一个简单的例子来了解一下DOM的结构。
<html>
<body>
<h1>DOM Demo</h1>
<P>Hello DOM!
</body>
</html>
上面的HTML所对应的DOM结构如下所示:(树状结构)
DOM元素之间可以通过一些对应的层级关系来找对目标元素,例如parent,firstChild,lastChild,nextSibling,prevSibling等等,例如上面的例子,我们可以通过bodyElem.parent来找到html元素。
但是,有一点值得注意,还是用上面的例子,当我们用bodyElem.firstChild.firstChild.nodeValue时,我们希望得到的是h1的content,但是结果却是如下JavaScript Error: ‘Uncaught TypeError: Cannot read property 'nodeValue' of null’。为什么会发生这样的错误呢,其根本原因就在于当我们使用文本编辑器或者是IDE工具进行HTML编码的时候,为了提高代码的可读性,我们会apply相对应的代码风格,譬如断行,缩进等等,这些因素就造成了在HTML元素与元素之间生成了额外的空白(space)文本元素,这就给我们后续操作DOM制造了不小的麻烦,为了解决这个问题,我们可以采用下面的方法:
function removeWhiteSpace(element) { element = element || document; var cur = element.firstChild; while (cur != null) { if (cur.nodeType === 3 &&!/\S/.test(cur.nodeValue)) { element.removeChild(cur); } else if (cur.nodeType == 1) { removeWhiteSpace(cur); } cur = cur.nextSibling; } }
我们判断当前节点的类型,如果是文本节点(nodeType === 3)并且文本值为space的时候,我们把它从当前的结构中移除掉。
Node Type
不同的DOM节点有不同的node type,具体可以参看下表:
Element Node | 1 |
Attribute Node | 2 |
Text Node | 3 |
CData Node | 4 |
Entity Reference Node | 5 |
Entity Node | 6 |
Processing Instruction Node | 7 |
Comment Node | 8 |
Document Node | 9 |
Document Type Node | 10 |
Document Fragment Node | 11 |
Notation Node | 12 |
最为常见跟使用的是Element Node / Tex Node / Document Node types.
DOM Operation Methods
DOM提供一以下两个API方法供开发者调用,以获取站点当中的DOM节点元素:
- Document.getElementById(id) : Element (快速获取页面中节点指定id的节点元素并返回该元素)
- Document.getElementsByTagName(tagName) : NodeList 或者是 elem.getElementsByTagName(tagName) : NodeList (快速获取当前站点或者指定节点中所有标签名为tagName的所有节点元素,并返回该节点元素集合(NodeList类型))
window.onload = function () { var elem = document.getElementById('id'); var elems = document.getElementsByTagName('div'); };
这两个方法是最经常使用的DOM方法,为了简化其操作,我们可以适当的将其进行封装,已达到最简化:
var $ = { id : function (id) { return document.getElementById(id); }, tag : function (tagName, elem) { elem = elem || document; return elem.getElementsByTagName(tagName); } };
通过上面的封装,我们可以把上面的代码简化为:
window.onload = function () { var elem = $.id('id'); var elems = $.tag('div'); }
延展:开发我们自己的DOMAPI
由于我们经常需要提取页面中某些css class为指定className的元素或者元素集合,我们可以把它作为我们的一个utility API放在我们自己的知识库中去
- getElementsByClassName(className) : NodeList
function getElementsByClassName(cssClass, elem) { var results = []; elem = elem || document; var elems = elem.getElemensByTagName(*); for (var i = 0, len = elems.length; i < len; i++) { var node = elems[i]; if (elems[i].className && (elems[i].className.indexOf(cssClass) !== -1)) { results.push(elems[i]); } } return results; }
DOM Modification API
- appendChild(elem) : 在当前操作的节点末尾添加elem元素
- insertBefore(nodeToInsert, refElem) : 在before前面插入节点nodeToInsert
- removeChild(nodeToRemove) : 移除节点
- createElement(elem) / createElementNS(elem, NS): 创建新元素节点
- createTextNode(text) : 创建新文本节点
DOM Attributes API
DOM Specification中除了提供了对DOM节点元素的操作之外,同时也提供了对节点属性的操作,通过这些方法,我们获取或者修改相对应的节点元素的属性值。
常用的用于操作DOM节点属性的方法如下所示:
- getAttribute(name)
- setAttribute(name, value)
简单的代码示例如下所示:
<html> <body> <h1>DOM Demo</h1> <input id='username' type='text' name='username' value='' /> </body> <script type="text/javascript"> window.onload = function () { var username = document.getElementById('username'); var type = username.getAttribute('type'); console.debug('type : ' + type); username.setAttribute('value', 'TEST'); } </script> </html>