10 Dom

1 节点层次

文档元素:文档的最外层元素,文档中所有其它元素都包含在文档元素中,一个文档中只能有一个文档元素。HTML文档的文档元素始终是<html>
DOM树:总共有12种节点类型

序号 类型 说明
1 element_node 元素节点
2 attribute_node 属性节点
3 text_node 文本节点
4 cdata_section_node CDATA片段
5 entity_reference_node 实体引用
6 entity_node 实体
7 processing_instruction_node 处理指令
8 comment_node 注释节点
9 document_node 文档节点
10 document_type_node
11 document_fragment_node
12 notation_node
1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html lang="en">
<head>
<title>SimplePage</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>

91A4B32B-788D-402E-BB53-87C0ADE3E9A1

1.1 Node类型

历史:DOM1 定义的 Node 接口的 JS 实现类 Node

nodeType 属性:JS 的所有节点类型都继承自 Node 类型,因此所有的节点类型都共享着相同的基本属性和方法。

等价的数字(兼容所有浏览器) Nodetype对应的常量(IE中不存在)
1 Node.ELEMENT_NODE
2 Node.ATTRIBUTE_NODE
3 Node.TEXT_NODE
4 Node.CDATA_SECTION_NODE
5 Node.ENTITY_REFERENCE_NODE
6 Node.ENITY_NODE
7 Node.PROCESSING_INSTRUCTION_NODE
8 Node.COMMENT_NODE
9 Node.DOCUMENT_NODE
10 Node.DOCUMENT_TYPE_NODE
11 Node.DOCUMENT_FRAGMENT_NODE
12 Node.NOTATION_NODE
1
2
3
4
// 判断节点类型
if(someNode.nodeType == 1){//兼容所有浏览器
alert('Node is an element!');
}

nodeName 和 nodeValue 属性

取值情况取决于节点类型

节点关系

childNodes属性

1
2
☑︎ 值:NodeList对象,一个类数组对象,用于保存一组有序的节点,可以通过位置访问这些节点。
☑︎ 特点:基于DOM结构动态查询
1
2
3
var firstChild = someNode.childnodes[0];
var secondChild = someNode.childnodes.item(1);
var count = someNode.childNodes.length;

将NodeList转换为数组

1
2
3
4
5
6
7
8
9
10
11
function convertToArray(nodes){
var array = null;
try{
array = Array.prototype.slice.call(nodes);
}catch(e){
for(var i = 0, len = nodes.length; i < len; i++){
array.push(nodes[i]);
}
}
return array;
}

parentNode属性

1
2
☑︎ 值:指向文档树中的父节点
☑︎ 特点:包含在childNodes列表中的所有节点都具有相同的父节点

firstChild属性

1
2
☑︎ 值:指向childNodes列表中的第一个节点
☑︎ 特点:相当于someNode.childNodes[0]

lastChild属性

1
2
☑︎ 值:指向childNodes列表中最后一个节点
☑︎ 特点:没有指向的节点值为null

previousSibling属性

1
2
☑︎ 值:指向同一childNodes列表中的上一个节点。
☑︎ 特点:没有指向的节点值为null

nextSibling属性

1
2
☑︎ 值:指向同一childNodes列表中的下一个节点。
☑︎ 特点:没有指向的节点值为null
1
2
3
4
5
if(someNode.nextSibling === null){
alert('最后一个节点');
}else{
alert('第一个节点');
}

A9518300-5B03-4EE5-A244-0DBE0A710CFD

ownerDocument属性

1
2
☑︎ 值:指向整个文档的文档节点
☑︎ 特点:通过这个属性就不用层层回溯达到顶端了

hasChildNodes()方法

1
2
☑︎ 返回值:节点包含子节点时返回true;否则返回false
☑︎ 要点:比查询childNodes属性的length值更简单好用

操作节点(必需先取得父节点,如果节点类型没有子节点将会出错)

appendChild()方法

1
2
3
4
☑︎ 用途:向childNodes列表的末尾添加一个节点,相关节点的关系指针都会相应得到更新。
☑︎ 参数:新创建的节点或文档树中的节点。
☑︎ 返回值:新增的节点
☑︎ 注意:任何DOM节点不能同时出现在多个位置,如果插入的节点本身就是DOM树上的,将会移动到新的位置。
1
2
3
var returnode  = someNode.appendChild(newNode);
alert(returnNode == newNode); //true
alert(someNode.lastChild == newNode); //true

insertBefore()方法

