通俗易懂的来讲讲DOM——科普性质的DOM⼊门教程
html document是什么==========转载需要分隔线==========
DOM是所有前端开发每天打交道的东西,但是随着jQuery等库的出现,⼤⼤简化了DOM操作,导致⼤家慢慢的“遗忘”了它的本来⾯貌。不过,要想深⼊学习前端知识,对DOM的了解是不可或缺的,所以本⽂⼒图系统的讲解下DOM的相关知识,如有遗漏或错误,还请⼤家指出⼀起讨论^ ^。
⼀、DOM是什么?
DOM(⽂档对象模型)是针对HTML和XML⽂档的⼀个API,通过DOM可以去改变⽂档。
这个说法很官⽅,⼤家肯定还是不明⽩。
举个例⼦:我们有⼀段HTML,那么如何访问第⼆层第⼀个节点呢,如何把最后⼀个节点移动到第⼀个节点上⾯去呢?
DOM就是定义了如果做类似操作,那么应该怎么做的标准。⽐如⽤getElementById来访问节点,⽤insertBefore来插⼊节点。
当浏览器载⼊HTML时,会⽣成相应的DOM树。
简⽽⾔之,DOM可以理解为⼀个访问或操作HTML各种标签的实现标准。
对于⼀个HTML来说,⽂档节点Document(看不到的)是它的根节点,对应的对象便是document对象(严格讲是⼦类HTMLDocument对象,下⾯单独介绍Document类型时会指出)。
换句话说存在⼀个⽂档节点Document,然后它有⼦节点,⽐如通过ElementsByTagName("html"),得到类型为元素节点的Element html。
每⼀段HTML标记都可以⽤相应的节点表⽰,例如:
HTML元素通过元素节点表⽰,注释通过注释节点表⽰,⽂档类型通过⽂档类型节点表⽰等。
⼀共定义了12种节点类型,⽽这些类型⼜都继承⾃Node类型。
所以我们⾸先讲Node类型,因为这个类型的⽅法是所有节点都会继承的。
⼆、Node类型(基类,所有节点都继承了它的⽅法)
Node是所有节点的基类型,所有节点都继承⾃它,所以所有节点都有⼀些共同的⽅法和属性。
先讲Node类型的属性
⾸先是nodeType属性,⽤来表明节点类型的,例如:
这⾥⾯,9代表的就是DOCUMENT_NODE节点的意思,可以通过Node.DOCUMENT_NODE查看节点对应的数字
⾄于⼀共有哪些节点,每个节点对应的数字⼜是多少,这个可以问⾕歌就知道了。反正常⽤的就是元素节点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对象)
再介绍下Node类型常⽤的⽅法
appendChild()⽅法可以在节点的childNodes的末尾增加⼀个节点,值得注意的是如果这个节点是已经存在在⽂档中的,那么便会删除原节点,感觉上就像是移动节点⼀样。
insertBefore()⽅法接受两个参数,⼀个是插⼊的节点,另外⼀个是参照的节点。如果第⼆个参数为null,则insertBefore和appendChild效果⼀样。否则便会把节点插⼊到参照节点之前。这⾥要注意的是,如果第⼆个参数不为null,那么插⼊的节点不能是已经存在的节点。replaceChild()⽅法可以替换节点,接受两个参数,需要插⼊的节点和需要替换的节点。返回被替换掉的节点。
removeChild()移除节点。这⾥有个常见需求,⽐如我有⼀个节点 #waste-node ,那么如何移除它呢?
var wasteNode =  ElementById("waste-node");
veClhid(wasteNode);    // 先拿到⽗节点,再调⽤removeClild删除⾃⼰
这⾥先暂停⼀下,不知道⼤家注意到没有,以上的⼏个⽅法都是操作某个节点的⼦节点,也就是说,操作前必须到⽗节点(通过parentNode来)
接下来说下复制节点的⽅法:
cloneNode();复制节点,接受⼀个参数 true或者false。如果true就是复制那个节点和它的⼦节点。如果是false,就是复制节点本⾝(复制出来的节点就会没有任何⼦元素)。这个⽅法返回复制的节点,如果需要操作它,那么需要借助前⾯讲的4个⽅法来把这个节点放⼊到html中去。
⾄此,Node类型的常见属性和⽅法都介绍完了。结合开头讲的,所有节点类型都继承⾃Node类型,所以这些⽅法是所有节点都有的。
三、Document类型
最开始讲DOM是什么的时候提到了Document类型。其实关于这个类型最重要的是它的⼀个⼦类HTMLDocument有⼀个实例对象document。⽽这个document对象是我们最常⽤的⼀个对象了。
document对象⼜挂载在window对象上,所以在浏览器就可以直接访问document了。
⽼规矩,先讲讲document对象的属性,等会讲讲它的⽅法。
document对象上的⼀些属性
document.childNodes 继承⾃上⾯讲的Node类型,可以返回⽂档的直接⼦节点(通常包括⽂档声明和html节点)
document.documentElement 可以直接拿到html节点的引⽤(等价于ElementsByTagName("html")[0])。
document.body body节点的引⽤
document.title  页⾯的title,可以修改,会改变浏览器标签上的名字
document.URL 页⾯的url
document.domain 取得域名,可以设置,但是通常只能设置为不包含⼦域名的情况,在⼀些⼦域名跨域情况下有效。
接下来介绍两个熟悉的⽅法
getElementById 和 getElementsByTagName
getElementById,传⼊id,得到元素节点。⾥⾯的参数区分⼤⼩写(IE8-不区分)。注意:如果有多个id相同的元素,则返回第⼀个。IE7-⾥⾯表单元素的name也会被当做id来使⽤。
getElementsByTagName 根据标签取得元素,得到的是HTMLCollection类型。如果传⼊的是 "*" ,则可以取得全部元素。
还有⼀个是只有HTMLDocument类型(也就是document对象)才有的⽅法 getElementsByName 顾名
思义,根据name返回元素。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>分开来拼装下,否则会被误以为是脚本结束的标志,导致这个结束符匹配到上⾯⼀个开始符。可以这样写"<scr" + "ipt>";
四、Element类型
接下来讲讲最重要也是最常见的⼀个类型,Element类型。
我们⽇常所操作的都是Element类型(实质是HTMLElement,这⾥为了⽅便理解,就简单这么说),⽐如
返回的就是Element类型。我们⽇常所说的“DOM对象”,通常也就是指Element类型的对象。
然后说说这个类型的常见属性:
⾸先最开始说的Node类型上的那些属性⽅法它都有,这个就不再重复了,主要说说它⾃⼰独有的。
⾸先是tagName,这个和继承⾃Node类型的nodeName⼀样。都是返回标签名,通常是⼤写,结果取决于浏览器。所以在做⽐较
的时候最好是调⽤下类似toLowerCase()这种⽅法再做⽐较。
说说上⾯提到过的HTMLElement类型
HTMLElement类型继承⾃Element类型,也是HTML元素的实际类型,我们在浏览器⾥⽤的元素都是这个类型。
这个类型都具有⼀些标准属性,⽐如:
id 元素的唯⼀标识
title 通常是⿏标移上去时候会显⽰的信息
className 类名
等等,这⼏个属性是可读写的,也就是说你改变他们会得到相应的效果。
除了属性外,还有⼏个重要的⽅法
⾸先说说操作节点属性的⽅法
getAttribute 、setAttribute 、removeAttribute这3个⽅法。
这些是操作属性最常⽤的⽅法了,怎么⽤就不说了,很简单,顾名思义。
还有⼀个attributes属性,保存了元素的全部属性。
这⾥停下来,出个问题,ele.className 和 Attribute("class")返回的结果是不是同⼀个东西?
解答这个问题,我要说⼀个重要知识点,⼀个元素的属性结构是这么来的,⽐如⼀个inpnt元素
<input id="test" checked="checked">
那么这个元素的属性被包含在 input.attributes⾥⾯,⽐如你在html元素上看到的class、id或者你⾃⼰定义的data-test这种属性。
然后 getAttribute 、setAttribute 、removeAttribute这3个⽅法可以认为是快捷的取attributes集合的⽅法。⽽直接input.id或者input.className 都是直接挂在input下的属性,和attributes是同级的。所以返回的东西也许看过去⼀样,实际是不⼀样的,不信你可以试试input.checked这Attribute("checked")试试。
关于这个知识点,详细的说可以再写⼀篇⽂章,在我的博客中有谈到过,⼤家可以看看这篇⽂章和⽂章后的讨论,便可以知道是怎么⼀回事。
总得来说,这3个⽅法通常⽤了处理⾃定义的属性,⽽不是id、class等这种“公认特性”。
接下来说说创建元素
⼀般之后可以为元素设置属性,两种⽅法,⼀种是直接node.property还可以node.setAttribute("propertyName","value")。等
但是做完这些之后,这个元素还是没有在页⾯中,所以你还得通过最上⾯讲的类似appendChild这些⽅法把元素添加到页⾯⾥⾯。
在IE中,还可以直接穿整个HTML字符串进去,来创建元素,⽐如
最后,元素节点也⽀持HTMLDocument类型的那些查⽅法,⽐如getElementsByTagName。不过它只会⾃⼰后代的节点。所以可以这么写代码
五、Text类型
这个类型很特殊,也是第三常见类型(第⼀第⼆分别就是Document和Element)。
这个节点简单来说就是⼀段字符串。
有个很重要的特征就是,它没有⼦元素(不过这个仔细想想也知道= =)
访问text节点的⽂本内容,可以通过nodeValue或者data属性。
下⾯简单说说它提供的⼀些⽅法
appendData();    // 在text末尾加内容
deleteData(offset, count);    // 从offset指定的位置开始删除count个字符
还有insertDate、replaceData、splitText等⽅法,就不⼀⼀说了,⽤的机会很少,可以⽤的时候再查阅。
然后它还有⼀个lenght属性,返回字符长度的。
这⾥说⼀个常见的坑。⽐如下⾯这个html结构
<ul>
<li></li>
<li></li>
</ul>
这⾥,ul的第⼀个⼦节点(firstChild)是什么呢?第⼀眼看过去,肯定认为是li了,但是实际上,你会发现不是li,⽽是⼀个⽂本节点!
这是因为浏览器认为ul和第⼀个li之间有空⽩字符,所以就有⽂本节点了。
这⾥⼀个常见的问题就是遍历ul的childNodes的时候,遍历的元素⼀定要判断下nodeType是不是等于1(等于1就代表是元素节点),这样才能跳过这个坑。否则你也可以删除所有的空格和换⾏符。
创建⽂本节点的⽅法是ateTextNode
然后接下来和操作Element类型⼀样,就是再插⼊到元素中,浏览器就可以看到了。
六、其他的⼀些类型 Comment、DocumentType和DocumentFragment
这些不常⽤的⼀句话带过把
Comment是注释节点
DocumentType就是doctype节点,通过docment.doctype来访问
DocumentFragment这个节点是⼀个⽂档⽚段,偶尔会⽤到。
⽐如⼀种常见的⽤法是,在⼀个ul中插⼊3个li。
如果你循环插⼊3次,那么浏览器就要渲染3次,对性能有蛮⼤的影响。
所以⼤家⼀般这么做
var fragment = ateDocumentFragment();
然后循环把li,⽤appendChild插⼊到fragment⾥⾯
最后在⼀次把fragment插⼊到ul⾥⾯。这样就会很快。
七、DOM扩展
进过上⾯讲的这么多节点类型,想必⼤家对DOM节点已经有了很深的了解,下⾯讲⼀讲DOM扩展的⼀些东西。
浏览器为了⽅便开发者,扩展了⼀些DOM功能。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。