DOM
IE中的所有DOM对象都是以COM对象的形式实现的。
节点层次
DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构。节点分为几种不同的类型:
文档元素: 在HTML页面中,文档元素始终都是
<html>
元素,(在XML中何元素都可能成为文档元素)
12种DOM节点层次(继承自一个基类型)
- 1、node类型
- 2、Document类型
- 3、Element类型
- 4、Text类型
- 5、Comment类型
- 6、CDATASection类型(only XML文档)
- 7、DocumentType(类型)(在Web浏览器中并不常用)
- 8、DocumentFragment
- 9、Attr类型
- … 其他
一、Node类型(12个数值常量来表明节点的类型。)
DOM1级定义了一个Node接口,该接口将由DOM中的所有节点类型实现。
JavaScript中的所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法。
1、dom.nodeName 和 nodeValue
这两个属性的值完全取决于节点的类型,对于元素节点,node-Name中保存的始终都是元素的标签名,而nodeValue的值则始终为null。
2、节点的关系 childNodes 、 parentNode、hasChildNodes()
每个节点都有一个childNodes属性,其中保存着一个NodeList对象,是一种类数组对象,用于保存一组有序的节点。childNodes列表中的每个节点相互之间都是同胞节点。通过使用列表中每个节点的previousSibling
和nextSibling
属性,可以访问同一列表中的其他节点。父节点与其第一个和最后一个子节点之间也存在特殊关系。父节点的firstChild
和lastChild
属性分别指向其childNodes列表中第一个和最后一个节点。
ParentNode.lastElementChild
ParentNode.firstElementChild
3、操作节点
-
appendChild()
: 将一个节点添加到指定父节点的子节点列表末尾, 如果传入到appendChild()中的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置。即使可以将DOM树看成是由一系列指针连接起来的,但任何DOM节点也不能同时出现在文档中的多个位置上。
//将一个节点添加到指定父节点的子节点列表末尾。
const child = node.appendChild(child);
// node: 是要插入子节点的父节点.
// child: 即是参数又是这个方法的返回值.
-
insertBefore()
参考节点之前插入一个节点作为一个指定父节点的子节点
const insertedElement = parentElement.insertBefore(newElement, referenceElement);
//1. referenceElement为null则newElement将被插入到子节点的末尾。
//2. 如果newElement已经在DOM树中,newElement首先会从DOM树中移除。
insertedElement
是被插入的节点,即 newElement
parentElement
是新插入节点的父节点
newElement
是被插入的节点
referenceElement
在插入newElement之前的那个节点
-
replaceChild()
: 接受的两个参数是:要插入的节点和要替换的节点
replacedNode = parentNode.replaceChild(newChild, oldChild);
// newChild 用来替换 oldChild 的新节点。如果该节点已经存在于DOM树中,则它会被从原始位置删除。
// oldChild 被替换掉的原始节点。
// replacedNode 和 oldChild相等。
-
removeChild()
从DOM中删除一个子节点。返回删除的节点
let oldChild = node.removeChild(child);
//OR
element.removeChild(child);
// child 是要移除的那个子节点.
// node 是child的父节点.
// oldChild保存对删除的子节点的引用. oldChild === child.
-
cloneNode()
: 接受一个布尔值参数,表示是否执行深复制。在参数为true的情况下,执行深复制,也就是复制节点及其整个子节点树;在参数为false的情况下,执行浅复制,即只复制节点本身。 normalize()
cloneNode 和 normalize 所有类型的节点都有
二、Document 类型(document对象-文档对象)
JavaScript通过Document类型表示文档。在浏览器中,document对象继承自Document类型的一个实例,表示整个HTML页面,是window对象的一个属性
- nodeType的值为9;
- nodeName的值为”#document”;
- nodeValue的值为null;
- parentNode的值为null;
- ownerDocument的值为null;
最常见的应用还是作为HTMLDocument实例的document对象
1、文档的子节点
DOM标准规定Document节点的子节点可以是DoumentType
、Element
、ProcessingInstruction
或Comment
,但还有两个内置的访问其子节点的快捷方式。
-
documentElement
属性,该属性始终指向<html>元素。 -
childNodes
列表访问文档元素,但通过documentElement属性则能更快捷、更直接地访问该元素。
// 取得对<html>的引用
var html = document.documentElement;
// true
alert(html === document.childNodes[0]);
//true
alert(html === document.firstChild);
//取得对<body>的引用
var body = document.body;
//取得对<!DOCTYPE>的引用
var doctype = document.doctype;
2、文档信息
作为HTMLDocument的一个实例,document对象还有一些标准的Document对象所没有的属性。
//取得文档标题
var originalTitle = document.title;
//设置文档标题
document.title = "New page title";
//取得完整的URL
var url = document.URL;
//取得域名
var domain = document.domain;
//取得来源页面的URL
var referrer = document.referrer;
只有domain是可以设置的。但由于安全方面的限制,也并非可以给domain设置任何值。如果URL中包含一个子域名,例如p2p.wrox.com,那么就只能将domain设置为”wrox.com“(URL中包含”www”,如www.wrox.com时,也是如此)。不能将这个属性设置为URL中不包含的域,如下面的例子所示。
//假设页面来自p2p.wrox.com域
// 成功
document.domain = "wrox.com";
// 出错!
document.domain = "nczonline.net";
当页面中包含来自其他子域的框架或内嵌框架时,能够设置document.domain就非常方便了。由于跨域安全限制,来自不同子域的页面无法通过JavaScript通信。而通过将每个页面的doc-ument.domain设置为相同的值,这些页面就可以互相访问对方包含的JavaScript对象了。
查找元素
- getElementById()
- getElementsByTagName()
- getElementsByName() 只有HTMLDocument类型才有的方法
- getElementsByClassName() (H5)
classList 属性
HTML5新增了一种操作类名的方式,可以让操作更简单也更安全,那就是为所有元素添加classList属性。这个classList属性是新集合类型DOMTokenList的实例。与其他DOM集合类似,DOMTokenList有一个表示自己包含多少元素的length属性,而要取得每个元素可以使用item()方法,也可以使用方括号语法。此外,这个新类型还定义如下方法。
- add(value):将给定的字符串值添加到列表中。如果值已经存在,就不添加了。
- contains(value):表示列表中是否存在给定的值,如果存在则返回true,否则返回false。
- remove(value):从列表中删除给定的字符串。
- toggle(value):如果列表中已经存在给定的值,删除它;如果列表中没有给定的值,添加它。
特殊集合
-
document.anchors
,包含文档中所有带name特性的<a>元素; -
document.forms
,包含文档中所有的<form>元素,与doc-ument.getElementsByTagName(“form”)得到的结果相同; -
document.images
,包含文档中所有的<img>元素,与doc-ument.getElementsByTagName (“img”)得到的结果相同; -
document.links
,包含文档中所有带href特性的<a>元素。
文档写入
write()
、writeln()
、open()
和close()
。
三、Element 类型
除Document类型之外,Element类型就要算是Web编程中最常用的类型了。Element类型用于表现XML或HTML元素,提供了对元素标签名、子节点及特性的访问。
- nodeType的值为1;
- nodeName的值为元素的标签名;
- nodeValue的值为null;
- parentNode可能是Document或Element;
- 其子节点可能是Element、Text、Comment、Processin-gInstruction、CDATASection或EntityReference
<div id="myDiv"></div>
//可以像下面这样取得这个元素及其标签名:
var div = document.getElementById("myDiv");
//"DIV"
alert(div.tagName);
//true
alert(div.tagName == div.nodeName);
// 在HTML中,标签名始终都以全部大写表示
1、HTML元素
所有HTML元素都是由HTMLElement或者其更具体的子类型来表示的。
2、操作特性
- getAttribute()
- setAttribute()
- removeAttribute()
3、attributes属性
attributes属性中包含一个NamedNodeMap,与NodeList类似,也是一个“动态”的集合。元素的每一个特性都由一个Attr节点表示,每个节点都保存在NamedNodeMap对象中。NamedNodeMap对象拥有下列方法。
4、创建元素
document.createElement()
var div = document.createElement("div");
div.id = "myNewDiv";
div.className = "box";
document.body.appendChild(div);
5、元素的子节点
元素可以有任意数目的子节点和后代节点,因为元素可以是其他元素的子节点。元素的childNodes属性中包含了它的所有子节点,这些子节点有可能是元素、文本节点、注释或处理指令。
四、Text 类型
文本节点由Text类型表示,包含的是可以照字面解释的纯文本内容。纯文本中可以包含转义后的HTML字符,但不能包含HTML代码。
- nodeType的值为3;
- nodeName的值为”#text”;
- nodeValue的值为节点所包含的文本;
- parentNode是一个Element;
- 不支持(没有)子节点。
可以通过nodeValue属性或data属性访问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为止处的字符串。
- length属性,保存着节点中字符的数目。
<!-- 没有内容,也就没有文本节点 -->
<div></div>
<!-- 有空格,因而有一个文本节点 -->
<div> </div>
<!-- 有内容,因而有一个文本节点 -->
<div>Hello World!</div>
通过 nodeValue 访问值
1.创建文本节点
- document.createTextNode()
var textNode = document.createTextNode("<strong>Hello</strong> world!");
var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
var anotherTextNode = document.createTextNode("Yippee!"); element.appendChild(anotherTextNode);
document.body.appendChild(element);
2.规范化文本节点normalize()。
3.分割文本节点splitText()。
五、Comment类型
<div id="myDiv"><!--A comment --></div>
DOM操作技术
动态脚本
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "client.js";
document.body.appendChild(script);
动态样式
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "style.css";
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
使用NodeList
NodeList每当文档结构发生变化时,NodeList都会得到更新。
小结
DOM由各种节点构成,简要总结如下。
- 最基本的节点类型是Node,用于抽象地表示文档中一个独立的部分;所有其他类型都继承自Node。
- Document类型表示整个文档,是一组分层节点的根节点。在JavaScript中,document对象是Document的一个实例。使用document对象,有很多种方式可以查询和取得节点。
- Element节点表示文档中的所有HTML或XML元素,可以用来操作这些元素的内容和特性。
- 另外还有一些节点类型,分别表示文本内容、注释、文档类型、CDATA区域和文档片段。
DOM扩展
- querySelector()
- querySelectorAll()
- matchesSelector() 这个方法接收一个参数,即CSS选择符,如果调用元素与该选择符匹配,返回true;否则,返回false。
H5
一、焦点管理
- document.activeElement
- document.hasFocus()
二、HTMLDocument 的变化
- readyState属性
document.readyState === 'loading'
document.readyState === 'complete'
- 字符集属性
//"UTF-16"
alert(document.charset);
document.charset = "UTF-8";
- 自定义数据属性
HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,目的是为元素提供与渲染无关的信息,或者提供语义信息。这些属性可以任意添加、随便命名,只要以data-开头即可。
dataset属性来访问自定义属性的值。dataset属性的值是DOMStringMap的一个实例,也就是一个名值对儿的映射。在这个映射中,每个data-name形式的属性都会有一个对应的属性
//本例中使用的方法仅用于演示
var div = document.getElementById("myDiv");
//取得自定义属性的值
var appId = div.dataset.appId;
var myName = div.dataset.myname;//设置值
三、插入标记
- innerHTML属性
- outerHTML属性
- insertAdjacentHTML()方法
四、内存与性能问题
// bad
for (var i=0, len=values.length; i < len; i++){
//要避免这种频繁操作!!
ul.innerHTML += "<li>" + values[i] + "</li>";
}
// good
var itemsHtml = "";
for (var i=0, len=values.length; i < len; i++){
itemsHtml += "<li>" + values[i] + "</li>";
}
ul.innerHTML = itemsHtml;
五、scrollIntoView()
scrollIntoView()可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。如果给这个方法传入true作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐。如果传入false作为参数,调用元素会尽可能全部出现在视口中,(可能的话,调用元素的底部会与视口顶部平齐。)不过顶部不一定平齐,例如:
//让元素可见
document.forms[0].scrollIntoView();