1
2
3
☑︎ 用途:将节点放在childNodes列表中某个特定的位置上。
☑︎ 参数(2):要插入的节点、作为参照的节点。
☑︎ 返回值:插入的新节点
1
2
3
4
5
6
7
8
9
//插入后成为最后一个子节点
var returnNode = someNode.insertBefore(newNode,null);
alert(newNode == someNode.lastChild);
//插入后成为第一个子节点
var returnNode = someNode.insertBefore(newNode,someNode.firstChild);
alert(newNode == someNode.firstNode);
//插入到最后一个子节点前面
var returnNode = someNode.insetBefore(newNode,someNode.lastNode);
alert(newNode == someNode.lastNode);

replaceChild()方法

1
2
3
4
☑︎ 用途:替换某个节点
☑︎ 参数(2):要插入的节点、要替换的节点
☑︎ 返回值:被替换(移除)的节点
☑︎ 注意:被替换的节点任然是文档的一部分,只是没有自己的位置
1
2
3
4
//替换第一个子节点
var returnNode = someNode.replaceChild(newCode, someNode.firseChild);
//替换最后一个子节点
returnNode = someNode.replaceChild(newCode, someNode.lastChild):

removeChild()方法

1
2
3
4
☑︎ 用途:移除节点
☑︎ 参数:要移除的节点
☑︎ 返回值:被移除的节点
☑︎ 注意:被替换的节点仍然是文档的一部分,只是没有自己的位置
1
2
//移除第一个子节点
var formerFirstChild = someNode.removeChild(someNode.firstCihld);

其它方法(所有类型节点都有)

cloneNode()

1
2
3
4
☑︎ 用途:创建一个节点的副本
☑︎ 参数:true表示深拷贝(递归子节点);false表示浅拷贝(不拷贝子节点)
☑︎ 返回值:节点副本
☑︎ 注意:返回的节点贵文档所有,但是是没有父节点的孤儿;IE9之前的版本会为空白创建节点;IE会同时复制事件处理程序/
1
2
3
4
5
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
1
2
3
4
var deepList = myList.cloneNode(true);
console.log(deepList.childNodes.length); //3(IE<9)或 7(其它浏览器)
var shallowList = myList.cloneNode(false);
console.log(shallowList.childNodes.length); //0

normalize()方法

1
2
☑︎ 用途:处理文档树中的文本节点,删除空文本节点,合并相邻文本节点
☑︎ 参数:父节点

1.2 Document类型

  • Document 类型
1
☑︎ JS通过该类型表示文档
  • HTMLDocument 类型
1
☑︎ 继承自Document类型,表示HTML文档
  • document对象
1
2
☑︎ HTMLDocuemnt类型的一个实例
☑︎ window对象的属性

Document 节点特征

序号 属性
1 nodeType 0
2 nodeName #document
3 nodeValue null
4 parentNode null
5 ownerDocument null
6 childNodes 最多一个DocumentType、Element或多个ProcessingInstruction、Comment

兼容性
| 类型 | 支持访问构造函数和原型 |
| ———— | ——————— |
| Document | FF、Safri、Chrome、Opera |
| HTMLDocument | 所有 |

1.2.1 文档的子节点

body 节点

  • document.documentElement(推荐)
  • document.childNodes[0]
  • document.firstChild
  • document.body
1
2
3
<html>
<body></body>
</html>
1
2
3
4
var html = document.documentElement;    //取得对<html>的引用
alert(html === document.childNodes[0]); //true
alert(html === docuemnt.firstChild); //true
alert(html === document.body); //true

document.docType

说明:访问<!DOCTYPE>节点

版本 处理方式 document.docType
IE8- 解释为注释并把它作为Comment节点 null
IE9+、FF 作为文档的第一个子节点 DocumentType节点(也可以通过firstChid和childNodes[0]访问到)
Safari、Chrome、Opera 不作为文档子节点,不会出现在document.childNodes中 DocumentType节点
1
var docType = docuemnt.doctype;    //取得对<!DOCTYPE>的引用

<html>之外的注释

1
2
3
4
5
<!-- 第一条注释 -->
<html>
<body></body>
</html>
<!-- 第二条注释 -->
版本 处理方式 节点类型
IE8-、Safari3.1+、Opera、Chrome 只为第一条注释创建注释节点 注释节点,document.childNodes中的第一个节点
IE9+ 为两条注释分别创建注释节点 注释节点,document.childNodes中的节点
FF、Safari3.1- 完全忽视这两条注释

1.2.2 文档信息

HTMLDocument 的实例 document 包含的 Document 对象没有的属性。

