HTML&DOM
一.我对于HTML的认识
超文本标记语言,标准通用标记语言下的一个应用。
“超文本”就是指页面内可以包含图片、链接,甚至音乐、程序等非文字元素。
超文本标记语言的结构包括“头”部分(英语:Head)、和“主体”部分(英语:Body),其中“头”部提供关于网页的信息,“主体”部分提供网页的具体内容 –百度百科
上述基本上毫无用处,相对于web三剑客(HTML,ECMAScript,CSS),它们各自负责解决结构(Structure)表现(Presentation)和行为(Behavior)三个层面,HTML负责的便是解决结构层(Structure),所以在我看来HTML并不能称为一种语言,因为HTML本身就是一种数据存储格式,这种数据格式可以被浏览器识别并渲染.
浏览器首先先渲染HTML标签的默认样式,然后在通过CSS内的选择器找到对应标签加以渲染,替换掉HTML标签默认属性,这就是为什么提倡使用H5的语义化标签,因为在某些时候CSS样式读取阻断,或者缓慢,那么页面还能保持默认的该有的样式,这样能加大用户体验.
但是这方面国内似乎做的并不到位,我现在是在做移动端开发,有些时候老一点的机型还会出现不适配的情况,这时候我所依赖的语义化标签不会被解析,默认变成一个和div一样的块级元素,现在开发情况基本上就是div+span循环嵌套,心塞塞.一次生产问题我就在也没有用过H5新语义化标签了,div+span虽然暴力 贵在稳定 (っ*´Д`)っ
二.DOM 盗墓学
1.节点点
大多数我会把HTML当做数据文件,CSS当做配置文件这两个东西傻傻的也比较好学,基本上就没有什么理解难度,难度在于当浏览器渲染之后HTML的DOM操作,可以说非常赤鸡了
既然说HTML是一种数据文件,那么HTML就有自己的数据结构,HTML内每一个组成结构的内容将被会划分,以便区分层级结构和数据位置关系,这就是为什么XML要比Json拥有更加直观的层级结构和数据位置关系.
<html>
<head>
<mate name="xxx"></mate>
<mate></mate>
</head>
<body>
<div>111</div>
<div>222</div>
</body>
</html>
<!--这段HTML可以直观的看到是谁嵌套了谁,子节点是什么,谁是谁的相邻节点-->
节点(Node)便是HTML内的基础单位<html></html>
是一个节点,body下div里的文字111
222
也是节点,甚至<mate name="xxx"></mate>
内的name="xxx"
也是节点,大家都是节点,只不过大家的节点种类不同而已.
2.三个火枪手(三大节点).
下面就介绍节点里的主要的三大节点.为了更好的区分他们介绍几个API (具体介绍和用法请点击链接,以后介绍API的时候大多也会用link的方式)
nodeType
HTML DOM nodeType 属性nodeName
HTML DOM nodeName 属性nodeValue
HTML DOM nodeValue 属性
我们区分一个Node是什么类型的会用到nodeType,这些Node在被读取的时候回根据这个Node是什么类型自动分配nodeType(具体对应表).
HTML内占比最多的有三个种类的节点分别是 元素(Element),对应的 nodeType=1
,属性(Attr) nodeType=2
,文本(Text) nodeType=3
.也被称为元素节点,属性节点,文本(文字)节点.
①元素节点(Element)
元素节点(Element)便是这些凑成CP的封闭标签(<div></div>
),或者一直单身的未能组成CP的单封闭标签(<br />
<hr/>
),会被浏览器识别为元素节点(Element),如果没有封闭成功会被当成文字节点或者有可能出现配对错误 like 下面
<div id="d1">
<div id="d2"></div>
<div><!--没有封闭的标签-->
很明显div#d1并没有封闭成功(封闭标签并没有加上/
),那么div#d1会和div#d2的封闭标签组成cp(没有组成元素节点),div#d1的结束标签和div#d2的开始标签会等待下一个与之和它能配对的标签继续组成元素节点,如果整个HTML像上述代码片段一样并没有和它能组成封闭标签的话他将会被识别成文本节点(Text).
元素节点嵌套错误,这是一个很可怕的事情,前端CSS非常多的样式要根据HTML元素节点的结构层次来判断继承关系和样式排版的,如果发生了元素嵌套错误很大几率页面会整体样式崩坏,就像俄国美少女经历岁月洗礼变成了一个战斗民族大妈一样.自己脑补吧.
如果你是一个移动端SPA开发的话HTML内容较少你会很快找到未封闭的标签,但是如果你是PC开发者并且你的工程非常巨大的话嘿嘿嘿…
②文本节点
文本节点(Text)就简单多了,空格回车未封闭好的标签,只要是浏览器不能识别的格式都会成当成文本节点(Text)处理,这点很容易理解,送分题略过.
③属性节点
属性节点(Attr)就是被识别的元素节点(Element)内标明的属性.
比如我们比较熟悉的id
name
class
等等…
学东西不要太死板,我曾经说过HTML本身只是一个数据文件,原理上id
name
class
和我常用来自定义存储数据的这种data-name
自定义属性来说,并没有什么区别,都用键值对形式,来给一个元素节点(Element)添加一个属性节点(Atte),或者说为标签添加一个键值对的数据.
这些特殊的属性(id
name
class
)难道没有什么特殊的地方吗?
有,但是不是针对HTML,而是针对浏览器有特殊的作用,各个浏览器读取时W3C统一规定用几个固定属性(Attr)来存各自需要存储的值而已.具体不在阐述了,只需要知道属性节点(Attr)包含的不仅仅是浏览器里识别的那几个特殊属性就OK.
所以当你某日将id="myEle"
写成xd="myEle"
时这个属性并不会消失,而是作为元素(Element)的xd属性存在变量里,只不过浏览器就无法通过id="myEle"
这个属性找到元素.
至于剩下的几个节点就不说了,实际中也不太会涉略,下面记录的元素树于节点树也是仅仅考虑三大节点,其他不予考虑.
3.DOM上的两颗树
元素树(Element Tree)
之前讲过元素(Element),元素树就是刨去文本节点(Text),仅仅保留元素节点(Element)和属性节点(Attr)的用来记录逻辑关系的结构树,看图看代码:
<html>
<head>
<mate></mate>
<mate></mate>
</head>
<body>
<div></div>
<div></div>
</body>
</html>
<!--这段HTML会被解析成-->
细不细超级简单,他们组成了一个元素树(Element Tree),元素树的每一个分支都是由元素节点(Element)构成.通过元素树的API就可以通过层级关系找到相对应的其他元素,比如head的父元素就是HTML.
节点树(Node Tree)
节点树(Node Tree) 就是所有节点组成的树。
看代码
<!--这回我们添加点其他东西-->
<html>
<head>
<mate></mate>
<mate></mate>
</head>
<body>
我是body下的文字
<div>我是div1</div>
<div>我是div2</div>
</body>
</html>
<!--这段HTML会被解析成-->
这棵树比之前多了些文字
这是最早设计层级树的理念,把所有节点都挂在树上,但是在实际操作中你会发现,当用节点树(Node Tree)的API去寻找body
下的第一个元素(Element),抓取到的并不是div1
而是body下的第一个文字节点(我是body下的文字
),这和我们想要的结果背道而驰.你可以保证在元素中没有文字,但是在开发中你不可能保证元素中没有空格回车,所以针对这一点才产生了元素树(Element Tree).
人们把节点树和元素树统称DOM树 其实真实的情况并不是浏览器里有两个树,只不过为了让大家更好理解才将存储数据结构的数据形象化,人的想象力总是很丰富的,而用来处理数据逻辑的仅仅也只是节点树(Node Tree)而已,只不过通过不同的API,筛选数据的方式有差异而已.元素树(ELement Tree)API会把文字节点筛掉.这样就可以通过元素树(ELement Tree)API来快速找到相对应的元素节点.
两种DOM API操作返回的都是一个DOM节点,如果查找API结果可能是复数的情况,会返回一个DOM的类数组对象
var Ele = document.getElementById('someElement');
//Ele返回的是一个DOM节点
var Eles = document.getElementById('someElement').parentNode.childNodes;
//Eles返回的就是一个类数组对象 因为一个元素只能有一个父元素,但是子元素有可能是多个
//所以返回的是一个类数组,类数组内存着符合查找内容DOM节点,可以通过Eles[index]方式访问调用.
树上的属性果实
很明显前面的两颗树忽略了一个内容,那就是身为三大节点属性之一的属性节点(Attr),元素树和节点树上都有属性节点(Attr),只不过属性节点(Attr)并没有数据层级关系,更像是依附于某个元素节点(文本节点并没有属性),如果把DOM树上的文本节点和元素节点比作树枝(每个分差点为一个节点),属性节点就是某个分岔点上的果实,如图
body下有两个div,同时body上有两个属性 name
id
,为了区分属性节点(Attr)和元素节点(Element)我在属性节点(Attr)加上了单引号,看起来div和和id属于同层级的数据 但是之前说过属性节点存储是单独的,虽然都属于body的子节点但是属性节点(Attr)并不参与层级排序,属性节点(Attr)本身也不分前后父子这种关系.
总体来说HTML下所有内容都分析成节点(Node),然后将他们一股脑的挂在树上,那么这就是节点树(Node Tree).
将未识别的文字节点(Text)从节点树上筛选下来组成元素树(Element Tree).
节点(Node)是HTML的基础单位
不管是属性也好文字也好元素也好都是节点(node)只不过大家的类型不同而已
理解上述,再去熟练DOM操作便是学会了盗墓大法,虽然现在各种库可以更方便的对元素进行增删改查,但是万变不离其中,各种库再厉害也是由这些基础构成的
最后附上菜鸟联盟的DOM教程 -> HTML DOM
自勉