漫谈DOM
从 DOM的来源 说起。
上世纪九十年代,在浏览器争夺战中,微软为了霸占更多的浏览器市场,于是山寨了Netscape的Javascript而开发了Jscript ,并且还在其自身的浏览器IE中加入一些私有事务,这也正是导致javascript在浏览器兼容性问题的主要原因。为了统一web的开发标准,于是,W3C在1998年发布了一套网页编程接口,即为DOM。
那么,究竟什么是DOM。
DOM 是一组用来描述脚本怎样与结构化文档进行交互和访问的web标准。DOM定义了一系列对象、方法和属性,用于访问、操作和创建文档中的内容、结构、样式和行为。
其实HTML,XML,SVG这些语言都是支持DOM的,而且正是通过DOM我们才能操纵这些文档结构。简而言之,DOM赋予了javascript操作结构化文档的能力。应该明白的是,DOM 不是javascript,,它是由W3C定义的一组规范。
DOM的级别
DOM 0级
在严格意义上来说,是没有DOM0级和0级规范的。如果有人提到 0 级,那很可能是指一组专有的DHTML方法、对象和集合。而这些专有特性在成为标准的规范之前,在不同浏览器中实现是不一致。
DOM1级
DOM1级于1998年10月发布,是作为推进标准发布的第一DOM标准版本。DOM1级是一个规范,由如下两部分组成。
DOM core:为XML文档规定了一般性的树形节点结构的内部运行机制,同时给出了创建、编辑和操纵这个树形结构的必要属性和方法。
DOM HTML:为与HTML文档、标签集合以及个别的HTML标签相关的具体元素定义了对象、属性和方法。
DOM1级规范包含诸如Document、Node、Attr、Element、Text、HtmlDocument、HtmlElement和HtmlCollection等对象的定义。
DOM2 级
DOM2 级于2000年11月发布,更新了核心并增加了其他一些规范。这些规范主要被分为这六部分:
DOM2 Core:类似DOM Core,规定了对DOM文档结构的控制机制,添加了更多的特性。
DOM2 Html:类似DOM Html 规定了HTML的DOM文档的控制机制。还包括另外一些属性。
DOM2 Events:规定了与鼠标相关的事件。
DOM2 Style: 提供了访问和操作所有与css相关的样式及规则的能力。
DOM2 Traversal and Range:这两个规范使你能够迭代访问DOM,以便根据需要对文档进行遍历或操作。
DOM2 Views:提供了访问和更新文档表现的能力。
DOM3 级
DOM3级包含更新之后的核心,总共包含三个推荐规范:
DOM3 Core:向原有核心添加了更多的新方法和新属性,同时修改了已有的一些方法。
DOM3 Load and Save:提供将XML文档的内容加载到DOM文档中和将DOM文档序列化为XML文档的能力。
DOM3 Validation:提供了确保动态生成的文档的有效性的能力。
检测是否支持DOM(或DOM几级)
document.implementation 检测是否支持DOM
document.implementation.hasFeature()检测支持DOM几级,它有两个参数:
第一个参数可以是以下的其中一个:Core、XML、HTML、Views、StyleSheets、css、css2、Events、UIEvents等
第二个参数是DOM的级别:即1.0,2.0,3.0;
if (document.implementation) { |
DOM的属性
nodeName
nodeName属性返回的是节点的名称。此属性只读;
元素节点的 nodeName 与标签名相同
属性节点的 nodeName 与属性名相同
文本节点的 nodeName 始终是 #text
文档节点的 nodeName 始终是 #document
nodeValue
nodeValue属性返回的是节点的值。
元素节点的 nodeValue 是 undefined 或 null
文本节点的 nodeValue 是文本本身
属性节点的 nodeValue 是属性值
nodeType
nodeType属性返回的是节点的类型。此属性只读的;这里列出了几个比较常用的节点对应的类型值:
元素 — 1
属性 — 2
文本 — 3
注释 — 8
文档 — 9
DOM的方法
获取DOM
getElementById(id) — 返回指定id的元素
getElementsByName(nameVal) — 返回匹配所有name属性值的元素节点列表(NodeList)
getElementsByTagName(tagName) — 返回所有匹配tagName标签名的元素节点列表(NodeList)
getElementsByClassName(class) — 返回所有匹配class类名的元素节点列表(NodeList)
parentNode — 返回相关元素的父节点
childNodes — 返回指定元素的子元素集合 ,注意只是子元素(第一级),并不包含子元素的后代元素
firstChild — 返回指定元素的第一个子节点
lastChild — 返回指定元素的最后一个子节点
previousSibling — 返回指定元素的上一节点
nextSibling — 返回指定元素的下一节点
children — 返回指定元素的子元素集合,注意只是子元素(第一级),并不包含子元素的后代元素
querySelector() — 以css选择符作为参数,获取第一个匹配的元素
querySelectorAll() — 以css选择符作为参数,获取匹配的一个nodelist集合
rows(pos) — 获取第pos行的tr的内容
rows(pos) — 获取第pos行的tr的内容
cells(pos) — 获取第pos个td的内容
插入和操作DOM
appendChild(elem) — 在父级元素的最后插入elem元素
removeChild(elem) — 从父级元素中移除elem元素
insertBefore(newElem,curElem) — 在curElem元素前面插入newElem元素
replaceChild(newElem,oldElem) — 使用newElem元素替换oldElem元素
insertRow(pos) — tbody的第pos行插入tr,如 tbody.insertRow(1)
insertCell(pos) — tr的第pos个位置插入td,如tr.insertCell(1)
创建DOM
createElement(tagName) — 创建元素节点
createAttribute(attr) — 创建属性节点
createTextNode(text) — 创建文本节点
createDocumentFragment — 创建文档碎片
操作属性
getAttribute(attr) — 获取元素的attr属性值
removeAttribute(attr) — 移除元素的attr属性
setAttribute(attr,val) — 设置元素的attr属性为val
内容操作
innerHTML — 获取元素内(不含本身标签)所有的HTML(IE下标签名为大写)
outerHTML — 获取元素本身以及元素内(包含本身)所有的HTML(IE下标签名为大写)
innerText(或者 textContent) — 获取元素的所有文本内容(FF不支持,返回undefined,可用textContent代替)
- outerText(或者 textContent) — 获取元素的所有文本内容
样式操作
style.cssText — 获取标签中style属性里css属性
getComputedStyle(或者 currentStyle) — 获取标签在样式表中的相关css属性
DOM的性能
“把DOM和javascript分别比喻成一个岛屿,它们两者要联系起来,必须缴纳过桥费。因此访问DOM次数越多,则过桥的费用就越高”。同时修改任何DOM元素的样式都会导致页面重绘(repaint)和重排(reflow)。如果你要提高网页DOM性能,可以从以下几方面着手:
存储局部变量更快些
//效率低 |
很明显,第一次需要在每次循环都访问div1,而第二种方法就类似创建文档碎片,把每次循环的内容都添加到变量content中,最后只需要访问一次div2(DOM),就可以完成插入内容。
innerHTML对比原生DOM
在为一个DOM元素添加内容时,我们可以使用innerHTML直接插入,也可以先创建子元素,再插入子元素。大量实验证明,在普通情况下两者执行效率相差无几。但某些情况下,innerHTML还是比元素DOM方法效率更高些。
使用API去获取元素
因为API是高效封装的,而且通过原生的DOM获取相应的元素通常需要复杂的匹配。因此可以使用querySelector和querySelectorAll来代替原生的获取方法,同时一些新的属性也直接返回是元素节点。以下列出便利的DOM属性:
属性名 | 被替换属性 |
---|---|
children | childNodes |
childElementCount | childNodes.length |
firstElementChild | firstChild |
lastElementChild | lastChild |
nextElementSibling | nextSibling |
previousElementSibling | previousSibling |
重绘和重排
前面说到,任何改变DOM样式的情况都加重浏览器的计算去重绘或重排网页,我们不能不让网页重排,因为网页交互是建立在操作DOM的基础上,但我们可以尽量减少重绘和重排的次数,通常情况下,我们可以采用如下方法:
使用ele.stye.cssText+=””来代替多次改变样式
改变DOM元素的class来代替修改内联样式。但此方法只能是固定某种样式,而不能反复修改DOM的样式属性
固定某些模块的宽、高
css放在顶部
让需要改变属性的元素脱离文档流,当该元素发生样式改变时,不会影响到页面的其他元素(最多重绘)
事件委托
当我们要操作一组元素时,我们一般采用循环的方式,对每个元素添加事件,但是这样会导致事件处理程序过多而影响性能。事件委托是利用元素事件的冒泡,将事件添加到父级元素上,然后通过事件源判断目标元素,从而减少事件对DOM的引用。
<ul id="list"> |
参考
- javascript高级程序设计
- javascript DOM高级程序设计
- DOM百科
- 高性能的javascript