第10章 DOM
DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)。DOM描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。
节点层次:
DOM可以将任何HTML或XML文档描绘成一个由多层次节点构成的结构。
文档节点是每个文档的根节点。
<html>元素,我们称之为文档元素。每个文档只能有一个文档元素。
每一段标记都可以通过树中的一个节点来表示:HTML元素通过元素节点表示,特性通过特性节点表示,文档类型通过文档类型节点表示,而注释则通过注释节点表示。总共有12种节点类型,这些类型都继承自一个基类型。
(1)Node类型:
JavaScript中的所有节点类型都继承自Node类型。
每个节点都有一个nodeType属性,用于表明节点的类型。
每个节点都有一个childNodes属性,其中保存着一个NodeList对象。可以将NodeList对象转换为数组:
var arrayofNodes = Array.prototype.slice.call(someNode.childNodes,0);
每个节点都有一个parentNode属性,该属性指向文档树中的父节点。
操作节点:
最常用的方法是appendChild(),用于向childNodes列表的末尾添加一个节点。
如果需要把节点放在childNodes列表中某个特定的位置上,而不是放在末尾,那么可以使用insertBefore(),接受两个参数:要插入的节点和作为参照的节点。
replaceChild()方法接受两个参数:要插入的节点和要替换的节点。
removeChild()方法接受一个参数:即要移除的节点。
(2)Document类型
JavaScript通过Document类型表示文档。在浏览器中,document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面。而且,document对象是window对象的一个属性,因此可以将其作为全局对象来访问。
documentElement属性,该属性始终指向HTML页面的<html>元素。document对象还有一个body属性,直接指向<body>元素。
Title属性、URL属性(地址栏中显示的URL)、domain属性(页面域名)、
浏览器对domain属性有一个限制,即如果域名一开始是松散的,那么不能将它设为紧绷的。例如开始是jinjumao.club,不能再将其设为aguang.jinjumao.club。
查找元素:
getElementById()、getElementsByTagName()、getElementsByName()。
如果页面中多个元素ID值相同,getElementById只返回文档中第一次出现的元素。
如果在文档加载结束后(window.onload)再调用document.write(),那么输出的内容将会重写整个页面。
(3)Element类型
要访问元素的标签名,可以使用nodeName属性,也可以使用tagName属性。
属性:id、title、lang、dir(语言的方向)、className(css类)
取得特性:每个元素都有一个或多个特性,操作特性的DOM方法主要有三个,分别是getAttribute()、setAttribute()和removeAttribute()。
Attributes属性:Element类型是使用attributes属性的唯一一个DOM节点类型,要想遍历元素的特性,可以派上用场。
创建元素:
使用document.createElement()方法可以创建新元素,这个方法只接受一个参数,即要创建的元素的标签名。
如果需要通过childNodes属性遍历子节点,一定不要忘记浏览器之间的差别,IE不会计算空白符,而其他浏览器可能会计算空白符,这意味着在执行操作前,最好先检查一个nodeType属性是否为element类型。
(4)Text类型
文本节点由Text类型表示,包含的是可以照字面解释的纯文本内容。
创建文本节点:可以使用document.createTextNode()创建新文本节点,接受一个参数—要插入节点的文本。
规范化文本节点:normalize()方法,将相邻文本节点合并。
(5)Comment类型
注释在DOM中是通过Comment类型来表示的。
创建注释节点:document.createComment()方法
(6)CDATASection类型
CDATASection类型只针对基于XML的文档,表示的是CDATA区域。
(7)DocumentType类型
支持它的浏览器会把DocumentType对象保存在document.doctype中。DOM1级描述了DocumentType对象的3个属性:name、entities和notations。其中,name表示文档类型的名称,也就是出现在<!DOCTYPE之后的文本。
(8)DocumentFragment类型
DOM规定文档片段是一种“轻量级”的文档,可以包含和控制节点。
虽然不能把文档片段直接添加到文档中,但可以将它作为一个“仓库”来使用,即可以在里面保存将来可能会添加到文档中的节点。要创建文档片段,可以使用document.createDocumentFragment()方法。
(9)Attr类型
元素的特性在DOM中以Attr类型来表示。从技术角度讲,特性就是存在于元素的attributes属性中的节点。
尽管它们也是节点,但特性却不被认为是DOM文档树的一部分。
DOM操作技术:
动态脚本:
动态样式:所谓动态样式是指在页面刚加载时不存在,页面加载完成之后动态添加到页面中的。
操作表格:
<table>元素是HTML中最复杂的结构之一。
小结:
DOM是语言中立的API,用于访问和操作HTML和XML文档。DOM1级将HTML和XML文档形象地看作是一个层次化的节点树,可以使用JavaScript来操作这个节点树,进而改变底层文档的外观和结构。
理解DOM的关键,就是理解DOM对性能的影响。DOM操作往往是JavaScript程序中开销最大的部分,而因访问NodeList导致的问题为最多。NodeList对象都是“动态的”,这就意味着每次访问NodeList对象,都会运行一次查询。有鉴于此,最好的办法就是尽量减少DOM操作。
第11章 DOM扩展
对DOM的两个主要的扩展是Selectors API(选择符API)和HTML5。
选择符API:
众多JavaScript库中最常用的一项功能,就是根据CSS选择符选择与某个模式匹配的DOM元素。实际上,jQuery的核心就是通过CSS选择符查询DOM文档取得元素的引用,从而抛开了getElementById()和getElementByTagName()。
Selectors API是由W3C发起指定的一个标准,致力于让浏览器原生支持CSS查询。
Selectors API Level 1的核心两个方法:querySelector()和querySelectorAll()。
querySelector():
接收一个CSS选择符,返回与该模式匹配的第一个元素,如果没有找到,返回null。
querySelectorAll():
接收的参数与querySelector()一样,都是一个CSS选择符,但返回的是所有的匹配元素而不仅仅是第一个元素。
Selectors API Level 2规范为Element类型新增了一个方法matchesSelector()。
matchesSelector():
接收一个参数,即CSS选择符,如果调用元素与该选择符匹配,返回true,否则返回false。
元素遍历:
Element Traversal规范为元素定义了一组属性,解决了遍历元素子元素时存在空白文本节点的问题。
HTML5:
对于传统的HTML而言,对JavaScript接口的描述都不过三言两语,主要篇幅都用于定义标记,与JavaScript相关的内容一概交由DOM规范定义。而HTML5规范则围绕如何使用新增标记定义了大量JavaScript API。
(1)与类相关扩充:
getElementsByClassName()方法:接收一个参数,即一个包含一或多个类名的字符串
classList属性:
add()、remove()、contains()、toggle(),移除元素user类,div.classList.remove(‘user’);
(2)焦点管理:
document.activeElement属性,这个属性始终会引用DOM中当前获得了焦点的元素。
(3)HTMLDocument的变化:
readyState属性:(1)loading,正在加载文档;(2)complete,已经加载完文档。
兼容模式,compatMode属性:(1)document.compatMode为“CSS1Compat”表示标准模式;(2)为BackCompat表示混杂模式。
(4)字符集属性:
charset:表示文档中实际使用的字符集
defaultCharset:表示默认字符集
(5)自定义数据属性:
HTML5规定可以为元素添加非标准的属性,但要添加前缀data-,添加了自定义属性之后,可以通过元素的dataset属性来访问自定义属性的值,如添加了data-myname,访问方式是div.dataset.myname
(6)插入标记
innerHTML属性:
在读模式下,innerHTML属性返回与调用元素的所有子节点对应的HTML标记。在写模式下,innerHTML会根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。
outerHTML属性:
在读模式下,outerHTML返回调用它的元素及所有子节点的HTML标签。在写模式下,outerHTML会根据指定的HTML字符串创建新的DOM子树,然后用这个DOM子树完全替换调用元素。
insertAdjacentHTML()方法:接收两个参数,插入位置和要插入的HTML文本。
内存与性能问题:
在使用innerHTML、outerHTML属性和inserAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理程序和JavaScript对象属性。
不过这几个属性还是能为我们带来便利的,特别是使用innerHTML,一般来说,在插入大量新的HTML标记时,使用innerHTML属性与通过多次DOM操作先创建节点再指定它们之间的关系相比,效率要高得多。
(7)scrollIntoView()方法:
scrollIntoView()可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。
专有扩展:
(1)文档模式:
IE8引入了一个新的概念叫“文档模式”。
(2)children属性:
由于IE9之前的版本与其他浏览器在处理文本节点中的空白符时有差异,因此就出现了children属性。这个属性是HTMLCollection的实例,只包含元素中同样还是元素的子节点。
(3)contains()方法:
在实际开发中,经常需要知道某个节点是不是另外一个节点的后代。IE为此率先引入了contains()方法,以便不通过在DOM文档树中查找即可获得这个信息。
(4)插入文本:
innerText属性:
读取时,它会按照由浅入深的顺序,将子文档树中的所有文本拼接起来。写值时,结果会删除元素的所有子节点,插入包含相应文本值的文本节点。
outerText属性:除了作用范围扩大到了包含调用它的节点之外,outerText与innerText基本上没大多区别。
(5)滚动
第12章 DOM2和DOM3
DOM1级主要定义的是HTML和XML文档的底层结构。DOM2和DOM3级则在这个结构的基础上引入了更多的交互能力,也支持了更高级的XML特性。为此,DOM2和DOM3级分为许多模块,分别描述了DOM的某个非常具体的子集。(DOM2级核心、DOM2级视图、DOM2级事件、DOM2级样式、DOM2级遍历和范围、DOM2级HTML)
DOM变化:
DOM2和3级的目的在于扩展DOM API,以满足操作XML的所有需求,同时提供更好的错误处理及特性检测能力。
(1)针对XML命名空间的变化
(2)其他方面的变化
“DOM2级视图”模块添加了一个名为defaultView的属性,其中保存着一个指针,指向拥有给定文档的窗口(或框架)。
样式:
(1)访问元素的样式
(2)操作样式表
CSSStyleSheet类型表示的是样式表,包括通过<link>元素包含的样式表和在<style>元素中定义的样式表。
(3)元素大小
1.偏移量
元素的可见大小由其高度、宽度决定,包括所有内边距、滚动条和边框的大小(注意,不包括外边距)。
offsetHeight:元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、水平滚动条的高度、上边框高度和下边框的高度。
offsetWidth:元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、垂直滚动条的宽度、左边框宽度和右边框宽度。
offsetLeft:元素的左外边框至包含元素的左内边框之间的像素距离。
offsetTop:元素的上外边框至包含元素的上内边框之间的像素距离。
2.客户区大小
元素的客户区大小指的是元素内容及其内边距所占据的空间大小。
clientWidth:元素内容区宽度加上左右内边距宽度。
clientHeight:元素内容区高度加上上下内边距高度。
3.滚动大小
scrollHeight:在没有滚动条的情况下,元素内容的总高度。(包括隐藏的高度)
scrollWidth:在没有滚动条的情况下,元素内容的总宽度。(包括隐藏的宽度)
scrollLeft:被隐藏在内容区域左侧的像素数。
scrollTop:被隐藏在内容区域上方的像素数。
因此,带有垂直滚动条的页面的总高度就是document.documentElement.scrollHeight。
对于不包含滚动条的页面而言,scrollWidth和scrollHeight与clientWidth和clientHeight之间的关系并不十分清晰,浏览器之间的差异很大。
Firefox中这两组属性始终都是相等的,都代表文档内容区域尺寸,而非视口尺寸;
Opera、Safari 3.1及更高版本、Chrome中这两组属性是有差别的,其中scrollWidth和scrollHeight等于视口大小,而clientWidth和clientHeight等于文档内容区域大小;
IE(标准模式)中,scrollWidth和scrollHeight等于文档内容区域大小,而clientWidth和clientHeight等于视口大小。
因此在确定文档的总高度时,取两个值的最大值。
scrollTop和scrollLeft是可以设置的。
遍历:
“DOM2级遍历和范围”模块定义了两个用于辅助完成顺序遍历DOM结构的类型:NodeIterator和TreeWalker。这两个类型能够基于给定的起点对DOM结构执行深度优先的遍历操作。
(1)NodeIterator:
NodeIterator类型是两者中比较简单的一个,可以使用document.createNodeIterator()方法创建它的新实例。
两个主要方法是:nextNode()和previousNode()
(2)TreeWalker:
TreeWalker是NodeIterator的一个更高级的版本,除了包括nextNode()和previousNode()在内的相同的功能之外,还提供了几个方法:
parentNode():遍历到当前节点的父节点;
firstChild():遍历到当前节点的第一个子节点;
lastChild():遍历到当前节点的最后一个子节点;
nextSibling():遍历到当前节点的下一个同辈节点;
previousSibling():遍历到当前节点的上一个同辈节点;
范围:
(1)DOM中的范围
DOM2级在Document类型中定义了createRange()方法。
每个范围由一个Range类型的实例表示,这个实例拥有很多属性和方法。
selectNode():选择整个节点,包括子节点;
selectNodeContents():只选择节点的子节点;
(2)IE8及更早版本中的范围