DOM基本操作
DOM (Document Object Model) 文档对象模型,是HTML/XML文档的编程接口。DOM表示由多层节点构成的文档,通过DOM,开发者可以添加、删除和修改页面的各个部分。
文章目录
1. 对节点的增删改查
1.1 查
1.1.1 查看元素节点
document
代表整个文档。
document
上有很多方法:
1.1.1.1 getElementById
document.getElementById('')
通过元素id来选择元素;
在IE8以下的浏览器,不区分id大小写,而且也返回匹配name属性的元素。
<div id="only"></div>
<script>
var div1 = document.getElementById('only');
</script>
1.1.1.2 getElementsByTagName
document.getElementsByTagName('')
,通过标签名选择元素,返回一个动态的包含所有指定标签名的元素的HTML集合(类数组);
<div></div>
<script>
var div1 = document.getElementsByTagName('div')[0];
</script>
兼容性很好,在IE4以及绝大部分浏览器上都可以使用。
getElementsByTagName('')
是最主流的用法。
''
中的标签名可以写*
,getElementsByTagName('*')
表示选择所有标签名的元素。
1.1.1.3 getElementsByClassName
document.getElementsByClassName('')
,通过类名选择元素;
但是IE8以及IE8以下版本的浏览器中没有此方法,正因为此兼容性问题,这种方法才不是最主流的用法。
<div class="selection"></div>
<div class="selection"></div>
<div class="selection"></div>
<script>
var div1 = document.getElementsByClassName('selection')[0];
</script>
1.1.1.4 getElementsByName
document.getElementsByName('')
,选择name属性(数据名)为指定值的所有元素;
需注意,只有部分标签name属性可以生效(例如,表单、表单元素、img、iframe等)。
<input name='fruit'>
<script>
var div1 = document.getElementsByName('fruit')[0];
</script>
1.1.1.5 querySelector
document.querySelector('')
,CSS选择器,可以按照CSS选择器的方式选中元素,这个方式选中的元素默认是单独的一个。
<div>
<strong></strong>
</div>
<div>
<span>
<strong></strong>
</span>
</div>
<script>
var div = document.querySelector('div>span strong');
</script>
在IE7和IE7以下版本中没有。
1.1.1.6 querySelectorAll
document.querySelectorAll('')
,CSS选择器,可以按照CSS选择器的方式选中元素,这个方式选中的元素是一组。
<div>
<strong></strong>
</div>
<div>
<span>
<strong></strong>
</span>
</div>
<script>
var div = document.querySelectorAll('div>span strong')[0];
</script>
在IE7和IE7以下版本中没有。
querySelector和querySelectorAll选择出来的元素不是实时的,是静态的,选中的元素不是HTML中的元素本身,而是元素的副本。
因此,基于两种query方法的两个缺点(1.兼容性;2.实时性),因此也并不常用。
1.1.2 遍历节点树
根据w3c的dom标准,文档中的所有内容都是节点,节点是dom的最小组成单元。
浏览器会根据dom模型将文档解析成一系列节点,这些节点组成一个树状结构,称为dom节点树。
dom节点树体现了文档的层次结构。dom节点树有两种类型,其一,dom文档节点树,其二,dom元素节点树,dom文档节点树包含文档中所有类型的节点,dom元素节点树只包含元素节点。
1.1.2.1 parentNode
node.parentNode
,父节点(最顶端的parentNode为#document)
<div>
<strong></strong>
<span></span>
<em></em>
</div>
<script>
var strong = document.getElementsByTagName('strong')[0];
var div = strong.parentNode;
</script>
若接着往上推,div的父节点是body,body的父节点是html,html的父节点是#document。
1.1.2.2 childNodes
node.childNodes
,子节点们。
每个节点都有一个childNodes属性,其中包含了NodeList的实例,NodeList
是一个类数组对象,用于存储可以按位置存取的有序节点。
<div>
<strong></strong>
<span></span>
<em></em>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
</script>
上述代码中,div的子节点有7个。
除了元素节点以外还有多种节点需要考虑在内,比如上例中存在文本节点。
又例如:
<div>123
<!-- 注释 -->
<span></span>
<em></em>
</div>
上述div有7个子节点,[text, comment, text, span, text, em, text]
。
NodeList是一个对DOM结构的查询,DOM结构的变化会自动地在NodeList中反映出来。因此NodeList是实时地活动对象,而不是第一次访问时所获得的快照。
可以使用[n]
或.item(n)
访问该节点的第n + 1个子节点(NodeList中第n + 1个元素)。
<div>
<span>123</span>
<strong>234</strong>
<i></i>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
</script>
1.1.2.3 firstChild
node.firstChild
,第一个子节点
1.1.2.4 lastChild
node.lastChild
,最后一个子节点
1.1.2.5 nextSibling
node.nextSibling
,后面一个兄弟节点
1.1.2.6 previousSibling
node.previousSibling
,前面一个兄弟节点
1.1.3 基于元素节点树的遍历
1.1.3.1 parentElement
node.parentElement
,返回当前元素的父元素节点(IE不兼容)
由于#document不是元素,所以父元素节点的顶端是html元素。
1.1.3.2 children
node.children
,只返回当前元素的元素子节点
<div>123
<!-- 注释 -->
<span></span>
<em></em>
</div>
div的元素子节点只有两个,[span, em]
。
1.1.3.3 childElementCount
node.childElementCount
相当于node.children.length
,当前元素节点的子元素节点个数。
1.1.3.4 firstElementChild
node.firstElementChild
,返回的是第一个元素节点(IE不兼容)
1.1.3.5 lastElementChild
node.lastElementChild
,返回的是最后一个元素节点(IE不兼容)
1.1.3.6 nextElementSibling
node.nextElementSibling
,返回后一个兄弟元素节点(IE不兼容)
1.1.3.7 previousElementSibling
node.previousElementSibling
,返回前一个兄弟元素节点(IE不兼容)
上述基于元素节点树的遍历,除了children
以外,其他在IE9以下不兼容。
1.1.4 节点的类型与属性
1.1.4.1 节点的类型
- 元素节点
- 属性节点
- 文本节点
- 注释节点
- document
- DocumentFragment
1.1.4.2 节点的四个属性
- nodeName
其中元素的标签名,以大写形式表示,只读。
<div>123
<!-- 注释 -->
<strong></strong>
<span></span>
<em></em>
<i></i>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
</script>
只读,不能写入
- nodeValue
Text(文本)节点或Comment(注释)节点的文本内容,可读写。
元素节点的nodeValue始终为null。
- nodeType
该节点的类型,只读。
各类型节点对应的nodeType值:
- 元素节点:1
- 属性节点:2
- 文本节点:3
- 注释节点:8
- document:9
- DocumentFragment:11
若使用遍历节点树的方法以及节点的nodeType属性来写一个输出某节点的所有子元素节点的函数(不能使用Children)
<div>123
<!-- 注释 -->
<strong></strong>
<span></span>
<em></em>
<i></i>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
// var div = strong.parentNode;
function retElementChild (node) {
var temp = {
length : 0,
push : Array.prototype.push,
splice : Array.prototype.splice
},
child = node.childNodes,
len = child.length;
for(var i = 0; i < len; i ++){
if(child[i].nodeType === 1){
temp.push(child[i]);
}
}
return temp;
}
</script>
- attributes
Element节点的属性集合
<div id="only" class="a"></div>
<script>
var div = document.getElementsByTagName('div')[0];
</script>
attributes有value和name两种方法,可以读取某属性的属性名和属性值,其中value可改写属性值,name只可读。
1.1.4.3 节点的一个方法
Node.hasChildNodes()
,判断该节点是否存在子节点,返回ture/false
<div id="only" class="a"></div>
<script>
var div = document.getElementsByTagName('div')[0];
</script>
<div id="only" class="a">
</div>
<script>
var div = document.getElementsByTagName('div')[0];
</script>
1.2 增
1.2.1 createElement
document.createElement('')
,创建一个由标签名称 tagName 指定的 HTML 元素。
var div = document.createElement("div"); //创建div元素
1.2.2 createTextNode
document.createTextNode('文本内容')
,创建一个新的文本节点。
1.2.3 createComment
document.createComment('注释内容')
,创建一个新的注释节点。
1.2.4 createDocumentFragment
创建文档碎片节点
1.3 插
1.3.1 appendChild
某节点.appendChild(子节点)
向节点添加最后一个子节点。
<script>
var div = document.createElement('div');
div.innerHTML = 123;
document.body.appendChild(div);
var text = document.createTextNode('createTextNode');
div.append(text); //向div节点添加最后一位子节点text
</script>
appendChild可以向目标节点插入一个新创建的节点,也可以插入某个已有节点。但是若是将已有节点插入,则此节点位置发生移动,即该节点从之前存在的位置移动到目标节点的最后一个子节点的位置。
<div></div>
<span></span>
<script>
var div = document.getElementsByTagName('div')[0];
var span = document.getElementsByTagName('span')[0];
div.appendChild(span);
</script>
原本div标签和span标签应该是兄弟元素,但是经过JS操作后,span标签变成了div标签的子元素。
简而言之,appendChild主要有两个功能:
- 插入新创建的节点;
- 移动已有的节点。
1.3.2 insertBefore
node.insertBefore(a, b)
,在node节点的子节点b前插入节点a。
<div>
<span></span>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
var span = document.getElementsByTagName('span')[0];
var strong = document.createElement('strong');
div.insertBefore(strong, span);
</script>
1.4 删
removeChild
parentNode.removeChild(childNode)
,在父节点中删除指定子节点。removeChild的方法是将指定子节点剪切出去,可以拿个变量接收剪切出去的节点。
<div>
<span></span>
<strong></strong>
<i></i>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
var strong = document.getElementsByTagName('strong')[0];
div.removeChild(strong);
</script>
remove
node.remove()
,销毁自身。remove方法不存在剪切,直接删除。
1.5 替换
1.5.1 replaceChild
parentNode.replaceChild(new, origin)
,在指定父节点中选定一个子节点origin,将其替换成节点new。
<div>
<span></span>
<strong></strong>
<i></i>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
var strong = document.getElementsByTagName('strong')[0];
var newDiv = document.createElement('div');
div.replaceChild(newDiv, strong);
</script>
2. DOM结构树
注:
- Document可以视作一个构造函数,从命名上也符合构造函数的命名规则,但是他无法使用
new Document()
来构造对象。 - document --> HTMLDocument.prototype --> Document.prototype
document节点表示每个文档的根节点,DOM中称之为文档元素(documentElement)。在HTML中,根节点的唯一子节点是<html>
元素,
这里给构造函数Document的原型对象Document.prototype上添加了属性abc,则构造函数HTMLDocument的原型对象HTMLDocument.prototype上继承了Document.prototype的属性abc,而document是对象,不是构造函数,其会继承HTMLDocument.prototype的属性。
上图的第二行有误,HTMLDocument是构造函数,是没有其原型对象上的属性的。
- Document下其实有两个分支,HTMLDocument和XMLDocument,因此Document上应该写HTMLDocument和XMLDocument的共有方法,HTMLDocument上应该写适用于HTML文档节点的方法。
- 注释节点和文本节点的方法在Comment和Text构造函数的原型对象上,这两个原型又继承自CharacterData的原型。
- 其他依此类推。
- 向上追溯原型:
-
其他规则:
1.
getElementById
方法定义在Document.prototype
上,即Element节点不能使用;2.
getElementByName
方法定义在HTMLDocument.prototype
上,即非HTML中的document不能使用(XML document, Element);3.
getElementsByTagName
方法定义在Document.prototype
和Element.prototype
上;4.
HTMLDocument.prototype
定义了一些常用属性,body,head分别指代HTML文档中的<body><head>
标签;5.
Document.prototype
上定义了documentElement
属性,指代文档的根元素,在HTML文档中,他总指代<html>
元素;6.
getElementsByClassName
、querySelectorAll
和querySelector
在Document.prototype
和Element.prototype
类中均有定义。
例2.1:对于getElementsByTagName
方法,可以灵活在Document.prototype
和Element.prototype
上交替使用。
<div>
<span>1</span>
</div>
<span></span>
<script>
var div = document.getElementsByTagName('div')[0];
var span = div.getElementsByTagName('span')[0];
</script>
例2.2:HTMLDocument.prototype
上的body,head属性
例2.3:Document.prototype
上定义了documentElement
属性
3. Element节点的一些属性和方法
3.1 一些属性
3.1.1 innerHTML
elementNode.innerHTML;
,获取此元素节点的html内容;
<div>
<span></span>
<strong></strong>
<i></i>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
</script>
elementNode.innerHTML = "content";
,将此节点的html内容替换成新的内容,覆盖之前的内容。
若不想覆盖之前的内容,则elementNode.innerHTML += "content";
。
innerHTML写入的内容不一定只是普通的文本,也可以以字符串的形式写入元素。
3.1.2 innerText
读写此元素节点的文本内容。
读的时候会将该节点中包括所有子节点的文本内容读出来。
<div>
<span>123</span>
<strong>234</strong>
<i></i>
</div>
<script>
var div = document.getElementsByTagName('div')[0];
</script>
改写的时候需要注意,其会将节点中的内容全部替换成这个文本,因此在有子节点或其他结构的节点慎用innerText来改写文本。
注意innerText在火狐浏览器中不兼容,但是火狐浏览器中提供了一个相同用法的属性textContent,但是textContent不适用于低版本的IE浏览器。
3.2 一些方法
3.2.1 setAttribute
elementNode.setAttribute('name', 'value')
,给元素节点添加行间属性,name为属性名,value为属性值。
3.2.2 getAttribute
elementNode.getAttribute('name')
,获取元素节点的name属性的属性值。