- DOM(文档对象模型)是针对HTML 和XML 文档的一个API
- IE 中的所有DOM 对象都是以COM 对象的形式实现的
nodeType属性
- 总共有12 种节点类型,这些类型都继承自一个基类型Node。
每个节点都有一个nodeType 属性,用于表明节点的类型。
元素节点(1);
属性节点(2);
文本节点(3);
注释节点(8);
文档节点(9);
文档段节点(11);
为了确保跨浏览器兼容,最好还是将nodeType 属性与数字值进行比较
NodeList
- NodeList 是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。NodeList 对象是基于DOM 结构动态执行查询的结果,因此DOM结构的变化能够自动反映在NodeList 对象中。NodeList 不是在我们第一次访问它们的某个瞬间拍摄下来的一张快照。
- NodeList有length属性,表示的是访问NodeList 的那一刻,其中包含的节点数量。
- 以将NodeList 对象转换为数组:
function convertToArray(nodes){
var array = null;
try
{
array = Array.propotype.slice.call(nodes,0);//非IE浏览器
}
catch(ex)
//由于IE8 及更早版本将NodeList实现为一个COM 对象,而我们不能像使用JScript 对象那样使用这种对象,因此上面的代码会导致错误。要想在IE 中将NodeList 转换为数组,必须手动枚举所有成员
{
array = new Array();
for(var i=0,len=nodes.length; i<len ;i++)
{
array.push(nodes[i]);
}
}
return array;
}
- 一般来说,应该尽量减少访问NodeList 的次数。因为每次访问NodeList,都会运行一次基于文档的查询。所以,可以考虑将从NodeList 中取得的值缓存起来。
每个节点都包含的属性&方法
- childNodes 属性:其中保存着一个NodeList 对象。
包含childNodes 列表中的每个节点相互之间都是同胞节点。 - parentNode属性,该属性指向文档树中的父节点
- previousSibling和nextSibling属性
- 父节点的firstChild 和lastChild
- ownerDocument,该属性指向节点所在的文档节点。任何节点都不能同时存在于两个或更多个文档中。
- childElementCount:返回子元素节点(不包括文本节点和注释)的个数。
- firstElementChild:指向第一个子元素节点;
- lastElementChild:
- previousElementSibling:
- nextElementSibling:
- 遍历元素节点
child = element.firstElementChild;
while(child!=element.lastElementChild)
{
//处理child
child = child.nextElementSibling;
}
-
hasChildNodes() 在节点包含子节点的情况下返回true;
-
appendChild() ,返回新增的节点
如果传入到appendChild()中的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置。
-
insertBefore( 要插入的节点,作为参照的节点 ),返回被插入的节点。
如果参照节点是null,则insertBefore()与appendChild()执行相同的操作。 -
replaceChild( 要插入的节点,要替换的节点 ) ,返回要替换的节点。
-
removeChild() ,返回被移除的节点。
-
cloneNode( 是否深拷贝 ),创建调用这个方法的节点的一个副本。
参数为true的情况下,执行深复制,复制节点及其整个子节点树;
参数为false 的情况下,执行浅复制,只复制节点本身。
cloneNode()方法不会复制添加到DOM 节点中的JavaScript 属性,例如事件处理程序等。这个方法只复制特性子节点,其他一切都不会复制。IE 在此存在一个bug,即它会复制事件处理程序,所以我们建议在复制之前最好先移除事件处理程序。 -
normalize(),处理文本节点。当在某个节点上调用这个方法时,就会在该节点的后代节点中查找。
如果找到了空文本节点,则删除它;
如果找到相邻的文本节点,则将它们合并为一个文本节点。
Firefox 3.6+和Chrome支持的classList 属性
- add(value):将给定的字符串值添加到列表中。如果值已经存在,就不添加了。
contains(value):表示列表中是否存在给定的值
remove(value):
toggle(value):
function contains(refNode, otherNode)
{
if (typeof refNode.contains == "function" &&
(!client.engine.webkit || client.engine.webkit >= 522))
{
return refNode.contains(otherNode);
} else if (typeof refNode.compareDocumentPosition == "function")
{
return !!(refNode.compareDocumentPosition(otherNode) & 16);
} else
{
var node = otherNode.parentNode;
do
{
if (node === refNode)
{
return true;
} else
{
node = node.parentNode;
}
} while (node !== null);
文档节点
- document 对象是window 对象的一个属性,因此可以将其作为全局对象来访问。
属性
document.documentElement //<html>
document.body //<body>
document.title //<title>中的文本,可以读取、修改,但不会影响<title>元素???
referrer
以下3个属性中的信息都存在于请求的HTTP 头部
document.URL //取得完整的URL
document.domain //取得域名
document.referrer //保存着链接到当前页面的那个页面的URL。
- URL/domain/referrer
- 只有domain 是可以设置的。并非可以给domain 设置任何值。如果URL 中包含一个子域名,例如p2p.wrox.com,那么就只能将domain 设置为"wrox.com",不能将这个属性设置为URL 中不包含的域。
如果域名一开始是“松散的”(wrox.com),那么不能将它再设置为“紧绷的”(p2p.wrox.com)。 - 当页面中包含来自其他子域的框架或内嵌框架时,能够设置 document.domain 就非常方便了。由于跨域安全限制, 来自不同子域的页面无法通过JavaScript 通信。而通过将每个页面的document.domain 设置为相同的值,这些页面就可以互相访问对方包含的JavaScript 对象了
document.activeElement 属性
//这个属性始终会引用DOM 中当前获得了焦点的元素。元素获得焦点的方式有页面加载、用户输入(通常是通过按Tab 键)和在代码中调用focus()方法。
- 文档刚刚加载完成时,document.activeElement 中保存的是document.body 元素的引用。文档加载期间,document.activeElement 的值为null。
document.readyState //值有两个:loading,正在加载文档;complete,已经加载完文档
document.compatMode //浏览器采用的渲染模式。在标准模式下,值等于"CSS1Compat",在混杂模式下,值等于"BackCompat"
document.charset //文档中实际使用的字符集,也可以用来指定新字符集
HTMLCollection 对象,与NodeList 非常类似。
collection.length
collection.item(1)//按索引访问
collection[1]
collection.namedItem("name")//按名称访问
collection["name"]
以下都是HTMLCollection 对象:
document.anchors //包含文档中所有带name 特性的<a>元素;
document.forms //包含文档中所有的<form>元素
document.images //包含文档中所有的<img>元素
document.links //包含文档中所有带href 特性的<a>元素。
- document.hasFocus() //用于确定文档是否获得了焦点。
通过检测文档是否获得了焦点,可以知道用户是不是正在与页面交互。 - document.createElement( 标签名 )//创建元素节点
- document.createTextNode( 文本 )//创建文本节点
- document.createDocumentFragment() //创建文档片段
document和HTML元素都存在的
- getElementById() 如果页面中多个元素的ID 值相同,只返回文档中第一次出现的元素。
- getElementsByTagName() //返回HTMLCollection 对象
- getElementsByName() //返回HTMLCollection 对象
- getElementByClassName( 包含一个或多个类名的字符串 )
类名以空格分隔,类名的顺序不重要
document、Element对象、DocumentFragment对象都存在的:
根据CSS选择符选择DOM元素
- querySelector( CSS 选择符 ) 返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null。
- querySelectorAll( CSS 选择符 ),返回所有匹配的元素。一组元素的快照,而非不断对文档进行搜索的动态查询。
检测浏览器实现了DOM的哪些部分
document.implementation.hasFeature("要检测的DOM 功能的名称","版本号");
//如果浏览器支持给定名称和版本的功能,则该方法返回true
- 但返回true有时候也不意味着实现与规范一致。建议多数情况下,在使用DOM 的某些特殊的功能之前,最好除了检测hasFeature()之外,还同时使用能力检测。
document.write()//会原样输出,包含</script>时需要转义--<\/script>
document.writeln()
document.open()
document.close()
//方法open()和close()分别用于打开和关闭网页的输出流。如果是在页面加载期间使用write()或writeln()方法,则不需要用到这两个方法。
Element类型
- tagName / nodeName:元素标签名
在比较之前要将标签名转换为相同的大小写形式
element.tagName.toLowerCase() == "div"
-
HTML元素对象添加了以下属性分别对应于每个HTML元素中都存在的标准特性。
id
title
className 与元素的class特性对应 -
children 只包含元素中同样还是元素节点的子节点,IE8 及更早版本的children 属性中也会包含注释节点
操作特性:
- 以下三个方法可以针对任何特性使用,包括那些以HTMLElement 类型属性的形式定义的特性
getAttribute() //如果给定名称的特性不存在,返回null;
也可以取得自定义特性;自定义特性应该加上data-前缀以便验证。
setAttribute()
removeAttribute():不仅会清除特性的值,而且也会从元素中完全删除特性。 - 可以通过DOM 元素本身的属性来操作,但不能操作自定义特性
(访问自定义特性会返回undefined,设置自定义特性不会生效) - dataset 属性来访问自定义属性(data-开头)的值。在这个映射中,每个data-name 形式的属性名都会有一个对应的属性值,只不过属性名没有data-前缀。[Firefox 6+和Chrome支持]
//取得自定义属性的值
var appId = div.dataset.appId;
//设置值
div.dataset.appId = 23456;
- attributes属性:attributes 属性中包含一系列节点,每个节点的nodeName 就是特性的名称,而节点的nodeValue就是特性的值。
attributes属性拥有下列方法
getNamedItem(name):返回nodeName 属性等于name 的节点;
也可以用[name]取代
removeNamedItem(name):从列表中移除nodeName 属性等于name 的节点;
setNamedItem(node):向列表中添加节点,以节点的nodeName 属性为索引???; 可以用[name]取代
item(pos):返回位于数字pos 位置处的节点。
var id = element.attributes.getNamedItem("id").nodeValue;
element.attributes["id"].nodeValue = "someOtherId";
常用attributes属性遍历元素特性
function outputAttributes(element){
var array = new Array(),
name,
value
i,
len;
for(i=0, len=element.attributes.length; i<len; i++)
{
name=element.attributes[i].nodeName;
value=element.attributes[i].nodeValue;
if (element.attributes[i].specified) //这个属性的值如果为true,则意味着要么是在HTML 中指定了相应特性,要么是通过setAttribute()方法设置了该特性。为了兼容IE7
{
array.push(name + "=\"" + value + "\"");
}
}
return array.join(" ");
开发人员经常不使用getAttribute(),而只使用对象的属性。只有在取得自定义特性值的情况下,才会使用getAttribute()方法。
- 属性的值与通过getAttribute()返回的值不相同:
- style: 在通过getAttribute()访问时,返回值中包含的是CSS 文本,而通过属性来访问它则会返回一个对象。
- 事件处理程序。通过getAttribute()访问,则会返回相应代码的字符串。而在访问onclick 属性时,则会返回一个JavaScript 函数(如果未在元素中指定相应特性,则返回null)
创建元素
- document.createElement( 标签名 ) 可以创建新元素。
- 在IE中可以为这个方法传入完整的元素标签,也可以包含属性
插入HTML标记内容
- innerHTML 属性
- 在读模式下,innerHTML 属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的HTML 标记。
- 在写模式下,innerHTML 会根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。会自动HTML转义字符串。
- 在大多数浏览器中,通过innerHTML 插入<script>元素并不会执行其中的脚本
- 大多数浏览器都支持以直观的方式通过innerHTML 插入<style>元素,
IE8及更早版本中
div.innerHTML = "<input type=\"hidden\"><style type=\"text/css\">body {background-color: red; }</style>";
-
不支持innerHTML 的元素有:<col>、<colgroup>、
<frameset>、<head>、<html>、<style>、<table>、<tbody>、
<thead>、<tfoot>和<tr>。在IE8 及更早版本中,<title>元素也没有innerHTML 属性。 -
outerHTML 属性
-
在读模式下,outerHTML 返回调用它的元素及所有子节点的HTML 标签。
-
在写模式下,outerHTML会根据指定的HTML 字符串创建新的DOM 子树,然后用这个DOM子树完全替换调用元素。
-
Firefox 7 及之前版本都不支持outerHTML 属性。
-
最好的做法是单独构建字符串,然后再一次性地将结果字符串赋值给innerHTML、outerHTML
var itemsHtml = "";
for (var i=0, len=values.length; i < len; i++)
{
itemsHtml += "<li>" + values[i] + "</li>";
}
ul.innerHTML = itemsHtml;
-
insertAdjacentHTML( 插入位置,要插入的HTML 文本 )
插入位置必须是下列值之一:
“beforebegin”,在当前元素之前插入一个紧邻的同辈元素;
“afterbegin”,在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
“beforeend”,在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;
“afterend”,在当前元素之后插入一个紧邻的同辈元素。 -
在删除带有事件处理程序或引用了一个JavaScript 对象作为属性的元素,就有可能导致内存占用问题。在使用上述某个属性将该元素从文档树中删除后,元素与事件处理程序(或JavaScript 对象)之间的绑定关系在内存中并没有一并删除。
因此,在使用innerHTML、outerHTML 属性和insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理程序和JavaScript 对象属性。
- matchesSelector( CSS 选择符 ) 如果调用元素与该选择符匹配,返回true;否则,返回false
- IE 9+通过msMatchesSelector() 支持该方法,
Firefox 3.6+通过mozMatchesSelector() 支持该方法,
Safari 5+和Chrome 通过**webkitMatchesSelector()**支持该方法
function matchesSelector(element, selector)
{
if (element.matchesSelector)
{
return element.matchesSelector(selector);
} else if (element.msMatchesSelector)
{
return element.msMatchesSelector(selector);
} else if (element.mozMatchesSelector)
{
return element.mozMatchesSelector(selector);
} else if (element.webkitMatchesSelector)
{
return element.webkitMatchesSelector(selector);
} else
{
throw new Error("Not supported.");
}
}
插入文本
- innerText
- 在通过innerText 读取值时,它会按照由浅入深的顺序,将子文档树中的所有文本拼接起来。
- 在通过innerText 写入值时,结果会删除元素的所有子节点,插入包含相应文本值的文本节点。自动对文本中存在的HTML 语法字符(小于号、大于号、引号及和号)进行了编码。
- 可以通过innerText 属性过滤掉HTML 标签。
div.innerText = div.innerText;
- Firefox 虽然不支持innerText,但支持作用类似的textContent 属性。
function getInnerText(element)
{
return (typeof element.textContent == "string") ?element.textContent : element.innerText;
}
function setInnerText(element, text)
{
if (typeof element.textContent == "string")
{
element.textContent = text;
} else
{
element.innerText = text;
}
}
- innerText 会忽略行内的样式和脚本,而textContent 则会像返回其他文本一样返回行内的样式和脚本代码。避免跨浏览器兼容问题的最佳途径,就是从不包含行内样式或行内脚本的DOM 子树副本或DOM片段中读取文本
Text类型
- 文本节点可以包含转义后的HTML 字符,但不能包含HTML 代码
- nodeValue / data 属性:访问Text 节点中包含的文本
设置这个属性的值时,字符串会自动经过HTML(或XML,取决于文档类型)编码。 - length属性:保存着节点中字符的数目。nodeValue.length 和data.length 中也保存着同样的值。
- appendData(text):将text 添加到节点的末尾。
deleteData(offset, count):从offset 指定的位置开始删除count 个字符。
insertData(offset, text):在offset 指定的位置插入text。
replaceData(offset, count, text):用text 替换从offset 指定的位置开始到offset+count 为止处的文本。
splitText(offset):从offset 指定的位置将当前文本节点分成两个文本节点。原来的文本节点将包含从开始到指定位置之前的内容,新文本节点将包含剩下的文本。返回新文本节点。
分割文本节点是从文本节点中提取数据的一种常用DOM 解析技术。
substringData(offset, count):提取从offset 指定的位置开始到offset+count 为止处的字符串。
创建文本节点
- document.createTextNode( 文本 ) 创建新文本节点,作为参数的文本也将自动按照HTML 或XML 的格式进行编码。
DocumentFragment类型
- 文档片段可以作为一个“仓库”来使用,即可以在里面保存将
来可能会添加到文档中的节点。 - document.createDocumentFragment( 无参数 ) //创建文档片段
- 假设我们想为这个
- 元素添加3 个列表项。如果逐个地添加列表项,将会导致浏览器反复渲染新信息。为避免这个问题,可以像下面这样使用一个文档片段来保存创建的列表项,然后再一次性将它们添加到文档中。
var fragment = document.createDocumentFragment(),
ul = document.getElementById("myList"),
li = null;
for(var i=0; i<3; i++)
{
li = document.createElement("li");
li.appendChild(document.createTextNode("Item"+i));
fragment.appendChild(li);
}
ul.appendChild(fragment);
动态创建脚本
function loadScriptString(code)
{
var script = document.createElement("script");;
try
{
script.appendChild(document.createTextNode(code));
}
catch(ex)
{
script.text = code;//IE中不能访问<script>节点的子节点
}
document.body.appendChild(script);
}
- 这样执行代码与在全局作用域中把相同的字符串传递给eval()是一样的。
动态样式
function loadStyleString(css)
{
var style = document.createElement("style");
try
{
style.appendChild(document.createTextNode(css));
}
catch(ex)
{
style.styleSheet.cssText = css;
}
var head = document.getElementsByTagName("head")[0];
head.appendChild(style);
}
- 如果专门针对IE 编写代码,务必小心使用styleSheet.cssText 属性。在重用同一个<style>元素并再次设置这个属性时,有可能会导致浏览器崩溃。同样,将cssText 属性设置为空字符串也可能导致浏览器崩溃。
操作表格
- DOM为<table>元素添加的属性和方法如下。
caption:保存着对<caption>元素(如果有)的指针。
tBodies:是一个<tbody>元素的HTMLCollection。
tFoot:
tHead:
rows:是一个表格中所有行的HTMLCollection。
createTHead():创建元素,将其放到表格中,返回引用。
createTFoot():
createCaption():
deleteTHead():
deleteTFoot():
deleteCaption():
deleteRow(pos):删除指定位置的行。
insertRow(pos):向rows 集合中的指定位置插入一行。 - 为<tbody>元素添加的属性和方法如下:
rows:保存着<tbody>元素中行的HTMLCollection。
deleteRow(pos):删除指定位置的行。
insertRow(pos):向rows 集合中的指定位置插入一行,返回对新插入行的引用。 - 为<tr>元素添加的属性和方法如下:
cells:保存着<tr>元素中单元格的HTMLCollection。
deleteCell(pos):删除指定位置的单元格。
insertCell(pos):向cells 集合中的指定位置插入一个单元格,返回对新插入单元格的引用。
var tbody = document.createElement("tbody");
table.appendChild(tbody);
//创建第一行
tbody.insertRow(0);
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode("Cell 1,1"));
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode("Cell 2,1"));
//创建第二行
tbody.insertRow(1);
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 1,2"));
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2,2"));
//将表格添加到文档主体中
document.body.appendChild(table);