DOM基础知识
DOM基础知识(不包括DOM事件)
DOM简介
DOM针对html和xml文档的一个API(应用程序接口),DOM描绘了一个层次化的节点树,允许开发人员添加、移动、修改页面的一部分内容。注意:IE中所有DOM对象是以COM对象形式实现的,其与原生Javascript中的DOM有所差异
DOM的具体内容
1、DOM节点层次
1.1Node类型
DOM将html描绘成一个多层次节点的结构,节点分为不同的类型,每种类型分别表示文档中不同的信息及标记,每个节点都拥有各自的特点,数据和方法,节点和节点之间存在着关系,从而形成关系网。文档节点是每个文档的根节点,<html>为整个html文档的文档元素.。
DOM0级定义一个Node接口,该接口将由DOM中的所有节点类型实现,在js中为Node类型实现。
nodeType属性:每个节点都有这个属性,用于表明节点的类型,由1—12个数值常量表示,常用元素节点为1,文本节点为3
nodeName属性:保存的始终是元素的标签名的大写;nodeValue属性:元素节点始终为null,文本节点为文本,attribute类型为特性的值
childNodes属性:每个节点都存在,其中保存着一个NodeList对象,NodeList是一种类数组对象,用于保存一组有序的节点,通过位置访问节点,length表示节点的数量。注意:nodeList不是数组实例,实际是基于DOM结构动态执行查询的结果,DOM的变化能够直接的反应在NodeList对象之下。有呼吸,有生命的对象。
firstChild:第一个节点;lastChild:最后一个节点
parentNode属性:表示父节点,每个节点都存在,指向文档树中的父节点
nextSibling属性:表示下一个同胞节点,最后一个节点的nextSibling为null;previousSibling属性:表示上一个同胞节点,第一个节点的previousSibling为null;没有同胞节点则都为null
ownerDocument属性:每个节点都存在,直接指向整个文档的文档节点即<html>,,表示这个节点只存在于这个文档之中,不能同时存在多个文件中
操作某节点的子节点
appendChild()方法:用于向childNodes节点后添加一个节点,节点添加后原来的关系指针都会相应的更新;
insertBefore()方法:用于向childNodes节点前添加一个节点,接受两个参数,为要插入的节点和参照的节点,
注意:如果该节点已经存在,那么该节点将从原来位置转移到新的位置;两个方法都是在父节点上操作的;
replaceChild()方法:用于替换节点,接受两个参数,为要插入的节点和要替换的节点。(技术上原先的节点还存在,只是所有关系指针被替换的节点复制一遍,实际上文档中已经没有其位置)
removeChild() 方法:用于移除节点,接受一个参数,为要移除的节点,这也是其的返回值(同样,该节点在文档中没有位置)
其他操作方法
cloneNode()方法:用于创建调用这个方法的节点的完全相同副本,接受一个布尔值的参数,表示是否深复制,true表示深复制,复制节点及整个子节点树,false表示浅复制,复制仅仅这个节点。这个方法不会复制添加到DOM节点中的js属性,只复制特性、(子节点)、其他一切不会复制。
normalize()方法:处理文档树中的文本节点,由于解析器的实现或DOM操作的原因,可能会出现文本节点不包文本,文本出现两次等情况,调用此方法就会在后代查找空文本节点删除,在创建文本节点细说
1.2Document类型
文档子节点
js通过document类型表示文档,浏览器中document的对象是HTMLDocument的一个实例,表示整个HTML页面,同时,document也是window对象的一个属性,可以作为全局对象访问
文档子节点的获取即html的获取可以通过document.doucmentElement或者document.childNodes[0]、document.firstChild
document.body直接指向<body>元素,document.doctype直接指向文档说明(浏览器的支持差别大)
document.title直接指向<title>元素,document.URL,指向页面完整的URL,document.domain,指向域名,document.referrer,指向来源页面的URL
查找元素
document提供两种方法获得元素
1、document.getElementById(id),id必须和元素的id特性(attr)严格匹配,有则返回i该元素,没有则返回null
2、document.getElementsByTagName(标签名),有则返回的是包含零或多个元素的NodeList,而在HTML文档中,会返回一个HTMLCollection对象,作为一个“动态”集合,跟NodeList相似,也有length值。同时,HTMLCollection有个namedItem()方法,可以用索引值表示比如,另外document.getElementsByTagName("*"),获取的所有的元素,返回的是HTMLCollection
<img src="dog.jpeg" name="imgDog"></img>
var images=document.getElementsByTagName("img")
var dog=images.namedItem("imDog")
或者是
var dog=images["imDog"]
3、document.getElementsByName(),只有HTMLDocument类型才有的方法,一般取得单选按钮比如,这个也会返回一个NodeList
<fieldset>
<legend>your color</legend>
<ul>
<li><input type="radio" value="red" name="color" id="colorRed" checked>red</li> 这里的name值都一样
<li><input type="radio" value="yellow" name="color" id="colorYellow">yellow</li>
<li><input type="radio" value="olive" name="color" id="colorOlive">olive</li>
</ul>
</fieldset>
var radios=document.getElementsByName("color")
4、其他一些特殊集合,比如document.anchors,document.form,document.links等等不常用
5、DOM一致性检测,DOM分为多级,检测浏览器的类型十分必要,通过document.implementation属性检测,DOM1级通过hasFeature()检测,最好还要通过能力检测方可使用一些不确定的DOM级别用法,具体如下
document.implementation.hasFeature("xml","1.0") 返回的是布尔值,最好通过能力检测
文档写入
document.write("<strong>"+这是加粗+"</strong>")
document.writeln("<strong>"+这是加粗+"</strong>")这个会在字符串末尾添加换行符\n
document.close()和document.open()关闭和打开
1.3Element类型
对于element类型,nodeName和tagName是一样的,都返回标签名
取得特性
每个元素都有一个或多个特性,用途在于给相应元素或其内容的附加信息
getAttribute("attr"),这里的attr可以是id,class,title,lang,dir等等,对于style和onclick这两个特性,由于通过特性和属性访问存在差异,一般不用getAttribute(),一般获取自定义特性时候
<div id="div1" class="div1" title="div" data-value="define"></div>
alert(div.getAttribute(data-value))获得自定义的特性,自定义特性加个data-前缀便于浏览器渲染
设置特性
通过setAttribute("attr","value")来设置特性,如果特性存在则会替换原来特性;通过removeAttribute()直接移除特性
div.mycolor="red"
alert(div.getAttribute("mycolor"))返回的是null除了IE,添加自定义属性是不同于设置特性的
Attribute属性
element类型是DOM中唯一支持attribute属性的类型,attribute中包含一个NamedNodeMap,和NodeList相似,也是个动态集合,每一个节点都保存在NamedNodeMap中,一些方法就不介绍,不常用,大多用用这个来遍历元素的特性,比如
function outputAttribute(element){
var pairs=new Array(),attrName,attrValue,i,len;
for(i=0;i<element.attribute.length;i++){
attrName=element.attribute[i].nodeName; 注意:这里的nodeName和nodeValue是attribute的属性,可不是element的属性
attrValue=element.attribute[i].nodeValue;
pairs.push(attrName+"=\""+attrValue+"\"")
}
return pairs.join(" ")
}
补充attr类型,nodeName为特性名称,nodeValue为特性值,不被认为是DOM文档树一部分,尽管也是节点,attr有三个属性为name,value,specified(布尔值,区别特性是指定还是默认),使用document.createAttribute()传入特性名称就可创建特性节点比如
var div=getElementById("div") 事实上这里的name就是setAttribute的nodeName value就是setAttribute的nodeValue
var attr=document.createAttribute("title")
attr.value="这是attr的value值"
div.setAttributeNode(attr)
alert(div.title) 弹出 这是attr的value值
创建元素
通过document.createElement(标签名)创建元素的标签,同时也为其设置了ownerDocument属性,通过appendChild,insertBefore,replaceChild等等将其添加到文档树中
newli=document.createElement("li")
newli.innerHTML="新创建的li"
ul.appendChild("newli")
元素的子节点
由于各个浏览器的差异,导致元素中的子节点由于空白字符的原因都是不一样的,当用childNodes遍历整个子节点时,由于浏览器的差别所以一般会判断nodeType属性
for(var i=0,len=element.childNodes.length;i<len;i++){
if(element.childNodes[i].nodeType==1){ 通过nodeType筛选出元素标签
//执行操作
}
}
元素遍历(Element Traversal)为其规范几个新的属性(兼容性问题有待商量)
childElementCount firstElementChild lastElementChild previousElementSibling nextElementSibling
var i,len,child=element.firstElementChild;
while(child!=element.lastElementChild){
processChild(child)
child=child.nextElementSibling
}
1.4Text类型
nodeType为3,nodeValue为节点包含的文本,没有内容就没有文本节点,有内容或空格都是一个文本节点即它的length,可以通过nodeValue和data来访问text节点的文本
创建文本节点
通过document.createTextNode(文本)创建新的文本节点,接受一个参数即要插入的文本
var div=document.createElement("div")
var text=document.createTextNode("这是一段新的文本")
div.appendChild(text)
document.body.appendChild(div)
规范化文本节点
一般情况下,每个元素只有一个文本节点,当出现多个文本节点时,文本就会连在一起,不会出现空格,用前面所说的在父节点上使用normalize()方法,
var div=document.createElement("div")
var textone=document.createTextNode("hello world")
var texttwo=document.createTextNode("lishuangshuang")
div.appendChild(textone)
div.appendChild(texttwo)
document.body.appendChild(div)
alert(div.childNodes.length) 此时为2
div.normalize()
alert(div.childNodes.length) 此时为1
alert(div.childNodes[0].nodeValue) 出现hello world lishaungshuang
分割文本节点
是一种从文本节点中提取数据的常用DOM解析技术,一般为splitText(数值)方法,将nodeValue分成连个文本节点
var div=document.createElement("div")
var textone=document.createTextNode("helloaworld")
div.appendChild(textone)
document.body.appendChild(div)
var newNode=div.firstChild.splitText(5)
alert(div.firstChild.nodeValue) 为hello
alert(newNode.nodeValue) 为aworld 这里的newNode就是div.childNodes[1]
alert(div.childNodes.length) 为2
1.5Comment类型
注释在DOM通过Comment类型表示,nodeValue就是注释的内容
1.6CDATASection类型
只针对xml文档,表示CDATA区域,多数浏览器会把其错误当作Comment或者Element,在xml文档中直接document.createCDataSection()创建CDATA区域
1.7CDATASection类型(不常用)
1.8DocumentFragment类型(文档片段)
nodeValue为null,直接document.createDocumentFragment()方法创建文档片段
var fragment=document.createDocumentFragment
var ul=document.getElementById("ul")
var li=null
for(var i=0;i<3;i++){
li=document.createElement("li")
li.appendChild(document.createTextNode("Item"+(i+1)))
fragment.appendChild(li) 先放在fragment中
}
ul.appendChild(fragment) 文档片段已删除并转移到ul里面了,避免了每一个浏览器反复渲染新信息
2、DOM操作技术
1动态脚本
这里的动态脚本指的是页面加载不存在时,但将来某一时刻通过修改DOM动态添加的脚本
var script=createELement("script")
script.type="text/javascript"
script.url="client.js"
document.body.appendChild(script)
function loadScriptString(code){
var script=document.createElement("script")
script.type="text/javascript"
try{
script.appendChild(document.createTextNode(code))
}catch(ex){
script.text=code 兼容IE
}
document.body.appendChild(script)
}
loadScriptString("function(){alert('hello world')}")
2动态样式
function loadStyle(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)
}
loadStyle("client.css")
function loadstyleString(css){
var style=document.createElement("style")
css.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;}")
3操作表格
原来的操作表格十分复杂比如
创建table
var table=document.createElement("table")
table.border=1
table.width="100%"
创建tbody
var tbody=document.createElement("tbody")
table.appendChild(tbody)
创建tr和td
var row1=document.createElement("row")
tbody.appendChild(row1)
var cell1=document.createElement("td")
cell1.appendChild(document.createTextNode("cell_1"))
row1.appendChild(cell1)
var cell2=document.createElement("td")
cell2.appendChild(document.createTextNode("cell_2"))
row1.appendChild(cell2)
添加到body中
document.body.appendChild(table)
table有一些属性
tBodies是一个<tbody>元素的HTMLCollection
tHead保存着对<thead>元素的指针
tFoot保存着对<tfoot>元素的指针
rows是表格中所有行的HTMLCollection
cells是表格中所有行的单元格的HTMLCollection
table有一些方法
deleteRow(pos)删除指定位置的行
insertRow(pos)在指定位置插入行,并返回该行
deleteCell(pos) insertCell(pos)同理
创建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.row[0].insertCell(0)
tbody.row[0].cells[0].appendChild(document.createTextNode("cell1"))
tbody.row[0].insertCell(1)
tbody.row[0].cells[1].appendChild(document.createTextNode("cell2"))
添加到body中
document.body.appendChild(table)
4使用NodeList
NodeList和NamedNodeMap和HTMLCollection都是动态的,每当文档结构发生变化时,都会得到更新,始终保持最新,最准确的信息,本质上说,所有的NodeList对象都是在访问DOM文档时实时运行的查询
var divs=document.getElementsByTagName("div"),i,div;
for(i=0;i<divs.length;i++){ //因为len是实时变化的,所以循环下去
div=document.createElement("div")
document.body.appendChild(div)
}
var divs=document.getElementsByTagName("div"),i,len,div;
for(i=0,len=divs.length;i++){ //这里的len已经初始化过,相当于保存一开始的快照,从而避免
div=document.createElement("div")
document.body.appendChild(div)
}
一般来说,尽量减少访问NodeList的次数,每次访问NodeList都会运行一次基于文档的查询,考虑先缓存一下
基础不牢,地动山摇