DOM(Document Object Model)文档对象模型是 HTML 和 XML 文档的编程接口。
@TOC
1. 节点层级
<html>
<head>
<title>Sample Page</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
这个例子可以表示为下图的层级结构
document 节点表示每个文档的根节点
1.1 Node 类型
所有节点类型都继承 Node 类型,节点类型由定义在 Node 类型上的 12 个数值常量表示
节点类型与这些常量比较来确定:
if (someNode.nodeType == Node.ELEMENT_NODE){
alert("Node is an element.");
}
1.1.1 nodeName 与 nodeValue
if (someNode.nodeType == 1){
value = someNode.nodeName; // 会显示元素的标签名
}
nodeName 始终等于元素的标签名,而 nodeValue 则始终为 null
1.1.2 节点关系
文档中的所有节点都与其他节点有关系,可以将其形容成家族关系。
每个节点都有一个 childNodes 属性,其中包含一个 NodeList 的实例。
NodeList是一个类数组对象,特点:它是一个实时的活动对象。
将NodeList转换为数组:
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时,只拷贝当前节点,不拷贝它的子节点
例子:
let deepList = myList.cloneNode(true);
alert(deepList.childNodes.length); // 3(IE9 之前的版本)或 7(其他浏览器)
let shallowList = myList.cloneNode(false);
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列表访问
let html = document.documentElement; // 取得对<html>的引用
alert(html === document.childNodes[0]); // true
alert(html === document.firstChild); // true
- body 属性,直接指向元素
let body = document.body; // 取得对<body>的引用
1.2.2 文档信息
title属性
// 读取文档标题
let originalTitle = document.title;
// 修改文档标题
document.title = "New page title";
3 个属性 URL、domain 和 referrer
// 取得完整的 URL
let url = document.URL;
// 取得域名
let domain = document.domain;
// 取得来源
let referrer = document.referrer;
1.2.3 定位元素
- getElementById()方法
一个参数:要获取元素的 ID,区分大小写
返回值:这个元素
存在多个相同ID会返回第一个元素
不存在则返回null - getElementsByTagName()
一个参数:标签名
返回值:HTMLCollection对象
对 HTMLCollection 对象而言,中括号可以接收数值索引和字符串索引,数值索引会调用item(),字符串索引会调用 namedItem()
<img src="myimage.gif" name="myImage">
let myImage = images.namedItem("myImage");
let myImage = images["myImage"];
给 getElementsByTagName()传入*,返回所有元素的对象
let allElements = document.getElementsByTagName("*");
第一项是元素,第二项是元素,以此类推
- getElementsByName()
一个参数:元素的name
返回:所有具有相同name的元素,HTMLCollection类型。
1.2.4 特殊集合
- document.anchors 所有带 name 属性的元素
- document.forms 包含文档中所有
- document.images 包含文档中所有元素
- document.links 包含文档中所有带 href 属性的元素。
1.2.5 文档写入
4 个方法:write()、writeln()、open()和 close()
- write(),向页面中动态添加内容
这个例子会在页面加载过程中输出当前日期和时间
<html>
<head>
<title>document.write() Example</title>
</head>
<body>
<p>The current date and time is:
<script type="text/javascript">
document.write("<strong>" + (new Date()).toString() + "</strong>");
</script>
</p>
</body>
</html>
- writeln()
比write()多一个换行符
1.3 Element 类型
- nodeType 等于 1
- nodeName 值为元素的标签名
- nodeValue 值为 null
- parentNode 值为 Document 或 Element 对象
可以通过 nodeName 或 tagName 属性来获取元素的标签名
注意:元素标签名始终以全大写表示;
<div id="myDiv"></div>
let div = document.getElementById("myDiv");
alert(div.tagName); // "DIV"
alert(div.tagName == div.nodeName); // true
1.3.1 HTML 元素
- id,元素在文档中的唯一标识符
- title,包含元素的额外信息,通常以提示条形式展示
- lang,元素内容的语言代码(很少用)
- dir,语言的书写方向(”ltr”表示从左到右,”rtl”表示从右到左,同样很少用);
- className,相当于 class 属性,用于指定元素的 CSS 类(因为 class 是 ECMAScript 关键字,所以不能直接用这个名字)。
这个元素中的所有属性都可以使用下列 JavaScript 代码读取:
let div = document.getElementById("myDiv");
alert(div.id); // "myDiv"
alert(div.className); // "bd"
alert(div.title); // "Body text"
alert(div.lang); // "en"
alert(div.dir); // "ltr"
1.3.2 取得属性
DOM 方法主要有 3 个:getAttribute()、setAttribute()和 removeAttribute()
可以操纵属性
let div = document.getElementById("myDiv");
alert(div.getAttribute("id")); // "myDiv"
alert(div.getAttribute("class")); // "bd"
alert(div.getAttribute("title")); // "Body text"
alert(div.getAttribute("lang")); // "en"
alert(div.getAttribute("dir")); // "ltr"
如果给定的属性不存在,则 getAttribute()返回 null。
1.3.3 设置属性
接收两个参数:要设置的属性名和属性的值。
div.setAttribute("id", "someOtherId");
div.setAttribute("class", "ft");
div.setAttribute("title", "Some other text");
div.setAttribute("lang","fr");
div.setAttribute("dir", "rtl");
removeAttribute()方法
用于从元素中删除属性
1.3.4 attributes 属性
attributes 属性包含一个NamedNodeMap 实例,是一个类似 NodeList 的“实时”集合。
- nodeName 是对应属性的名字
- nodeValue 是属性的值
取得元素 id 属性的值:
let id = element.attributes.getNamedItem("id").nodeValue;
简写:
let id = element.attributes["id"].nodeValue;
通常开发者更喜欢使用 getAttribute()、removeAttribute()和 setAttribute()方法。
但是迭代一个元素上的所有属性很方便:
function outputAttributes(element) {
let pairs = [];
for (let i = 0, len = element.attributes.length; i < len; ++i) {
const attribute = element.attributes[i];
pairs.push(`${attribute.nodeName}="${attribute.nodeValue}"`);
}
return pairs.join(" ");
}
1.3.5 创建元素
document.createElement()方法创建新元素.
接收一个参数,即要创建元素的标签名
let div = document.createElement("div");
元素被添加到文档树之后,浏览器会立即将其渲染出来
document.body.appendChild(div);
1.3.6 元素后代
遍历某个元素的子节点:
for (let i = 0, len = element.childNodes.length; i < len; ++i) {
if (element.childNodes[i].nodeType == 1) {
// 执行某个操作
}
}
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()方法
对子节点中的同胞文本节点进行合并
let element = document.createElement("div");
element.className = "message";
let textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
let anotherTextNode = document.createTextNode("Yippee!");
element.appendChild(anotherTextNode);
document.body.appendChild(element);
alert(element.childNodes.length); // 2
element.normalize();
alert(element.childNodes.length); // 1
alert(element.firstChild.nodeValue); // "Hello world!Yippee!"
1.4.3 拆分文本节点
splitText()方法,和normalize()相反
let element = document.createElement("div");
element.className = "message";
let textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);
let newNode = element.firstChild.splitText(5);
alert(element.firstChild.nodeValue); // "Hello"
alert(newNode.nodeValue); // " world!"
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 值为属性值;
let attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);
alert(element.attributes["align"].value); // "left"
alert(element.getAttributeNode("align").value); // "left"
alert(element.getAttribute("align")); // "left"