DOM(Document Object Model)文档对象模型是 HTML 和 XML 文档的编程接口。
@TOC

1. 节点层级

  1. <html>
  2. <head>
  3. <title>Sample Page</title>
  4. </head>
  5. <body>
  6. <p>Hello World!</p>
  7. </body>
  8. </html>

这个例子可以表示为下图的层级结构
【DOM-节点层级】 - 图1
document 节点表示每个文档的根节点

1.1 Node 类型

所有节点类型都继承 Node 类型,节点类型由定义在 Node 类型上的 12 个数值常量表示
节点类型与这些常量比较来确定:

  1. if (someNode.nodeType == Node.ELEMENT_NODE){
  2. alert("Node is an element.");
  3. }

1.1.1 nodeName 与 nodeValue

  1. if (someNode.nodeType == 1){
  2. value = someNode.nodeName; // 会显示元素的标签名
  3. }

nodeName 始终等于元素的标签名,而 nodeValue 则始终为 null

1.1.2 节点关系

文档中的所有节点都与其他节点有关系,可以将其形容成家族关系。
每个节点都有一个 childNodes 属性,其中包含一个 NodeList 的实例。
NodeList是一个类数组对象,特点:它是一个实时的活动对象。

将NodeList转换为数组:

  1. let arrayOfNodes = Array.from(someNode.childNodes);
  • 父节点parentNode 属性
  • 兄弟节点,previousSibling(上一个) 和 nextSibling(下一个)

1.1.3 操纵节点

  • appendChild()方法
    用法:在 childNodes 列表末尾添加节点
    返回值:返回新添加的节点
    一个参数,要添加的节点变量
  • insertBefore()方法
    用法:在指定节点前添加新节点
    返回值:返回新添加的节点
    两个参数,1.要插入的节点。2.参照节点
  • replaceChild()方法
    用法:替换某个节点
    返回值:返回新添加的节点
    两个参数:要插入的节点和要替换的节点

1.1.4 其他方法

cloneNode()方法
用法:复制节点
返回值:返回一个节点
1个参数:为true时深拷贝,为false时,只拷贝当前节点,不拷贝它的子节点
例子:

  1. let deepList = myList.cloneNode(true);
  2. alert(deepList.childNodes.length); // 3(IE9 之前的版本)或 7(其他浏览器)
  3. let shallowList = myList.cloneNode(false);
  4. alert(shallowList.childNodes.length); // 0

1.2 Document 类型

文档对象 document 是HTMLDocument 的实例

  • nodeType 等于 9
  • nodeName 值为”#document”
  • nodeValue 值为 null;
  • parentNode 值为 null
  • ownerDocument 值为 null

1.2.1 文档子节点

  • documentElement 属性
    可以直接访问html元素,也可以通过childNodes列表访问
  1. let html = document.documentElement; // 取得对<html>的引用
  2. alert(html === document.childNodes[0]); // true
  3. alert(html === document.firstChild); // true
  • body 属性,直接指向元素
  1. let body = document.body; // 取得对<body>的引用

1.2.2 文档信息

title属性

  1. // 读取文档标题
  2. let originalTitle = document.title;
  3. // 修改文档标题
  4. document.title = "New page title";

3 个属性 URL、domain 和 referrer

  1. // 取得完整的 URL
  2. let url = document.URL;
  3. // 取得域名
  4. let domain = document.domain;
  5. // 取得来源
  6. let referrer = document.referrer;

1.2.3 定位元素

  • getElementById()方法
    一个参数:要获取元素的 ID,区分大小写
    返回值:这个元素
    存在多个相同ID会返回第一个元素
    不存在则返回null
  • getElementsByTagName()
    一个参数:标签名
    返回值:HTMLCollection对象
    对 HTMLCollection 对象而言,中括号可以接收数值索引和字符串索引,数值索引会调用item(),字符串索引会调用 namedItem()
  1. <img src="myimage.gif" name="myImage">
  2. let myImage = images.namedItem("myImage");
  3. let myImage = images["myImage"];

给 getElementsByTagName()传入*,返回所有元素的对象

  1. let allElements = document.getElementsByTagName("*");

第一项是元素,第二项是元素,以此类推

  • getElementsByName()
    一个参数:元素的name
    返回:所有具有相同name的元素,HTMLCollection类型。

1.2.4 特殊集合

1.2.5 文档写入

4 个方法:write()、writeln()、open()和 close()

  • write(),向页面中动态添加内容
    这个例子会在页面加载过程中输出当前日期和时间
  1. <html>
  2. <head>
  3. <title>document.write() Example</title>
  4. </head>
  5. <body>
  6. <p>The current date and time is:
  7. <script type="text/javascript">
  8. document.write("<strong>" + (new Date()).toString() + "</strong>");
  9. </script>
  10. </p>
  11. </body>
  12. </html>
  • writeln()
    比write()多一个换行符

1.3 Element 类型

  • nodeType 等于 1
  • nodeName 值为元素的标签名
  • nodeValue 值为 null
  • parentNode 值为 Document 或 Element 对象

可以通过 nodeNametagName 属性来获取元素的标签名
注意:元素标签名始终以全大写表示;

  1. <div id="myDiv"></div>
  2. let div = document.getElementById("myDiv");
  3. alert(div.tagName); // "DIV"
  4. alert(div.tagName == div.nodeName); // true

1.3.1 HTML 元素

  • id,元素在文档中的唯一标识符
  • title,包含元素的额外信息,通常以提示条形式展示
  • lang,元素内容的语言代码(很少用)
  • dir,语言的书写方向(”ltr”表示从左到右,”rtl”表示从右到左,同样很少用);
  • className,相当于 class 属性,用于指定元素的 CSS 类(因为 class 是 ECMAScript 关键字,所以不能直接用这个名字)。