document.title属性

1
2
3
☑︎ 作用:可以取得当前页面的标题,也可以修改当前页面的标题并反映在浏览器的标题栏。
☑︎ 值:<title>元素中的文本,显示在浏览器窗口的标题栏或标题页上。
☑︎ 特点:修改该属性不会改变<title>属性

1
2
3
4
//取得文档标题
var originalTitle = document.title;
//设置文档标题
document.title = 'new page title';

document.URL属性

1
2
3
☑︎ 作用:取得页面完整的URL
☑︎ 值:地址栏中显示的URL
☑︎ 特点:只读

document.domain属性

1
2
3
☑︎ 作用:取得页面的域名或通过改变页面中包含的来自其它子域框架或内嵌框架的domain实现跨域通信
☑︎ 值:页面的域名
☑︎ 特点:可写,由于跨域安全限制,不可设置为URL不包含的域,,即只能设置为父域;一旦设置为“的“松散的”就不能设置回”紧绷的“(IE7-除外)。
1
2
3
//假设页面来自www.wrox.com
document.domain = 'wrox.com';
document.domain = 'www.wrox.com';//出错!

docuemnt.referrer属性

1
2
3
☑︎ 作用:取得链接到当前页面的那个页面的URL
☑︎ 值:链接到当前页面的那个页面的URL,可能包含空字符串
☑︎ 特点:只读
1
2
3
4
5
6
//取得完整的URL
var url = document.URL;
//取得域名
var domain = document.demain;
//取得来源页面的URL
var referrer = dicument.referrer;

1.2.3 查找元素

getElementById()方法

1
2
3
☑︎ 用途:通过ID获得元素
☑︎ 参数:要取得元素的ID,区分大小写
☑︎ 返回值:存在返回相应ID元素;否则返回null

注意

1
2
3
☑︎ IE7-不区分大小写
☑︎ 页面中多个ID相同的元素只返回第一个
☑︎ IE7-怪癖:name值匹配的表单元素(input、textarea、button、select)也会被该方法返回,因此注意不让表单字段的name和其它元素ID相同

getElementByTagName()方法

1
2
3
4
☑︎ 用途:通过标签名获得元素集合
☑︎ 参数:标签名
☑︎ 返回值:HTMLCollection对象,类似NodeList
☑︎ 注意:传入”*“作为参数可以返回所有元素,IE会返回所有注释节点
1
<img src="myimage.gif" name="myimage">
1
2
3
4
var images = document.getElementByTagName('img'); //取得所有图像的集合
console.log(images.length); //输出图像的数量
console.log(images[0].src); //输出第一个图像元素desrc属性
console.log(images.item(0).src);

HTMLCollection 对象

☑︎ namedItem() 方法

1
2
3
4
☑︎ 用途:通过元素的name特性取得集合中的项
☑︎ 参数:元素的name属性值
☑︎ 返回值:元素
☑︎ 注意:可以替换为使用方括号语法
1
2
3
var myImage = images.namedItem('myImage');

var myImage = images['myImage'];

getElementsByName()

1
2
3
4
☑︎ 用途:返回给定name特性的所有元素
☑︎ 参数:元素的name
☑︎ 返回值:HTMLCollection类型
☑︎注意:返回值使用namedItem()只能获得第一项
1
2
3
4
5
6
7
8
9
10
11
12
13
<fieldset>
<legend>Which color do you prefer?</legend>
<ul>
<li>
<input type="radio" value="red" name="color" id="colorRed">
<label for="color"></label>
<input type="radio" value="green" name="color" id="colorGreen">
<label for="color"></label>
<input type="radio" value="blue" name="color" id="colorBlue">
<label for="color"></label>
</li>
</ul>
</fieldset>
1
var radios = document.getElementsByName('color');

1.2.4 特殊集合(HTMLCollection)

特点:会随着文档的更新而更新
| 集合 | 说明 | 备注 |
| —————- | —————- | —————————————- |
| document.anchors | 文档中所有带name特性的a元素 | |
| document.applets | 文档中所有applet元素 | 不建议使用 |
| document.forms | 文档中所有form元素 | document.getElementByTagName(“form”)得到相同结果 |
| document.images | 文档中所有img元素 | document.getElementByTagName(“img”)得到相同结果 |
| document.lnks | 文档中所有带href特性的a元素 | |

1.2.5 DOM一致性检测

document.implementation属性

可用于检测浏览器实现了DOM的哪些部分

document.implementation.hasFeature()

