通俗易懂的讲解DOM
2016-11-21 22:22
218 查看
DOM是所有前端开发每天打交道的东西,但是随着jQuery等库的出现,大大简化了DOM操作,导致大家慢慢的“遗忘”了它的本来面貌。不过,要想深入学习前端知识,对DOM的了解是不可或缺的,所以本文力图系统的讲解下DOM的相关知识,如有遗漏或错误,还请大家指出一起讨论^ ^。
举个例子:我们有一段HTML,那么如何访问第二层第一个节点呢,如何把最后一个节点移动到第一个节点上面去呢?
DOM就是定义了如何做类似的操作,那么应该怎么做的标准呢,比如用
当浏览器载入HTML时,会生成相应的DOM树。
简而言之,DOM可以理解为一个访问或操作HTML各种表情的实现标准。
对于一个HTML来说,文档节点
换句话说存在一个文档节点
每一段HTML标记都可以用相应的节点来表示,例如:
HTML元素通过元素节点表示,注释通过注释节点表示,文档类型通过文档类型节点表示等。
一共定义了12种节点类型,而这些类型又都继承自
所以我们首先讲
先讲
首先是
这里面,9代表的就是
至于一共有哪些节点,每个节点对应的数字又是多少,这个可以问问百度。反正最常用的元素节点是Element(对应数字为1)和文本几点Text(对应数字为3)
然后常用的还有
对于元素节点
对于文本节点
每个节点还有
调用
访问
然后各个节点还存在各种属性让它们可以相互访问,下图是个很好的总结
比较有用的属性和方法:
1.
如果包含子节点就返回
2.
返回文档节点的引用(在html里面也就是
比较有用的操作DOM的方法:
这里大家需要注意一下,上面的四个方法都是操作某个节点的子节点,也就是说,操作前必须先找到父节点(通过
复制节点的方法
上面这些就是Node类型中常用的属性和方法。所有的类型都继承自Node类型所以这些属性和方法是所有节点都有的。
document对象的常用属性
document对象常用的方法
还有一个只有
说到
最后,关于
需要注意的是:在页面加载过程中,可以使用这两个方法向页面添加内容。如果页面已经加载完了,再调用write,会重写整个页面。
还有一点,如果要动态的写入脚本,例如
我们平时所操作的都是
Element类型常见的属性
最常用的当然就是
首先是
上面我们提到了
这个类型的元素都具有一些标准属性,比如:
除了属性外,还有几个重要的方法。首先说一下操作节点属性的方法,
这里要说一个问题,
要理解这个问题,首先要说一个重要的知识点,一个元素的属性结构是这么来的,比如一个input元素
那么这个元素的属性被包含在
然后
总的来说,这三个方法通常是用于处理自定义的属性,而不是
下面来说一下创建元素
做完这些以后元素并不是在页面中,所以还要通过最上面讲的像
在IE中,还可以直接将整个HTML字符串加进去来创建元素,比如
最后,元素节点也支持
它还有个重要的特征就是它没有子元素(文本节点,什么都没有),访问text节点的文本内容,可以通过
下面加单说一下它的一下方法
还有
它还有一个
这里说一下一个比较常见的错误,初学者经常会遇到的坑,先来看下面的一段代码:
这里我们会发现ul的第一个子节点输出的是#text,这是为什么呢,难道不应该是
这是一个常见的问题就是遍历
创建文本节点的方法是
比如一种常见的用法是,在一个
创建一个
浏览器为了方便开发者,扩展了一下DOM功能,因为是浏览器自己扩展的,所以使用的时候一定要做兼容性测试
判断标准模式和混杂模式,通过
上面说了一个文本节点是第一子元素的问题,所以浏览器又实现了一个
为了方便判断A节点是不是B节点的子节点,引入了
针对访问元素,又提供了四个方法:
重要的是,这几个方法又心梗问题,比如在IE中,通过
还有一个技巧是,插入大量的html代码,用
一、DOM是什么
DOM(文档对象模型)是针对HTML和XML文档的一个API,通过DOM可以去改变文档。这个说法很官方,大家可能还不明白。举个例子:我们有一段HTML,那么如何访问第二层第一个节点呢,如何把最后一个节点移动到第一个节点上面去呢?
DOM就是定义了如何做类似的操作,那么应该怎么做的标准呢,比如用
getElementById来访问节点,用
insertBefore来插入节点。
当浏览器载入HTML时,会生成相应的DOM树。
简而言之,DOM可以理解为一个访问或操作HTML各种表情的实现标准。
对于一个HTML来说,文档节点
Document(这个是看不到的)是他的根节点,对应的对象便是
document对象(严格的讲是子类
HTMLDocument对象,下面单独介绍
Document类型时会指出)。
换句话说存在一个文档节点
Document,然后他有子节点,比如通过
document.getElementsByTagName(“html”),得到类型为元素节点的Element html。
每一段HTML标记都可以用相应的节点来表示,例如:
HTML元素通过元素节点表示,注释通过注释节点表示,文档类型通过文档类型节点表示等。
一共定义了12种节点类型,而这些类型又都继承自
Node类型。
所以我们首先讲
Node类型,因为这个类型的方法是所有节点都会继承的。
二、Node类型(基类,所有节点都继承了它的方法)
Node是所有节点的基类型,所有节点都继承自它,所有所有节点都有一些共同的方法和属性。
先讲
Node类型的属性
首先是
nodeType属性,用来表明节点类型的,例如:
document.nodeType;返回9,其中
document对象为文档节点的
Document的实例。
这里面,9代表的就是
DOCUMENT_NODE节点的意思,可以通过
Node.DOCUMENT_NODE查看对应的数字
document.nodeType === Node.DOCUMENT_NODE; //true
至于一共有哪些节点,每个节点对应的数字又是多少,这个可以问问百度。反正最常用的元素节点是Element(对应数字为1)和文本几点Text(对应数字为3)
然后常用的还有
nodeName和
nodeValue
对于元素节点
nodeName就是标签名,
nodeValue就是
null
对于文本节点
nodeName为”#text”(chrome里面测试的),
nodeValue就是实际的值
每个节点还有
childNodes属性,这是个十分重要的属性,他保存了这个节点所有直接子元素
调用
childNodes返回的就是一个
NodeList对象,它极其像一个数组,但是有一个关键的地方,他是动态查询的,也就是说每次调用他都会对DOM结构查询,所以对它的使用需要谨慎,注意性能。
访问
childNodes可以使用数组下表或者
item方法
然后各个节点还存在各种属性让它们可以相互访问,下图是个很好的总结
比较有用的属性和方法:
1.
hasChildNodes()
如果包含子节点就返回
true,比查询
childNodes的
length来的简单。
2.
ownerDocument
返回文档节点的引用(在html里面也就是
document对象)
比较有用的操作DOM的方法:
appendChild()方法可以在节点的
childNodes的末尾添加一个节点,值得注意的是如果这个节点是已经存在于文档中的,那么变回删除原节点,感觉上就像是移动节点一样。
insertBefore()方法接受两个参数,一个是插入的节点,另外一个是参照的节点。如果第二个参数为
null,则
insertBefore和
appendChild的效果一样。否则便会把节点插入到参照节点之前。这里要注意的是,如果第二个参数不为
null,那么插入的节点不能是已经存在的节点,否则结果同上。
replaceChild()方法可以替换节点,接受两个参数,需要插入的节点和需要替换的节点。返回被替换掉的节点。
removeChild()移除节点。这里有个常见的需求,比如我有一个节点#node,那么如何移除它呢?
var node = document.getElementById("node"); node.parentNode.removeChild(node); //先拿到父节点,再调用父节点的removeChild删除自己
这里大家需要注意一下,上面的四个方法都是操作某个节点的子节点,也就是说,操作前必须先找到父节点(通过
parentNode来找)
复制节点的方法
cloneNode()复制节点,接受一个参数
true或者
false。如果
true就是复制那个节点和它的子节点,如果是
false,就是复制节点本身(复制出来的节点没有任何子元素)。这方法返回复制的节点,如果如要操作它,那么需要借助前面讲的四个方法来把这个节点放到html中去。
上面这些就是Node类型中常用的属性和方法。所有的类型都继承自Node类型所以这些属性和方法是所有节点都有的。
三、Document类型
最开始讲DOM的时候提到了Document类型。其实关于这个类型最重要的就是它的一个子类
HTMLDocument有一个实例对象
document。而这个
document对象是我们最常用的一个对象了。
document对象又是在
window对象上,所以浏览器就可以直接方法
document了。
document对象的常用属性
document.childNodes继承自上面讲的
Node类型,可以放文档的直接子节点(通常包括文档声明和html节点)
document.documentElement可以直接拿到html节点的引用(等价于
document.getElementsByTagName("html")[0])
document.body
body节点的引用
document.title页面
title,可以修改,会改变浏览器标签上的名字
document.URL页面的
url
document.referrer取得
referrer,也就是打开这个页面的那个页面的地址,做来源统计时候比较有用
document.domain取得域名,可以设置,但是同城只能设置为不包含子域名的情况,在一些子域名跨域情况下有效。
document对象常用的方法
getElementById,传入id,得到元素节点。里面的参数区分大小写(IE8不区分)。注意:如果有多个id相同的元素,则返回第一个。IE7里面表单元素的
name也会被当做id来使用。
getElementsByTagName根据标签取得元素,得到的是
HTMLCollection类型。如果传入的是”*”,则可以得到全部的元素。
还有一个只有
HTMLDocument类型(也就是
document对象)才有的方法
getElementsByName,就是根据那么返回元素。
document对象还有一些集合,例如
document.forms可以返回所有的
form表单。类型也是
HTMLCollection.
说到
HTMLCollection,
HTMLCollection就是一个包含一个或者多个元素的集合,和讲的
NodeList很像。
HTMLCollection这个类型有两个方法,一个是通过下标(或者
.item())得到具体元素,还有就是通过
['name'](或者
.namedItem())获得具体元素。
最后,关于
document对象还有一套比较重要的方法,那就是
write(),
writeln(),
open(),
close()
open和
close分别是打开和关闭网页的输出流,在页面加载的过程中,就相当于
open状态。这两个方法一般不会去用它。
write和
writeln都是向页面写入东西,区别就是后者会多一个换行符。
需要注意的是:在页面加载过程中,可以使用这两个方法向页面添加内容。如果页面已经加载完了,再调用write,会重写整个页面。
还有一点,如果要动态的写入脚本,例如
<script>xxx</script>这样的,那么就要把
</script>分开拼装,否则会被误以为是脚本结束的标志,导致这个结束符匹配到上面一个开始符。可以这样写“”
四、Element类型
下面我们来说一下最重要也是最常见的一个类型,Element类型。
我们平时所操作的都是
Element类型(实质上是
HTMLElement,这里为了方便理解,就简单这么说),比如
document.getElementById("test")返回的就是
Element类型。我们平时所说的”DOM对象”,通常也就是指
Element类型的对象。
Element类型常见的属性
最常用的当然就是
Node类型上的那些属性和方法,这里就不在重复说了,主要说一下它独有的
首先是
tagName,这个和继承自Node类型的
nodeName一样。都是返回标签名,通常都是大写,有的浏览器会返回小写。所以在比较的时候最好调用一下类似
toLowerCase()这种方法再做比较。
上面我们提到了
HTMLElement类型,
HTMLElement类型继承自Element类型,也就是HTML元素的实际类型,我们在浏览器里用的元素都是这个类型。
这个类型的元素都具有一些标准属性,比如:
id元素的唯一标识,
title通常是鼠标移上去时显示的信息,
className类名等等,这几个属性是可读写的,也就是说你改变它们以后会得到相应的效果。
除了属性外,还有几个重要的方法。首先说一下操作节点属性的方法,
getAttribute、
setAttribute、
removeAttribute这三个方法。这些是操作属性最常用的方法了,怎么用就不说了,大家应该都会用。还有一个attributes属性,保存了元素的全部属性。
这里要说一个问题,
ele.className和
ele.getAttribute("class")返回的结果是不是同一个东西?
要理解这个问题,首先要说一个重要的知识点,一个元素的属性结构是这么来的,比如一个input元素
<input id="test" checked="checked" />
那么这个元素的属性被包含在
input.attributes里面,比如你在
html元素上看到的
class、
id或者你自己定义的
data-test这种属性。
然后
getAttribute、
setAttribute、
removeAttribute这三个方法可以认为是快捷的取
attributes集合的方法。而直接
input.id或者
input.className都是直接挂在
input下的属性,和
attributes是同级的,所以返回的东西也许看上去是一样的,但是实质上是不一样的,大家可以试一下
input.checked和
input.getAttribute("checked"),结果是前者返回
true,后者返回
checked。
<input id="btn1" checked="checked"/> var test = document.getElementById("btn1"); console.log(a.getAttribute("checked")); //checked console.log(a.checked) //true
总的来说,这三个方法通常是用于处理自定义的属性,而不是
id、
class等这样的共有特性。
下面来说一下创建元素
document.createElement()可以创建一个元素,比如:
document.createElement("div")创建了一个
div元素,之后的操作一般都是为元素设置属性,常用的两种方法,一种是直接
node.property,另一种是
node.setAttribute("propertyName","value")。
做完这些以后元素并不是在页面中,所以还要通过最上面讲的像
appendChild()这些方法来将元素添加到页面中。
在IE中,还可以直接将整个HTML字符串加进去来创建元素,比如
document.createElement("<div>test</div>")。
最后,元素节点也支持
HTMLDocument类型的那些查找方法,比如
getElementsByTagName。不过它只会找自己后代的节点,所以代码可以这样写:
document.getElementById("test").getElementsByTagName("div") //找到id为test元素下面的所有div节点
五、Text类型
这个类型比较特殊,也是第三常见的类型(前两个分别是Document和
Element),这个节点简单的来说就是一个字符串。
它还有个重要的特征就是它没有子元素(文本节点,什么都没有),访问text节点的文本内容,可以通过
nodeValue或者
data属性。
下面加单说一下它的一下方法
appendData(); //在Text末尾添加内容 deleteData(offset,count); //从offset指定的位置开始删除count个字符
还有
insertData、
replaceData、
splitText等方法,因为用的特别少,几乎不用,就不一一说了,用的时候可以再查阅。
它还有一个
length属性,返回的是字符串的长度。
这里说一下一个比较常见的错误,初学者经常会遇到的坑,先来看下面的一段代码:
<ul id="test"> <li>北京</li> <li>上海</li> </ul> <script> var ul = document.getElementById("test"); var first = ul.firstChild; console.log(first); //#text </script>
这里我们会发现ul的第一个子节点输出的是#text,这是为什么呢,难道不应该是
<li>北京</li>吗,不是的,因为
<li>北京</li>和
<ul>之间还有一段空格,这些空格被看做为文本节点,所以会它的第一个节点是文本节点。
这是一个常见的问题就是遍历
ul的
childNodes的时候,遍历的时候一定要判断
nodeType是不是等于1(等于1代表是元素节点),这样才能跳出这个坑。
创建文本节点的方法是
document.createTextNode,然后接下来的操作和
Element类型一样。
六、其他的一些类型 Comment、DocumentType和DocumentFragment
这些不常用的就简单的说一下吧,Comment是注释节点
DocumentType就是
doctype节点,通过
document.doctype来访问。
DocumentFragment这个节点是一个文档片段,偶尔会用到。
比如一种常见的用法是,在一个
ul中插入三个
li,如果你连续循环插入三次,那么浏览器就渲染三次,对性能有挺大的影响,所以大家一般这么做:
var fragment = document.createDocumentFragment();
创建一个
fragment,用
appendChild把
li插入到
fragment中,最后再把
fragment插入到
ul中,这样就会优化性能。
七、DOM扩展
通过上面说的一些节点类型,大家对DOM的了解也会深一点,下面来说一下关于DOM扩展的一下东西。浏览器为了方便开发者,扩展了一下DOM功能,因为是浏览器自己扩展的,所以使用的时候一定要做兼容性测试
判断标准模式和混杂模式,通过
document.compatMode和
document.documentMode
上面说了一个文本节点是第一子元素的问题,所以浏览器又实现了一个
children属性,这个属性只包含元素节点。
为了方便判断A节点是不是B节点的子节点,引入了
contains方法,比如
B.contains(A); //true代表是,false代表不是
针对访问元素,又提供了四个方法:
innerText、
innerHTML、
outerText、
ouerHTML,通过这些方法,可以读写元素,其中TEXT返回的文本内容,*HTML返回的是html文本,而outer则代表包含元素本身。
重要的是,这几个方法又心梗问题,比如在IE中,通过
inner*删除的节点,其绑定的事件依然存在内存中,会消耗大量的内存。
还有一个技巧是,插入大量的html代码,用
innerHTML是非常快的,建议使用。
相关文章推荐
- DOM之通俗易懂讲解
- DOM 之通俗易懂讲解
- 比较经典的DOM解析XML范例讲解
- ASM(Active Shape Model)主动形状模型通俗易懂讲解二:建模
- JavaScript---网络编程(6)-Dom和Bom模型概念讲解(节点获取,window对象)
- svm算法 最通俗易懂讲解
- 一篇通俗易懂的讲解OpenGL ES的文章,opengles
- 通俗易懂JSONP讲解
- 简单通俗讲解DOM
- react-router-dom示例讲解(五)——阻止导航
- 通俗易懂的字符串匹配的KMP算法讲解
- EM算法及其通俗易懂的讲解
- 从”JAVA“而终 24:BOM以及DOM讲解
- DOM 讲解结束
- JavaScript---网络编程(6)-Dom和Bom模型概念讲解(节点获取,window对象)
- 通俗易懂地讲解 __block 变量
- 用通俗易懂的大白话讲解Map/Reduce原理
- 这是对position讲解最通俗易懂的版本了。
- 通俗易懂讲解happens-before原则
- 正则表达式———通俗易懂———边讲解边举例