这个元素中的所有属性都可以使用下列 JavaScript 代码读取:

  1. let div = document.getElementById("myDiv");
  2. alert(div.id); // "myDiv"
  3. alert(div.className); // "bd"
  4. alert(div.title); // "Body text"
  5. alert(div.lang); // "en"
  6. alert(div.dir); // "ltr"

1.3.2 取得属性

DOM 方法主要有 3 个:getAttribute()、setAttribute()和 removeAttribute()
可以操纵属性

  1. let div = document.getElementById("myDiv");
  2. alert(div.getAttribute("id")); // "myDiv"
  3. alert(div.getAttribute("class")); // "bd"
  4. alert(div.getAttribute("title")); // "Body text"
  5. alert(div.getAttribute("lang")); // "en"
  6. alert(div.getAttribute("dir")); // "ltr"

如果给定的属性不存在,则 getAttribute()返回 null。

1.3.3 设置属性

接收两个参数:要设置的属性名和属性的值。

  1. div.setAttribute("id", "someOtherId");
  2. div.setAttribute("class", "ft");
  3. div.setAttribute("title", "Some other text");
  4. div.setAttribute("lang","fr");
  5. div.setAttribute("dir", "rtl");

removeAttribute()方法
用于从元素中删除属性

1.3.4 attributes 属性

attributes 属性包含一个NamedNodeMap 实例,是一个类似 NodeList 的“实时”集合。

  • nodeName 是对应属性的名字
  • nodeValue 是属性的值

取得元素 id 属性的值:

  1. let id = element.attributes.getNamedItem("id").nodeValue;

简写:

  1. let id = element.attributes["id"].nodeValue;

通常开发者更喜欢使用 getAttribute()、removeAttribute()和 setAttribute()方法。
但是迭代一个元素上的所有属性很方便:

  1. function outputAttributes(element) {
  2. let pairs = [];
  3. for (let i = 0, len = element.attributes.length; i < len; ++i) {
  4. const attribute = element.attributes[i];
  5. pairs.push(`${attribute.nodeName}="${attribute.nodeValue}"`);
  6. }
  7. return pairs.join(" ");
  8. }

1.3.5 创建元素

document.createElement()方法创建新元素.
接收一个参数,即要创建元素的标签名

  1. let div = document.createElement("div");

元素被添加到文档树之后,浏览器会立即将其渲染出来

  1. document.body.appendChild(div);

1.3.6 元素后代

遍历某个元素的子节点:

  1. for (let i = 0, len = element.childNodes.length; i < len; ++i) {
  2. if (element.childNodes[i].nodeType == 1) {
  3. // 执行某个操作
  4. }
  5. }

1.4 Text 类型

  • nodeType 等于 3
  • nodeName 值为”#text”;
  • nodeValue 值为节点中包含的文本
  • parentNode 值为 Element 对象
  • 不支持子节点

两个访问Text节点包含的文本:nodeValue属性和data属性
也可以通过这两个属性进行更改

文本节点方法:

  • appendData(text),向节点末尾添加文本 text;
  • deleteData(offset, count),从位置 offset 开始删除 count 个字符;
  • insertData(offset, text),在位置 offset 插入 text;
  • replaceData(offset, count, text),用 text 替换从位置 offset 到 offset + count 的文本;
  • splitText(offset),在位置 offset 将当前文本节点拆分为两个文本节点;
  • substringData(offset, count),提取从位置 offset 到 offset + count 的文本。

1.4.1 创建文本节点

document.createTextNode()方法
作用:创建新文本节点
一个参数:要插入节点的文本

1.4.2 规范化文本节点

normalize()方法
对子节点中的同胞文本节点进行合并

  1. let element = document.createElement("div");
  2. element.className = "message";
  3. let textNode = document.createTextNode("Hello world!");
  4. element.appendChild(textNode);
  5. let anotherTextNode = document.createTextNode("Yippee!");
  6. element.appendChild(anotherTextNode);
  7. document.body.appendChild(element);
  8. alert(element.childNodes.length); // 2
  9. element.normalize();
  10. alert(element.childNodes.length); // 1
  11. alert(element.firstChild.nodeValue); // "Hello world!Yippee!"

1.4.3 拆分文本节点

splitText()方法,和normalize()相反

  1. let element = document.createElement("div");
  2. element.className = "message";
  3. let textNode = document.createTextNode("Hello world!");
  4. element.appendChild(textNode);
  5. document.body.appendChild(element);
  6. let newNode = element.firstChild.splitText(5);
  7. alert(element.firstChild.nodeValue); // "Hello"
  8. alert(newNode.nodeValue); // " world!"
  9. alert(element.childNodes.length); // 2

1.5 Comment 类型

注释通过Comment类型表示

  • nodeType 等于 8
  • nodeName 值为”#comment”;
  • nodeValue 值为注释的内容;
  • parentNode 值为 Document 或 Element 对象;
  • 不支持子节点。

Comment 类型与 Text 类型继承同一个基类
与 Text 类型相似,注释的实际内容可以通过 nodeValue 或 data属性获得。

1.6 Attr 类型

元素数据在 DOM 中通过 Attr 类型表示,相当于元素的属性的引用。

  • nodeType 等于 2;
  • nodeName 值为属性名;
  • nodeValue 值为属性值;
  1. let attr = document.createAttribute("align");
  2. attr.value = "left";
  3. element.setAttributeNode(attr);
  4. alert(element.attributes["align"].value); // "left"
  5. alert(element.getAttributeNode("align").value); // "left"
  6. alert(element.getAttribute("align")); // "left"