1
2
3
4
☑︎ 参数(2):要检测的DOM功能的名称、版本号
☑︎ 返回值:支持返回true;否则返回false
☑︎ 问题:返回true并不意味着实现和规范完全一致
☑︎ 注意:同时使用能力检测
1
var hasXmlDom = document.implementation.hasFeature("XML","1.0");

C8E4D61B-9AE3-48A2-9BFD-D6D3907A1DE5

1.2.6 文档写入

1
2
3
不支持文档写入的情况
☑︎ 严格型 XHTML 文档
☑︎ 按照 application/xml+xhtml 内容类型提供的页面

document.write()

1
2
3
4
☑︎ 用途:原样写入输出流到文本
☑︎ 参数:字符串
☑︎ 注意:加载文档阶段调用直接向其中输出内容;加载结束后调用会重写整个页面,而且需要自己打开/关闭输出流
,关闭输出流后才会将内容添加进文档。

document.writeln()

1
2
3
☑︎ 用途:写入输出流到文本,会自动在字符串的末尾添加一个换行符(\n)
☑︎ 参数:字符串
☑︎ 注意:加载文档阶段调用直接向其中输出内容;加载结束后调用会重写整个页面,而且需要自己打开/关闭输出流。

document.open()

1
2
☑︎ 用途:HTML 文档加载完后使用,用来打开网页输出流
☑︎ 注意:会导致之前 body 中的所有内容被删除

document.close()

1
2
☑︎ 用途:关闭输出流
☑︎ 注意:open() 和 close() 之间执行的 write() 会依次往后插入到 body 中

1.3 Element类型

节点特征

序号 属性
1 nodeType 1
2 nodeName 元素的标签名
3 nodeValue null
4 parentNode Document或Element
5 childNodes Element、Text、Comment、ProcessingInstruction、CDATASection或EntityReference

属性

☑︎ nodeName属性

1
值:标签名

☑︎ tagName属性

1
值:标签名,比nodeName更清晰
1
<div id="myDiv"></div>
1
2
3
var div = document.getElementById('myDiv');
alert(div.tagName); //DIV
alert(div.tagName == div.nodeName); //true

注意:大小写(HTML中标签名始终都以全部大写表示;XML(XHTML)中与源代码一致)

1
2
3
if(element.tagName.toLowerCase() == 'div'){
//在此执行某些操作
}

兼容性
| 浏览器版本 | 行为 |
| —————- | ———————- |
| safari2-、Opera8- | 不能访问Element类型的构造函数 |
| 其它 | 可以访问Element类型的构造函数及其原型 |

1.3.1 HTML元素

属性 说明
id 元素在文档中的唯一标识符
title 有关元素的附加说明信息,一般通过工具提示条显示出来
lang 元素内容的语言代码,很少使用
dir 语言的方向,“ltr”(从左到右);“rtl”(从右到左)
className 为元素指定的CSS类(没有使用class,因为是保留字)
1
<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
1
2
3
4
5
6
var div =  document.getElementById("myDiv");
console.log(div.id); //"myDiv"
console.log(div.className); //"bd"
console.log(div.title); //"Body text"
console.log(div.lang); //"en"
console.log(div.dir); //"ltr"

所有HTML元素都是由 HTMLElement 或更具体的子类型来表示(斜体指不推荐):

CE9F1E79-0245-4A66-BEBF-3B83927813DD

2D7C17AF-ABB5-45AE-9CEE-AD6E7EC1105F

1.3.2 取得特性

getAttribute() 方法

1
2
3
4
☑︎ 用途:获得特性值(推荐只在获得自定义特性时使用)
☑︎ 参数:元素的属性,不区分大小写
☑︎ 返回值:属性不存在返回null
☑︎ 注意:自定义属性也有效,但只有公认的(非自定义的)属性才能在DOM对象中找到对应属性(IE除外)
1
<div id="myDiv" class="bd"  title="Body text" lang="en" dir="ltr" my_special_attribute="hello"></dvi>
1
2
3
4
5
6
7
8
9
10
var div = document.getElementById("myDiv");
console.log(div.getAttribute("id")); //"myDiv"
console.log(div.getAttribute("class")); //"bd"
console.log(div.getAttribute("title")); //"Body text"
console.log(div.getAttribute("lang")); //"en"
console.log(div.getAttribute("dir")); //"ltr"
替代:DOM本身的属性(自定义特性无法访问)
console.log(div.id); //"myDiv"
console.log(div.my_special_attribute); //"undefined"(IE除外)
console.log(div.align); //“left”

