html dom与javascript的关系 -我们用JavaScript对网页(HTML)进行的所有操作都是通过DOM进行的

时间:2022-05-26 20:17:20

一,什么是DOM (参考源http://www.cnblogs.com/chaogex/p/3959723.html)

DOM是什么

DOM全称为The Document Object Model,应该理解为是一个规范,定义了HTML和XML文档的逻辑结构和文档操作的编程接口。

文档逻辑结构

DOM实际上是以面向对象方式描述的对象模型,它将文档建模为一个个对象,以树状的结构组织(本文称之为“文档树”,树中的对象称为“节点”)。
每个文档包含1个document节点,0个或1个doctype节点以及0个或多个元素节点等。document节点是文档树的根节点。
如对于HTML文档,DOM 是这样规定的:

  • 整个文档是一个文档节点
  • 每个 HTML 标签是一个元素节点
  • 包含在 HTML 元素中的文本是文本节点
  • 每一个 HTML 属性是一个属性节点
  • 注释属于注释节点

节点与文档内容是一一对应的关系,节点之间有层次关系。

例如下面的hmlt文档:

<!DOCTYPE html>
<html>
<head>
<title>文档标题</title>
</head>
<body>
<a href="">我的链接</a>
<h1>我的标题</h1>
</body>
</html>

会被建模为下面的文档树:

html dom与javascript的关系 -我们用JavaScript对网页(HTML)进行的所有操作都是通过DOM进行的

又如下面的html文档:

<!DOCTYPE html>
<html class=e>
<head>
  <title>Aliens?</title>
</head>
<body>Why yes.</body>
</html>

会被建模为下面的文档树:

html dom与javascript的关系 -我们用JavaScript对网页(HTML)进行的所有操作都是通过DOM进行的

文档操作

程序员可以使用DOM定义的接口来获得对文档中所有元素进行访问的入口,创建文档,浏览文档结构,添加、修改或删除文档元素和内容。
HTML或XML文档中的所有的内容都可以通过使用DOM定义的接口来操作。

DOM到底是对象模型还是编程接口?

总的来说,DOM应该理解为是1个规范。
站在实现(如浏览器)和使用者(如程序员)的角度来看,DOM就是一套文档节点的编程接口,只要实现了接口,就可以使用接口成员来操作文档;站在设计和制定的角度来看,DOM是一个对象模型,它将文档内容建模为对象并组织为树状结构,定义了这些对象的行为和属性以及这些对象之间的关系。

DOM不是什么

  • DOM不是一个数据结构集,并没有定义数据结构。
  • DOM没有定义文档中什么信息是相关的或者文档中的信息是如何组织的。

如对于XML,这些是在XML Information Set中指定的。DOM只是这些信息集的API。(Application Programming Interface,应用程序编程接口)

DOM的分级

上面讨论的DOM是1级DOM,具体就是 DOM CORE和DOM HTML,它将HTML和XML文档映射为对由层次对象(节点)组成的树。
根据W3C DOM规范,DOM有1级、2级、3级以及最新的4级.

二,什么是HTML DOM (参考源 http://blog.csdn.net/liu_shi_jun/article/details/40817297)

HTML DOM 是:

  • HTML 的标准对象模型
  • HTML 的标准编程接口
  • W3C 标准

HTML DOM 定义了所有 HTML 元素的对象属性,以及访问它们的方法

换言之,HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准。

下面说的dom实际上指的是html dom。

脚本开发人员可以通过文档对象的属性、方法和事件来掌控、操纵和创建动态的网页元素。每一个网页元素(一个HTML标签)都对应着一个对象(object,所谓“对象”,用白话说就是“东西”。object这个词在*通常翻译成“物件”)。网页上的标签是一层层嵌套的,最外面的一层是<HTML>,文档对象模型也这样一层层嵌套着,但是通常被理解成一棵树的形状。树根是window或document对象,相当于最外层的标签的外围,也就是整个文档。树根之下(这棵树的图通常是倒着画,就好像遗传谱系或者家谱那样。树根就是唯一的共同祖先)是子一级的对象,子对象也有它自己的子对象,除了根对象以外,所有的对象都有自己的父对象,同一对象的子对象之间就是兄弟的关系。

在这种由“父子兄弟”组成的“单性繁殖家族图谱树”框架结构中,每个网页元素都可以被确切地定位。文档对象模型把整张网页组织成这样的一个树状的结构,树结构中的每一个元素都被视为一个节点(node)。包括JavaScript在内的各种编程语言都可以通过文档对象模型来访问和改变网页的各种细节。

万维网协会(World Wide Web Consortium,W3C)已经给文档对象模型制定了一系列标准,并且正在制定更多的相关标准。当代的浏览器除支持其中的一部分标准之外,还支持某些早在W3C标准制定以前就流行了的历史既成的编程接口。也就是说现在浏览器使用的技术历史由来纷繁复杂,有些人们普遍使用的DOM技术并无标准可依。

我们将深入所有通用DOM的细节(包括IE浏览器中“与众不同”的某些技术),以全面掌握面向实践的技术。

我们用JavaScript对网页(HTML)进行的所有操作都是通过DOM进行的。DOM属于浏览器,而不是JavaScript语言规范里的规定的核心内容,所以如果你下载一个JavaScript语言的参考帮助文档来查的话,就连妇孺皆知的document.write方法也找不到。

简而言之,DOM可以理解为一个访问或操作HTML各种标签的实现标准。(参考源:http://www.cnblogs.com/iOS-mt/p/5600959.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方法。

  然后各个节点还存在各种属性让它们可以相互访问,下图很好的总结了

html dom与javascript的关系 -我们用JavaScript对网页(HTML)进行的所有操作都是通过DOM进行的

比较有用的方法和属性:

  1、hasChildNodes()

  如果包含子节点就返回true,比查询childNodes的length来的简单。

  2、ownerDocument

  返回文档节点的引用(在html里面也就是document对象)

再介绍下Node类型常用的方法

  appendChild()方法可以在节点的childNodes的末尾增加一个节点,值得注意的是如果这个节点是已经存在在文档中的,那么便会删除原节点,感觉上就像是移动节点一样。

  insertBefore()方法接受两个参数,一个是插入的节点,另外一个是参照的节点。如果第二个参数为null,则insertBefore和appendChild效果一样。否则便会把节点插入到参照节点之前。这里要注意的是,如果第二个参数不为null,那么插入的节点不能是已经存在的节点。

  replaceChild()方法可以替换节点,接受两个参数,需要插入的节点和需要替换的节点。返回被替换掉的节点。

  removeChild()移除节点。这里有个常见需求,比如我有一个节点 #waste-node ,那么如何移除它呢?

var wasteNode =  document.getElementById("waste-node");
wasteNode.parentNode.removeClhid(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节点的引用(等价于document.getElementsByTagName("html")[0])。

  document.body body节点的引用

  document.title  页面的title,可以修改,会改变浏览器标签上的名字

  document.URL 页面的url

  document.referrer 取得referrer,也就是打开这个页面的那个页面的地址,做来源统计时候比较有用

  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,这里为了方便理解,就简单这么说),比如

document.getElementById("test") 

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

  然后说说这个类型的常见属性:

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

  首先是tagName,这个和继承自Node类型的nodeName一样。都是返回标签名,通常是大写,结果取决于浏览器。所以在做比较

  的时候最好是调用下类似toLowerCase()这种方法再做比较。

  说说上面提到过的HTMLElement类型

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

  这个类型都具有一些标准属性,比如:

  id 元素的唯一标识

  title 通常是鼠标移上去时候会显示的信息

  className 类名

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

  除了属性外,还有几个重要的方法

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

  getAttribute 、setAttribute 、removeAttribute这3个方法。

  这些是操作属性最常用的方法了,怎么用就不说了,很简单,顾名思义。

  还有一个attributes属性,保存了元素的全部属性。

  这里停下来,出个问题,ele.className 和 ele.getAttribute("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这input.getAttribute("checked")试试。

  关于这个知识点,详细的说可以再写一篇文章,在我的博客 从is(":checked")说起 中有谈到过,大家可以看看这篇文章和文章后的讨论,便可以知道是怎么一回事。

  总得来说,这3个方法通常用了处理自定义的属性,而不是id、class等这种“公认特性”。

  接下来说说创建元素

  document.createElement()可以创建一个元素,比如:

document.createElement("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个字符

  还有insertDate、replaceData、splitText等方法,就不一一说了,用的机会很少,可以用的时候再查阅。

  然后它还有一个lenght属性,返回字符长度的。

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

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

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

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

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

  创建文本节点的方法是document.createTextNode

  然后接下来和操作Element类型一样,就是再插入到元素中,浏览器就可以看到了。

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

  这些不常用的一句话带过把

  Comment是注释节点

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

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

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

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

  所以大家一般这么做

  先

var fragment = document.createDocumentFragment();

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

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