DOM 概况

DOM(文档对象模型)是针对 HTML 和 XML 文档的一个API(应用程序编程接口)。DOM 描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。

层次节点


DOM可以将任何 HTML 或 XML 文档描绘成一个由多层节点构成的结构。节点分成几种不同的类型,每种类型分别表示文档中不同的信息及(或)标记。每个节点都拥有各自的特点、属性及方法,另外也与其他节点存在某种关系。节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的树形结构。以下面的 HTML 为例:

<html>
  <head>
    <title> Sample Page </title>
  </head>
  <body>
    <p> Hello World! </p>
  </body>
</html>

可以将这个简单的 HTML 文档表示为一个层次结构:

Document
  Element html
    Element head
      Element title
        Text Sample Page

    Element body
      Element p
        Text Hello World!

文档节点是每个文档的根节点,在这个例子中,文档节点只有一个子节点,即 <html> 元素,我们称之为 文档元素。文档元素是文档的最外层元素,文档中的其他所有元素都包含在文档元素中。每个文档只能有一个文档元素。在 HTML 中,文档元素始终是 <html> 元素;而在 XML 中,没有预定义的元素,因此任何元素都能成为文档元素。

每一段标记都可以通过树中的一个节点来表示: HTML 元素通过元素节点来表示,特性(attribute)通过特性节点来表示,文档类型通过文档类型节点来表示,而注释通过注释节点表示。总共有 12 种节点类型,这些类型都继承自一个基类型。

Node 类型


DOM1 级定义了一个 Node 接口,该接口将由 DOM 中的所有节点类型实现。 这个 Node 接口在 Javascript 中是作为 Node 类型实现的;除了 IE 之外,其他所有浏览器中都可以访问到这个类型。Javascript 中所有节点类型都继承自 Node 类型,因此所有节点类型都共享着相同的基本属性和方法。

每个节点都有一个 nodeType 属性,用于表明节点的类型。 节点类型由在 Node 类型中定义的下列 12 个数值常量来表示,任何节点类型必居其一:

  1. Node.ELEMENT_NODE(1)
  2. Node.ATTRIBUTE_NODE(2)
  3. Node.TEXT_NODE(3)
  4. Node.CDATA_SECTION_NODE(4)
  5. Node.ENTITY_REFERENCE_NODE(5)
  6. Node.ENTITY_NODE(6)
  7. Node.PROCESSING_INSTRUCTION_NODE(7)
  8. Node.COMMENT_NODE(8)
  9. Node.DOCUMENT_NODE(9)
  10. Node.DOCUMENT_TYPE_NODE(10)
  11. Node.DOCUMENT_FRAGMENT_NODE(11)
  12. Node.NOTATION_NODE(12)

值得注意的是,并不是所有节点类型都受到 Web 浏览器的支持。 开发人员最常用的就是元素文本节点。而且,上面列出的变量,在 IE 中并没有什么卵用。

<div> </div>
<script>
  var a = document.querySelector('div');
  console.log(a.nodeType === 1); // 兼容所有浏览器
  console.log(a.nodeType === Node.ELEMENT_NODE); // 不兼容 IE
</script>

操作节点


// 访问子节点
var firstNode = someNode.childNodes[0];
var secondNode = someNode.childNodes.item(1);
var count = someNode.childNodes.length; // 能动态变化, childNode并不是快照

var firstNode = someNode.firstChild;
var lastNode = someNode.lastChild;

// 访问兄弟节点
var nextNode = someNode.nextSibling;
var preNode = someNode.previousSibling;

// 判断有没有子节点
var hasChild = someNode.hasChildNodes();
var hasChild = someNode.childNodes.length > 0;

// 访问节点的文档节点
var documentNode = someNode.ownerDocument;

/* 操作节点 */

// appendChild
var returnNode = someNode.appendChild(newNode);
console.log(returnNode === newNode) // true
console.log(someNode.lastChild === newNode) // true

// 如果传入到 appendChild() 中的节点已经是文档的一部分了,那就将该节点从原来的位置移到新的位置
var returnNode = someNode.appendChild(someNode.firstChild);
console.log(returnNode === someNode.firstChild); // false
console.log(returnNode === someNode.lastChild); // true

// insertBefore(a, b) 将a插入b前 a和b互为Sibling
// 插入后成为最后一个子节点
var returnNode = someNode.insertBefore(newNode, null);
console.log(newNode === someNode.lastChild); // true

// 插入后成为第一个子节点
var returnNode = someNode.insertBefore(newNode, someNode.firstChild);
console.log(returnNode === someNode.firstChild); // true

// removeChild 移除节点
var formerFirstChild = someNode.removeChild(someNode.firstChild);

// replaceChild 替换
// 替换第一个子节点
var returnNode = someNode.replaceChild(newNode, someNode.firstChild);

前面介绍的都是操作节点的子节点,也就是说,要使用这些方法必须先获得父节点。最后介绍的 cloneNode() 方法适合所有节点。

<ul>
  <li> apple </li>
  <li> orange </li>
  <li> pear </li>
</ul>

<script>
  var myList = document.querySelector('ul');

  // 深度复制
  var deepList = myList.cloneNode(true);
  console.log(deepList.childNodes.length); // 7

  // 浅复制
  var shallowList = myList.cloneNode(false);
  console.log(shallowList.childNodes.length); // 0
</script>
上一篇:TCP 和 UDP 在socket编程中的区别(转)


下一篇:socket编程中write、read和send、recv之间的区别~转载