特殊特性
☑ ︎style属性

访问方式 返回值
div.getAttribute(“style”) CSS文本
div.style 对象

☑︎ 事件处理程序
| 访问方式 | 返回值 |
| ————————— | —– |
| div.getAttribute(“onclick”) | 代码字符串 |
| div.onclick | 函数 |

1.3.3 设置特性

setAttribute()方法

1
2
3
☑︎ 用途:设置或创建特性值(可以自定义,HTML5要求data_前缀)
☑︎ 参数(2):要设置的特性名、值
☑︎ 注意:特性名会同意被转成小写;IE7-有异常
1
2
3
4
5
div.setAttribute("id",  "sometherId");
div.setAttribute("class", "ft");
div.setAttribute("title", "some other text");
div.setAttribute("lang", "fr");
div.setAttribute("dir", "rtl");

removeAttribute()方法

1
2
3
4
☑︎ 用途:彻底删除元素的特性
☑︎ 参数:特性名
☑︎ 特点:不常用
☑︎ 兼容性:IE6-不支持

1.3.4 attributes属性

1
2
3
☑︎ 用途:包含元素的特性,适合用来遍历元素的特性
☑︎ 特点:Element节点独有
☑︎ 值:NamedNodeMap(类似NodeList)

NamedNodeMap对象

☑︎ getNameItem(name): 返回nodeName属性等于name的节点

1
2
3
var id = element.attributes.getNamedItem("id").nodeVlaue;

var id = element.attributes['id'].nodeValue;

☑︎ removeNamedItem(name): 从列表中移除 nodeName 属性等于 name 的节点

1
var oldAttr = element.attributes.removeNamedItems("id");

☑︎ setNamedItem(node): 向列表中添加节点,以节点的 nodeName 属性为索引

1
element.attributes.setNamedItem(newAttr);

☑︎ item(pos): 返回位于数字pos位置处的节点

遍历attributes
方式一:全部遍历

1
2
☑︎ 不能保证 attributes 中属性出现的顺序
☑︎ IE7-会返回元素所有的属性,包括未设定的
1
2
3
4
5
6
7
8
9
10
11
12
13
function outputAttributes(element){
var paris = new Array(),
attrName,
attrValue,
i,
len;
for(i=0,len=element.attrbutes.length; i<len;i++){
attrName = element.attributes[i].nodeName;
attrValue = element.attrbutes[i].nodeValue;
pairs.push(attrNames + "=\" ""+attrValue+"\"");
}
return pairs.join(" ");
}

方式二:只遍历设置了值的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function outputAttributes(element){

var paris = new Array(),
attrName,
attrValue,
i,
len;
for(i=0,len=element.attrbutes.length; i<len;i++){
attrName = element.attributes[i].nodeName;
attrValue = element.attrbutes[i].nodeValue;
if(eleement.attributes[i].specified){
pairs.push(attrNames + "=\" ""+attrValue+"\"");
}
}
return pairs.join(" ");
}

1.3.5 创建元素

document.createElement()方法

1
2
3
4
☑︎ 用途:创建节点(会同时设置ownerDocument)
☑︎ 参数:标签名(HTML中不区分大小写;XML和XHTML中区分),IE允许传入完整的元素标签
☑︎ 返回值:创建的节点
☑︎ 注意:将新元素添加到DOM树种才会影响浏览器的显示
1
2
3
4
var div = document.createElement('div');
div.id = "myNewDiv";
div.className = "box";
document.body.appendChild(div);

☑︎ 附:IE允许传入完整元素标签

用途:通过指定完整的标签,避开IE7-动态创建元素的某些问题(仅在使用标签名作参数给IE7带来问题时使用)

1
2
3
4
☑︎ 不能设置动态创建的 iframe 元素的 name 属性
☑︎ 不能通过表单的 reset()方法重设动态创建的 <input> 元素
☑︎ 动态创建的 type 特性值为 “reset” 的 button 元素无法重设表单
☑︎ 动态创建的一批 name 相同的单选按钮彼此毫无关系
1
2
3
4
5
6
7
8
9
10
11
12
13
var div = document.createElement("<div id='myNewDiv' class='box'></div>");
if(client.bowser.ie && client.browser.ie<=7){

//创建一个带name特性的iframe元素
var iframe = document.createElement("<iframe name=\"myFrame\"></iframe>");
//创建input元素
var input = document.createElement("<input type=\"checkbox\">");
//创建button元素
var button = document.createElement("<button type=\"reset\"></button>");
//创建单选按钮
var radio1 = document.createElement("<input type=\"radio\" name=\"choice\" value=\"1\">");
var radio2 = document.createElement("<input type=\"radio\" name=\"choice\" value=\"1\">");
}

