DOM

原文链接:通俗易懂讲DOM;

1. DOM

DOM(文档对象模型)是针对HTML和XML文档的一个API,通过DOM可以改变文档。

DOM可以理解为一个 访问或操作HTML各种标签的实现标准。

Document类型代表一个HTML或XML文档,Element类型代表该文档中的一个元素。HTMLDocument和HTMLElement子类只是针对HTML文档和元素。

https://sonya1.github.io/assets/img/work_fight/DOM0.png

对于一个HTML来说,文档节点Document(看不见的)是它的根节点(#document),对应的对象便是document对象(严格讲是子类HTMLDocument对象),下面单独介绍Document类型时会指出。

每一段HTML标记都可以用相应的节点表示,比如:HTML元素可以通过元素节点表示,注释通过注释节点表示,文档类型通过文档类型节点表示等。

一共定义了12种节点类型,而这些类型又都继承自Node类型。

2. Node类型(基类,所有节点都继承了他的方法)

2.1 Node类型的属性

如下图:

https://sonya1.github.io/assets/img/work_fight/DOM1.png

如下图: https://images0.cnblogs.com/blog2015/563928/201503/082214053365307.jpg

2.2 Node的方法

3、Document类型

最开始讲DOM是什么的时候提到了Document类型。其实关于这个类型最重要的是它的一个子类HTMLDocument有一个实例对象document。而这个document对象是我们最常用的一个对象了。

document对象又挂载在window对象上,所以在浏览器就可以直接访问document了。

3.1 document对象的属性

3.2 document对象的方法

还有一点,如果要动态写入脚本 例如 这样的 ,那么要注意把</script>分开来拼装下,否则会被误以为是脚本结束的标志,导致这个结束符匹配到上面一个开始符。可以这样写”<scr” + “ipt>”;

3.3 document对象的集合

HTMLCollection就是一个包含一个或多个元素的集合,和上面讲的NodeList还挺像的。HTMLCollection这个类型有两个方法,一个是通过下标(或者.item())得到具体元素,还有就是通过[‘name’](或者.namedItem())获得具体元素。

4.Element类型

我们日常所操作的都是Element类型(实质是HTMLElement,这里为了方便理解,就简单这么说),比如

document.getElementById("test") 

返回的就是Element类型。我们日常所说的“DOM对象”,通常也就是指Element类型的对象。

4.1 Element类型的常见属性:

首先最开始说的Node类型上的那些属性方法它都有,这个就不再重复了,主要说说它自己独有的。

HTMLElement类型

HTMLElement类型继承自Element类型,也是HTML元素的实际类型,我们在浏览器里用的元素都是这个类型。

HTMLElement类型的标准属性

等等,这几个属性是可读写的,也就是说你改变他们会得到相应的效果。

HTMLElement类型的方法

首先说说操作节点属性的方法

最后,元素节点也支持HTMLDocument类型的那些查找方法,比如getElementsByTagName。不过它只会找自己后代的节点。所以可以这么写代码

document.getElementById("test").getElementsByTagName("div");    // 找到id为test元素下的所有div节点

5.Text类型

这个类型很特殊,也是第三常见类型(第一第二分别就是Document和Element)。

这个节点简单来说就是一段字符串。

有个很重要的特征就是,它没有子元素(不过这个仔细想想也知道= =)

5.1 属性

5.2 方法

这里说一个常见的坑。比如下面这个html结构

<ul>
     <li></li>
     <li></li>
</ul>

这里,ul的第一个子节点(firstChild)是什么呢?第一眼看过去,肯定认为是li了,但是实际上,你会发现不是li,而是一个文本节点!

这是因为浏览器认为ul和第一个li之间有空白字符,所以就有文本节点了。

这里一个常见的问题就是遍历ul的childNodes的时候,遍历的元素一定要判断下nodeType是不是等于1(等于1就代表是元素节点),这样才能跳过这个坑。否则你也可以删除所有的空格和换行符。

6、其他的一些类型 Comment、DocumentType和DocumentFragment

Comment是注释节点

DocumentType就是doctype节点,通过docment.doctype来访问

DocumentFragment这个节点是一个文档片段,偶尔会用到。

比如一种常见的用法是,在一个ul中插入3个li。

如果你循环插入3次,那么浏览器就要渲染3次,对性能有蛮大的影响。

所以大家一般这么做

var fragment = document.createDocumentFragment();

然后循环把li,用appendChild插入到fragment里面

最后在一次把fragment插入到ul里面。这样就会很快。

7、DOM扩展

浏览器为了方便开发者,扩展了一些DOM功能。

因为是浏览器自己扩展的,所以使用前兼容性问题一定要注意

其中,*TEXT是返回文本内容 *HTML是返回html文本。

而outer*则是代表是否包含元素本身。

实际使用来看,在读内容的时候 inner和outer没有区别。

在把内容写入元素的时候,就是是否包含元素本身的区别。

重要的是,这几个方法有性能问题,比如在IE中,通过inner*删除的节点,其绑定的事件依然在内存中,就很容易消耗大量内存。

还有一个技巧是,插入大量的html代码,用innerHTML是非常快的,建议使用。

9、MORE

DOM知识远不止这些,接下来会简单说说DOM的一些其余接口

处理样式

设置样式的基本的方式就是 ele.style.width = “20px”;这个大家估计很常用。 使用类似这种方法来处理要注意的点就是记得加单位。 快捷一点的方法就是 ele.style.cssText = “width: 20px;height:20px;”;这个可以批量设置。

上面说的是设置,那么获取元素所使用的样式,一般而言会用 document.defaultView.getComputedStyle(ele, null);方法来实现。这个方法会返回这个一个CSSStyleDeclaration对象(就和ele.style返回的一样),但是会包含这个元素的全部样式信息,然后直接返回值.width或者别的属性名就可以得到样式了。

不过IE不支持这种方式,IE更简单,直接ele.currentStyle就可以得到和 document.defaultView.getComputedStyle(ele, null)一样的返回值了。

元素的大小

取得元素的宽高 就使用 offsetHeight/offsetWidth,注意,不包括margin部分

得到元素的偏移值就复杂了一点,有两个方法offsetTop/offsetLeft,但是这两个方法是指元素针对与它的offsetParent对象而言的,所以,如果你想得到元素距离视口的位置,那么还需要找到offsetParent,计算他们的offsetTop/offsetLeft,在找offsetParent的offsetParent,如此循环直到offsetParent为null。注意,这个计算的位置也不包括margin部分。

上面说的是不包括margin,然后还有一组属性clientWidth/clientHeight,它们也可以得到宽高,但是它们是不包括margin和border,也不计算滚动条。

最后,滚动的位置与距离,这个很难说清,大家直接看图比较清楚明了。 https://images0.cnblogs.com/blog2015/563928/201503/092005208552262.png

其中,scrollLeft和scrollTop是可以设置的,如果你把scrollTop设置成 “10px”,那么元素就是滚动到10px的地方去。

Table of Contents