本章内容
- 理解包含不同层次节点的DOM
- 使用不同的节点类型
- 克服浏览器兼容性问题及各种陷阱
DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)。DOM描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。
10.1 节点层次
DOM可以将任何HTML或XML文档描绘成一个由多层节点构成的结构。以下面的HTML为例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<p>Hello World</p>
</body>
</html>
以上例子中。文档节点只有一个子节点,即<html>元素,我们称之为文档元素。文档元素是文档的最外层元素,其他所有元素都包含在文档元素中。每个文档只能有一个文档元素。在HTML页面中。文档元素始终是<html>元素。而在XML中由于没有预定义的元素,所有任何元素都可以是文档元素。
function conToArray(nodes){
var array = null;
try{
//针对非ie浏览器
array = Array.prototype.slice.call(nodes,0)
} catch(ex){
array = new Array()
for(var i = 0;i<nodes.length;i++){
array.push(nodes[i])
}
}
return array
}
//如果列表中只有一个节点,那么该节点的nextSibling和previousSibling都为null
if(someNode.nextSibling === null){
alert('到底了')
}else if(someNode.perviousSibling === null){
alert('上面也没了')
}
//新增节点
var result = someNode.appendChild(newNode)
alert(result == newNode) //true
alert(someNode.lastChild == newNode) //true
//someNode有多个子节点
var re = someNode.appendChild(someNode.firstChild)
alert(re == someNode.firstChild) //false
alert(re == someNode.lastChild) //true
//插入节点
//使用insertBefore().接收两个参数:要插入的节点和作为参照的节点.如果参照节点是null.则insertBefore和appendChild执行相同操作.如下:
//插入后成为最后一个子节点
re = someNode.insertBefore(newNode,null)
alert(newNode == someNode.lastChild) //true
//插入后成为第一个子节点
var r = someNode.insertBefore(newNode,someNode,firstChild)
alert(r == newNode) //true
//插入最后一个子节点前面
r = someNode.insertBefore(newNode,someNode.lastChild)
//注意.appendChild和insertBefore方法都只是插入节点,不会移除节点.
//replaceChild方法接收两个参数:要插入的节点和要替换的节点.要替换的节点将由这个方法返回的文档树中移除.同时由要插入的节点占据位置.如下:
//替换第一个子节点
var n = someNode.replaceChild(newNode,someNode.firstChild)
//替换最后一个子节点
n = someNode.replaceChild(newNode,someNode.lastChild)
//移除节点 removeChild()接收一个参数.即要移除的节点.被移除的节点将成为方法的返回值,如下:
//移除第一个子节点
n = someNode.removeChild(someNode.firstChild)
//移除最后一个子节点
n = someNode.removeChild(someNode.lastChild)
//上面介绍的4个方法操作都是某个节点的子节点.也就是说使用这几个方法必须先取得父节点.使用parentNode属性.并不是所有类型的节点都有子节点.
//深复制
var deepList = myList.cloneNode(true)
alert(deepList.childNodes.length) //3 ie<9或7
//浅复制
var slit = myList.cloneNode(false)
alert(slit.childNodes.length) //0
//normalize()方法作用是处理文档树中的文本节点.由于解析器实现或DOM操作的原因.会出现文本节点不包含文本,或者链接出现两个文本节点的情况.在某个节点调用这个方法,就会找到上述两种情况.找到空文本节点,则删除它.找到相邻的文本节点就合并成一个.
1.2 Document 类型
//访问子节点
var html = document.documentElement;
console.log(html === document.childNodes[0]) //true
console.log(html === document.firstChild[0]) //true
//document对象还有个body属性,直接指向<body>元素.
var body = document.body
//取得对<!DOCTYPE>的引用
var doctype = document.doctype
2. 文档信息
//取得文档的标题
var title = document.title
//设置文档标题
document.title = '我是文档标题'
//取得完整的URL;
var url = document.URL;
//取得域名
var domain = document.domain;
//取得来源页面的URL;
var referrer = document.referrer;
//出于安全考虑,domain并非可以设置任何值.不能将这个属性设置为URL中不包含的域.如下:
//假设页面来自p2p.wrox.com域
document.domain = 'wrox.com' //成功
document.domain = 'www.baidu.com' //失败
//域名一开始是a,如果用domain设置成b,那它将不能在设置回a.
3. 查找元素
getElementById()和getElementsByTagName()
//getElementById()查找元素
//根据ID查找元素.ID必须与HTML里面的ID完全一致.区分大小写
var div = document.getElementById('divName')
//根据标签名查找元素
//getElementsByTagName()返回的是一个或多个元素的nodeList
var img = document.getElementsByTagName('img')
//保存的img集合可以通过下列方式访问
console.log(img.length)
console.log(img[0].src)
console.log(img.item(0).src)
//如果img集合中包含有个name属性的.可以通过下面方式访问
var imgName = img.namedItem('imgName')
//也可以通过方括号语法来访问.如下:
var imgName = img['imgName']
//在后台,对数值索引就调用item(),对字符串索引就调用namedItem()
//getElementsByTagName('*')表示全部
var all = document.getElementsByTagName('*')
//第三个方法.getElementsByName().返回带有给定name特性的所有元素.常用于单选
var radios = document.getElementsByName('color')
//包含文档中所有带name属性的a元素
var a = document.anchors;
//包含文档中所有form元素,与document.getElementsByTagName('form')结果相同
var form = document.forms;
//包含文档中所有img元素
var img = document.images
//包含文档中所有带href属性的元素
var link = document.links
6. 文档写入
write()、writeIn()、open()、close()。
write和writeIn方法接收一个字符串参数,即要写入的文本。write会原样写入。writeIn会在末尾加一个\n换行符。
//文档写入字符串
document.write('<b>我是写入文档</b>')
//也可以写入js文件;
document.writeIn('<script type="text/javascript" src="file.js"></script>')
//open和close的作用是打开和关闭页面
1.3 Element类型
Element类型用于表现XML或HTML元素。
//取得标签名
var div = document.getElementById('mydiv')
console.log(div.tagName)
//nodeName也可以取得标签名
console.log(div.tagName === div.nodeName)
//在HTML中,标签名始终都以大写表示,通过如下方式转换
console.log(div.tagName.toLowerCase()) //结果为div;
1.HTML元素
所有HTML元素都由HTMLElement的子类型来表示 。HTMLElement类型直接继承Element并添加了一些属性。
- id,元素在文档中的唯一标识
- title,有关元素的附加说明信息,一般通过工具提示条显示出来
- lang,元素内容的语言代码,很少用
- dir,语言的方向,值为“ltr”或“rtl”
- className,与元素的class特性对应,即为元素指定的css类。没有将这个属性命名为class,是因为class是ES中的保留字。
以下是上述属性的使用方法:
//取得id;
var id = document.getElementById('mydiv');
//标题
console.log(id.title)
//class
console.log(id.className)
//lang
console.log(id.lang)
//dir
console.log(id.dir)
//也可以通过下面方式赋值
//标题
id.title = 'new text';
//class
id.className = 'newClass'
//lang
id.lang = 'fr'
//dir
id.dir = 'rtl'
2.取得特性(属性)
操作特性的方法为:getAttribute()、setAttribute()、removeAttribut()。如下使用方式:
//操作特性(属性)
//获取id属性
console.log(id.getAttribute('id'))
//获取class属性 传入的字符串必须用特性名称保持一致.如果没找到传入的特性名称,则显示null
console.log(id.getAttribute('class'))
//也可以获取自定义特性
console.log(id.getAttribute('zidingyi'))
//获取style;
console.log(id.getAttribute('style'))
//onclick;
console.log(id.getAttribute('onclick'))
3.设置特性
//设置特性
id.setAttribute('id','newId')
id.setAttribute('class','newClass')
//也可以如下:
id.id = 'newIdd';
id.className = 'newclassss'
//removeAttribute()不仅会清除特性的值,还会从元素中完全删除特性
id.removeAttribute('class')
//遍历元素特性函数
function bl(element){
var pains = new Array(),
attrName,
attrValue,
for(let i = 0;i<element.length;i++){
attrName = element.attributes[i].nodeName
attrValue = element.attributes[i].nodeValue
pains.push(attrName + '=' + attrValue)
}
return pains.join(" ")
}
5.创建元素
//创建元素
var d = document.createElement('div')
//新创建的元素可以直接添加属性
d.id = 'newid'
d.className = 'newClass'
d.innerText = '1111'
//将新创建的元素添加到DOM里
document.body.appendChild(d)
6. 元素子节点
//获取子节点
var ul = document.getElementById('ul')
var li = ul.getElementsByTagName('li')
console.log(li)
1.4 Text类型
下列方法可以操作节点中的文本:
appendData(text):将text添加到节点的末尾。
deleteData(offset,count):从offset指定的位置开始删除count个字符。
insertData(offset,text):从offset指定的位置插入text。
replaceData(offset,count,text):用text替换指定的位置从offset开始到count结束。
splitText(offset):从offset指定的位置将文本节点分为两个文本节点。
substringData(offset,count):提取从offset指定的位置开始到offset+count为止处的字符串。
除此之外,文本节点还有一个length属性。保存着节点中字符的数目。
可以用以下代码来访问文本子节点:
//访问文本子节点
var textNode = div.firstChild; //或者div.childNodes[0]
//取得之后可以用下列方式修改它
div.firstChild.nodeValue = "修改过后的值"
1. 创建文本节点
//创建文本节点
var t = document.createTextNode('<b>Hello</b> wolrd')
var er = document.createElement('div')
er.className = 'message'
var er1 = document.createTextNode('我是message div里面的值')
er.appendChild(er1)
var er2 = document.createTextNode('我是message div里面后创建的值')
er.appendChild(er2)
document.body.appendChild(er)
2. 规范化文本节点
//规范化文本节点
console.log(er.childNodes.length)
er.normalize()
console.log(er.childNodes.length)
console.log(er.firstChild.nodeValue)
3. 分割文本节点
//分割文本节点
var fg = er.firstChild.splitText(5)
console.log(er.firstChild.nodeValue)
console.log(fg.nodeValue)
console.log(er.childNodes.length)
文档片段用法
//文档片段
var fra = document.createDocumentFragment()
var ul = document.getElementById('myul')
var li = null;
for(var i = 0;i<5;i++){
li = document.createElement('li')
li.appendChild(document.createTextNode('我是第' + i + '个li'))
// li.innerText = '我是第' + i + '个li'
fra.appendChild(li)
}
ul.appendChild(fra)
1.9 attr 类型
//操作元素的特性
var attr = document.createAttribute('align')
attr.value = 'left'
div.setAttributeNode(attr)
console.log(div.attribute('align').value)
console.log(div.getAttributeNode('align').value)
console.log(getAttribute('align'))
2. 动态脚本
2.1 插入动态脚本
//插入动态脚本函数
function loadJs(url){
var script = document.createElement('script')
script.type = 'text/javascript'
script.src = url
document.body.appendChild(script)
}
loadJs('jquery.min.js')
//也可以用这种方式
var script1 = document.createElement('script')
script1.type = 'text/javascript'
var code = 'function sayHi(){alert("hi")}'
try{
script1.appendChild(document.createTextNode('code'))
} catch(ex){
script1.text = 'code'
}
document.body.appendChild(script1)
2.2 动态样式
//动态样式
function loadCss(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)
}
2.3 操作表格
//创建表格
var table = document.createElement('table')
table.border = 1
table.width = '100%'
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)