1.3.6 元素的子节点

遍历子节点

问题:IE会将空白符也解析为子节点

1
2
3
4
5
6
<ul id="myList">

<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>

解决:遍历时判断节点的类型

1
2
3
4
5
for(var i=0,len=element.childNodes.length; i< len;i++){
if(element.childNodes[i].nodeType == 1){
//执行某些操作
}
}

通过标签名取得子节点

注意:会递归各个层次获取子节点

1
2
var ul = document.getElementById("myList"):
var items = ul.getElementByTagName("li");

1.4 Text类型

节点特征
| 序号 | 属性 | 值 |
| —- | ———- | ——- |
| 1 | nodeType | 3 |
| 2 | nodeName | #text |
| 3 | nodeValue | 包含的文本内容 |
| 4 | parentNode | Element |
| 5 | childNodes | 不支持子节点 |

重要属性 说明
nodeValue属性、data属性 Text节点中包含的文本
length属性 包含文本的字符的数目(nodeValue.length、data.length)
方法 说明
appendData(text) 将text添加到节点的末尾
deleteDate(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
<div>Hello World!</div>
1
2
var div = docuemnt.getElementByTagName('div')[0];
var textNode = div.firstChild.nodeValue = "Some <strong>other</strong> message";

1.4.1 创建文本节点

document.createTextNode() 方法

1
2
3
☑︎ 用途:创建新文本节点(会同时设置ownerDocument属性)
☑︎ 参数:要插入节点中的文本(会按照HTML或XML的格式进行编码)
☑︎ 注意:只有添加到文档树中后参会被渲染;两个同胞且相邻的文本节点会被连起来显示。
1
2
3
4
5
var element = document.createElement("div");
element.className ="message";
var textNode = document.createTextNode("Hello World!");
element.appendChild(textNode);
document.body.appendChild(element);

1.4.2 规范化文本节点

normalize()方法

1
2
3
☑︎ 调用:定义在Node类型中,所有节点类型都可以调用
☑︎ 用途:合并文本子节点为一个文本子节点
☑︎ 注意:某些情况下IE6会崩溃(已经修复?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//创建父节点
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);
alert(element.childNodes.length); //2
element.normalize();
alert(element.childBodes.length); //1
alert(element.firstChild.nodeValue); //"Hello world!Yippee!"

1.4.3 分割文本节点

spliteText()方法

1
2
3
4
5
☑︎ 调用:定义在Node类型中,所有节点类型都可以调用
☑︎ 用途:按照指定的位置分割nodeValue的值,原来的节点包含从开始到指定位置的文本

☑︎ 参数:分隔文本的位置
☑︎ 返回值:包含指定位置到结尾文本的新文本节点
☑︎ 注意:并不会导致页面有任何变化
1
2
3
4
5
6
7
8
9
var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.append(element);
var newNode = element.firstChild.splitText(5);
console.log(element.firstChild.nodeValue); //"Hello world!"
console.log(newNode.nodeValue); //" world!"
console.log(element.childNodes.length); //2

1.5 Comment类型

节点特征

序号 属性
1 nodeType 8
2 nodeName #comment
3 nodeValue 注释的内容
4 parentNode Docuemnt或Element
5 childNodes 不支持子节点

重要属性

nodeValue、data:取得注释的内容

1
<div id="myDiv"><!--A comment--></div>
1
2
3
var div = document.getElementById("myDiv");
var comment = div.firstChild;
alert(comment.data); //"A comment"

方法

和Text继承自相同基类,拥有除splitText()之外的所有字符串操作方法

document.createComment()方法

1
2
3
☑︎ 用途:创建注释节点
☑︎ 参数:注释字符串
☑︎ 注意:浏览器不识别</html>之后的注释节点

1
var comment = document.createComment("A comment");

兼容性

浏览器 对注释节点的处理 形式
Firefox、Safari、Chrome、Opera Comment 可以访问其构造函数和原型
IE8 标签名为”!”的元素 通过getElementByTagName()访问
IE9 HTMLCommentElement

1.6 CDATASelection类型

节点特征

序号 属性
1 nodeType 4
2 nodeName #cdata-section
3 nodeValue CDATA区域中的内容
4 parentNode Docuemnt或Element
5 childNodes 不支持子节点
1
2


1
2
3
注意
☑︎ 多数浏览器会把CDATA区域错误地解析为Comment或Element
☑︎ 只能出现在XML文档
1
<div id="myDiv">![CDATA[This is some content.]]</div>

方法

document.createCDataSelection()方法

1
2
☑︎ 用途:创建CDATA区域
☑︎ 参数:传入节点的内容

1.7 dcumentType类型

节点特征

序号 属性
1 nodeType 10
2 nodeName doctype的名称
3 nodeValue null
4 parentNode Docuemnt
5 childNodes 不支持子节点

属性

☑︎ name: 文档类型的名称,也就是<!DOCTYPE之后的文本
☑︎ entities: 由文档类型描述的实体的NamedNodeMap对象
☑︎ notations: 由文档类型描述的符号的NamedNodeMap对象

1
2
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

1
alert(document.doctype.name);    //"HTML"

兼容性
| 版本 | 对DocumentType的支持 | document.doctype的值 |
| —- | —————- | —————— |
| IE8- | 不支持 | null |
| IE9 | 不支持 | 正确赋值 |

1.8 docmentFragment 类型

文档片段介绍

☑︎ 说明:只有该类型没有对应的标记。是一种“轻量级”的文档,可以包含并控制节点,但不会像完整的文档那样占用额外的资源。
☑︎ 用途:不能把文档片段直接添加到文档,但可以将它作为一个“仓库”来使用,即可以在里面保存将来可能添加到文档中的节点。

序号 属性
1 nodeType 11
2 nodeName #docuement-frafment
3 nodeValue null
4 parentNode null
5 childNodes Element、ProcessingInstruction、Comment、Text、CDATASection、EntityReference

创建

document.createDocumentFragment()方法

☑︎ 用途:创建文档片段
☑︎ 注意:一个节点append文档片段会导致文档片段中的所有节点都被移动到这个节点

1
<ul id="myList"></ul>
1
2
3
4
5
6
7
8
9
var fragment = document.createDoocumentFragment();
var ul = document.getElementById("myList");
var li = null;
for(var i=0; i<3; i++){
li = document.createElement("li");
li.appendChild(docuemnt.createTextNode("Item "+(i+1)));
fragment.appendChild(li);
}
ul.appendChild(fragment);

1.9 tr 类型

注意: 不被认为是 DOM 树的一部分

节点特征
| 序号 | 属性 | 值 |
| —- | ———- | ————————————— |
| 1 | nodeType | 11 |
| 2 | nodeName | 特性的名称 |
| 3 | nodeValue | 特性的值 |
| 4 | parentNode | null |
| 5 | 子节点 | HTML中不支持子节点、XML中可以是Text或EntityReference |

属性 说明
nodeName、name 特性名称
nodeValue、value 特性值
specified 代码中指定了值true;否则为false

创建

1
2
3
4
5
6
7
document.createAttribute()方法
var attr = document.createAttribute("align");
attr.value = "left";
element.setAttribute(attr);
alert(element.attributes["align"].value); //"left"
alert(element.getAttributeNode("align").value); //"left"
alert(element.getAttribute("align")); // "left"

获得/设置特性

getAttrbuteNode()方法

☑︎ 用途:获得特性节点
☑︎ 参数:特性名称
☑︎ 返回值:特性节点
☑︎ 定义于:Node

setAttrbuteNode()方法

☑︎ 用途:设置特性
☑︎ 参数:特性节点
☑︎ 定义于:Node

2 DOM操作技术

2.1 动态脚本

页面加载时不存在,但将来的某一时刻通过修改 DOM 动态添加的脚本。

方式一:插入外部文件

☑︎ 特点:元素被加入到页面中时才会开始加载

案例一:插入到body最后面
目标

1
<script type="text/javascript" src = "client.js"></script>

实现

1
2
3
4
5
6
7
function loadScript(url){
var script = document.createElement("script");
script.type = "text/script";
script.src = url;
document.body.appendChild(script);
}
loadScript("client.js");

方式二:在页面中插入JS代码
☑︎ 特点:脚本执行后立即可用,将在全局作用域中执行

目标

1
2
3
4
5
<script type="text/javascript">
function sayHi(){
alert("hi");
}
</script>

实现1:IE会出错(IE将script视为一个特殊的元素,不允许DOM访问其子节点)

1
2
3
4
var script  =document.createElement("script");
script.type = "text/javascript";
script.appendChild(document.createTextNode("function sayHi(){alert('hi');}"));
document.body.appendChild(script);

实现2:IE不会有问题,但Safari3.0-不能正确支持text属性

1
2
3
4
var script  =document.createElement("script");
script.type = "text/javascript";
script.text = "function sayHi(){alert('hi');}";
document.body.appendChild(script);

实现3:兼容所有浏览器

1
2
3
4
5
6
7
8
9
10
11
function loadScriptString(code){
var script = document.createElement("script");
script.type = ""text/javascript;
try{
script.appendChild(document.createTextNode(code));
}catch(ex){
script.text = code;
}
document.body.appendChild(script);
}
loadScriptString("function sayHi(){alert('hi');}");

2.2 动态样式

1
2
☑︎ 必需将<link>元素添加到<head>元素中才能保证所有浏览器行为一致
☑︎ 异步加载

方式一

插入外部文件

插入目标

1
<link rel = "stylesheet" type="text/css" href = "styles.css">

实现

1
2
3
4
5
6
7
8
9
function loadStyles(url){
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = url;
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
}
loadStyles("style.css");

方式二

插入包含嵌入式CSS的style节点(解决IE不允许访问style的子节点的问题)

插入目标

1
2
3
4
5
<style type="text/css">
body{
background-color:red;
}
</style>

实现1:未解决 IE 不能访问 style 子节点的问题

1
2
3
4
5
6
7
8
function loadStyleString(css){
var style = document.creatEllement("style");
style.type="text/css";
style.appendChild(document.createTextNode(css));
var head = document.getElementByTagName('head')[0];
head.appendChild(style);
}
loadStyleString("body{background:red;}");

实现2:针对IE访问元素的 styleSheet.cssText
☑︎ 注意:重用同一个style元素进行再次设置或设置为空字符串可能呆滞浏览器崩溃。

1
2
3
4
5
6
7
8
9
10
11
12
function loadStyleString(css){
var style = document.creatEllement("style");
style.type="text/css";
try{
style.appendChild(document.createTextNode(css));
}catch(ex){
style.styleSheet.cssText = css;
}
var head = document.getElementsByTagName('head')[0];
head.appendChild(style);
}
loadStyleString("body{background:red;}");

2.3 操作表格

HTMLDOM 还为 tabletbodytr 元素添加了一些属性和方法
| table的属性或方法 | 说明 |
| ————— | ———————— |
| caption | 保存着对caption元素(如果有)的指针 |
| tBodies | 一个tbody元素的HTMLCollection |
| tFoot | 保存着tfoot元素(如果有)的指针 |
| tHead | 保存着对thead元素(如果有)的指针 |
| rows | 是一个表格中所有行的HTMLCollection |
| createTHead() | 创建thead元素,将其放在表格中,返回引用 |
| createTFoot() | 创建tfoot元素,将其放在表格中,返回引用 |
| createCaption() | 创建Caption元素,将其放在表格中,返回引用 |
| deleteTHead() | 删除thead元素 |
| deleteTFoot() | 删除tfoot元素 |
| deleteCaption() | 删除caption元素 |
| deleteRow(pos) | 删除指定位置的行 |
| insertRow(pos) | 向rows集合中的指定位置插入一行 |

tbody的属性或方法 说明
rows 表格中所有行的HTMLCollection
deleteRows(pos) 删除指定位置的行
insertRow(pos) 向rows集合中的指定位置插入一行,返回新插入行的引用
tr的属性或方法 说明
cells 保存着tr元素中单元格的HTMLCollection
deleteCell(pos) 删除指定位置的单元格
deleteCell(pos) 删除指定位置的单元格
insertCell(pos) 项cells集合中指定位置插入一个单元格,返回对心插入单元格的引用
1
2
3
4
5
6
7
8
9
10
11
12
<table border="1" width="100%">
<tbody>
<tr>
<td>Cell 1,1</td>
<td>Cell 2,1</td>
</tr>
<tr>
<td>Cell 1,2</td>
<td>Cell 2,2</td>
</tr>
</tbody>
</table>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//创建table
var table = document.createElement("table");
table.border = 1;
table.width = "100%";
//创建tbody
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"));

2.4 使用 NodeList

☑︎ 减少对 NodeList 的访问,或将 NodeList 的值缓存起来,因为每次访问都会运行一次基于文档的查询;
☑︎ 遍历 NodeList 最好将其 length 属性值保存在另外一个变量

1
2
3
4
5
6
7
8
var divs = document.getElementsByTagName("div"),
i,
len,
div;
for(i=0,len = divs.length;i<len; i++){
div = document.createElement("div");
document.body.append(div);
}