DOM是前端编程中一个非常重要的部分,我们在动态修改页面的样式、内容、添加页面动画以及为页面元素绑定事件时,本质都是在操作DOM。DOM并不是JS语言的一个部分,我们通过JAVA、PHP等语言抓取网页内容时需要对网页进行解析并拿到我们感兴趣的那部分内容,这时其实也是在操作DOM。当然在前端领域,我们肯定还是通过JS来操作DOM,而DOM也是伴随JS的出现而诞生的,随着前端的不断发展,DOM标准也在不断演进,每个新的版本都为DOM进行了一定程度的扩展。本文主要总结DOM1级中的核心内容。

 
1、DOM的定义及历史
 
1998年10月,DOM1成为了W3C的推荐标准,我们看下标准中对于DOM的定义:
The Document Object Model (DOM) is an application programming interface (API) for HTML and XML documents. It defines the logical structure of documents and the way a document is accessed and manipulated.
从定义中可以看出,DOM是HTML或XML的API,它定义了文档的逻辑结构并且提供了能够操纵文档内容的方式,我们再看一下文档中提到的:
With the Document Object Model, programmers can build documents, navigate their structure, and add, modify, ordelete elements and content.
 
也就是说,我们通过DOM,可以构建一个文档、遍历文档结构,并且对文档元素和内容进行增、删、改。
 
1.1 DOM发展概述
 
非标准时期—DOM 0:
DOM是Netscape最早提出,并且与JS的诞生是在同一个时间。Netscape2浏览器首先实现了DOM,那时的DOM可以成为DOM0级,DOM0级中定义了获取文档中一些元素的入口,比如form(document.forms)和image(document.images),后期的浏览器为了实现向后兼容,同样也支持DOM0中的这些接口。在JS事件中,我们经常提及的DOM0事件,也是在这个阶段定义的。
 
标准时期—DOM1、2、3、4:
1998年10月,DOM1成为了W3C的推荐标准。DOM1主要定义的是HTML和XML文档的底层结构,为基本的文档结构和查询提供了接口。DOM2和DOM3标准的核心内容分别在2000年和2004年被提出,现代浏览器对DOM2和3已经有了比较好的支持。而在W3C的官网上,DOM4也已经在2015年11月份发布。
 
本文主要总结DOM1中的主要内容。
 
2、DOM1中的那些东东
DOM1定义了HTML和XML文档的底层结构,而这个结构其实就是由不同的节点(Node)构成的一个树状结构(DOM Tree),树的根节点就是文档的根节点(对于HTML来说,就是html节点)。在DOM树中,节点分为不同的类型,节点之间通过某种关系(父子关系,兄弟关系等)结合起来,就构成了整棵DOM树。这里对于树的结构我们不做深入分析,而重点放在构成树的这些不同类型的节点,了解了不同节点所拥有的特性和方法,那么我们进行基本的DOM操作就可以游刃有余了。
 
2.1 所有节点的基类—Node
我们通过浏览器的调试工具来看一下Node类型所具有的方法和属性(这些方法和属性是定义在Node的prototype上的,即由所有子类的实例所共享的):
 
我们可以看到,Node类的原型对象定义了很多的属性和方法(IE中不能直接访问该类),I比如最常见的nodeName, nodeValue, nodeType, childnodes, appendChild等等,这些方法是每一个节点类型都具有的(由于我们是在较新版的chrome浏览器中打印出如下内容的,因此有些方法可能后来的DOM标准扩展进来的)。 下面我们来对DOM1中Node的这些共享方法进行一下总结:
2.1.1 表示节点自身属性的
(1)nodeType属性:从截图中可以看出,Node类有一些静态属性表示不同类型的节点序号,DOM1中一共有12种节点类型:
 
在HTML中,我们最常用的节点类型有:元素节点Element(1),属性节点Attr(2),文本节点Text(3),文档节点Document(9)。
 
(2)nodeName和nodeValue
这两个属性完全取决于节点的类型,nodeName是节点的标签名,nodeValue是节点的值。对于元素节点Element来说,nodeValue始终为null。
2.1.2 表示节点关系的
DOM中的节点之间具有某种关系,正是通过这些关系构建起了DOM树,Node中定义了能够让我们通过这些关系来操作DOM节点的属性和方法。
(1)childnodes属性:这个属性返回该节点的所有子节点所构成的NodeList对象,关于NodeList对象的操作可以参照《JavaScript高级程序设计》第3版的10.1节。
(2)parentNode属性:指向节点的父节点
(3)previousSibling和nextSibling属性:前一个和后一个兄弟节点,兄弟节点即拥有同一个父节点的节点。
(3)firstChild和lastChild属性:第一个和最后一个子节点
(4)hasChildNodes()方法:判断一个节点是否有一个或多个子节点
(5)ownerDocument:指向节点所在的文档对象Document
注:虽然每一个节点都有childNodes属性,但有些节点是没有子节点的,这一点在介绍具体的节点类型时会详细说明。
 
2.1.3 节点操作方法
(1)最常用的节点操作方法就是appendChild(),该方法用于为节点增加一个子节点,并返回新增的子节点。如果新增的子节点在调用这个方法前不是该节点的子节点,那么就将新增的节点添加到该节点的末尾;反之,则是把已经存在的子节点移动到该节点的末尾。
(2)insertBefore():这个方法接收两个参数:要插入的节点和参照节点,如果不传第二个参数,则默认增加到末尾。
(3)replaceChild():这个方法可以起到删除节点的作用,同样接收两个参数,第一个参数为要插入的节点,第二个参数为要替换的节点;如果参数不足2个则会报错。替换后的节点的所有关系指针都会从被它替换的节点复制过来。被替换的节点依然在文档中,但是文档中已经没有它的位置。
(4)removeChild():删除一个节点,与replaceChild相似,被删除的节点仍然在文档中,但是已经没有它的位置了。
 
2.1.4 其他方法
(1)cloneNode():cloneNode()方法执行对一个节点的复制并返回复制的节点,这个方法还接收一个布尔值参数,表示是否执行深复制。如果执行深复制,那么就克隆这个节点的整个节点树,否则就只克隆这个节点。
注:在执行 节点复制时,IE存在一个bug,即会复制该节点的JS属性,比如事件处理程序。
(2)normalize():这个方法的作用是处理文档中的文本节点,比如删除空的文本节点,合并相邻的两个文本节点等。
 
2.2 Document类型
在JS中,Document类型表示整个文档,在浏览器中,document对象是HTMLDocument的一个实例,表示整个HTML页面,同时它还是window对象的一个属性,因此可以将其作为全局对象来访问。它有如下特性:
[1]nodeType为9
[2]nodeName为#document
[3]nodeValue为null
[4]parentNode为null
[5]ownerDocument为null
[6]子节点可能是一个DocumentType(最多一个)、Element(最多一个)、ProccessingInstruction或Comment。
 
Document类型可以表示HTML页面或其他基于XML的文档,但最常见的还是作为HTMLDocument的实例代表一个HTML页面,通过document对象,不仅可以取得与页面相关的信息,还可以对页面的内容和结构进行修改。
 
2.2.1 获得文档的子节点
有两种方式可以获取文档的子节点:通过documentElement属性,这个属性指向html元素,或者通过childNodes[0]。
另外,作为HTMLDocument实例的document对象还有一个body属性,即document.body,指向<body>元素。
 
Document的子节点还可能是DocumentType,但浏览器对于document.doctype属性的支持差异较大,总结为如下:
[1]IE8及以下的版本,如果存在文档类型声明,会错误地把它视为一个Comment节点,而document.doctype始终为null。
[2]对于IE9+和其他新版浏览器,如果存在文档类型声明,则会把它作为document的第一个子节点。
注:《JavaScript高级程序设计》第三版的10.1.2节提到,Safari,chrome以及opera在文档类型声明存在的情况下,会解析文档声明,但是不作为document的子节点,在chrome47.0.2526.80中测试发现是会作为document的子节点的。
 
2.2.2 关于文档的信息
作为HTMLDocument的一个实例,document对象还有普通Document实例对象没有的属性,这些属性提供了一些与网页有关的信息:
(1)document.title:通过title属性可以获取该网页的标题,也可以修改该网页的标题,并且修改后的标题会反应在浏览器的标题栏。
(2)document.URL、document.domain、document.referrer:这三个属性全部对应于HTTP的头部之中,其中,URL属性可以取得完整的URL,domain可以取得域名,referrer可以取得当前页面的来源页面,如果没有来源页面,那么referrer为空。
    这三个属性中,只有domain是可以设置的,但是在设置时也存在一些限制,即:不能将domain设置成URL属性中不包含的域,另外,如果一开始domain的设置的"松散的",则不能再将它设置成"紧绷的".。
    比如一开始的时候:document.domain = xx.com,然后再设置:document.domain = ss.xx.com时就会报错了。
 
2.2.3 查找元素
document中定义的getElementById与getElementsByTagName方法恐怕是我们接触js dom操作时最先接触到的方法了,这两个方法也是查找元素时使用的非常常用的两个方法,另外,HTMLDocument还有一个特有的getElementByName方法,即根据name属性来查找元素。
(1)getElementById()方法:根据元素的id来查找元素,这个方法的注意点在于除IE7以及以下版本的浏览器中是区分大小写的。另外如果页面中存在多个ID相同的元素,则只会取第一个匹配到的元素。IE7及以下版本的浏览器中还有一个奇怪的现象:如果一个表单元素的name属性与该方法的id参数匹配,而且该元素在id匹配的元素之前,那么也会返回该元素。
(2)getElementsByTagName()方法:根据元素的标签名来查找元素,这个方法接收一个参数,并且会返回标签名与传入参数相匹配的元素组成的NodeList对象。在HTMLDocument中,返回的是一个HTMLCollection对象,这个对象与NodeList非常相似,除了可以用item()方法访问特定数值索引的节点之外,它还提供了namedItem()方法来匹配列表中特定name的元素;同时我们可以直接使用方括号的方法访问列表中特定的元素,可以传入数值索引值,也可以传入字符串值,后台会自动调用相应的方法。
注:我们还可以传入一个"*"通配符来获取页面的所有元素。
(3)getElementsByName()方法:这个也是HTMLDocument才有的方法,是根据name属性值来查找元素,与getElementByTagName相似,该方法也返回NodeList对象,而在HTMLDocument中返回的是HTMLCollection对象。
 
2.2.4 特殊集合
document对象还有一些特殊集合,并且很多特殊集合其实在DOM0阶段就已经存在了:
(1)document.anchors:获取页面中的所有锚点,即有name属性的a元素。
(2)document.applets:获取页面中所有的applet元素,但是现代web中已经很少出现applet元素了。
(3)document.images:获取页面中所有的img元素。
(4)document.links:获取页面所有带href属性的a元素。
 
2.2.5 DOM一致性检测
 由于DOM分为多个级别,也包含多个部分,因此检测浏览器实现了哪一部分就十分必要。document.implementation属性就是为此提供相应信息的。DOM1级只为document.implementation实现了一个方法:hasfeature(),该方法接收两个参数,第一个是DOM功能的名称,第二个是版本号。如果浏览器支持给定的功能和版本则返回true,下表列出了可检测的功能和版本号。
DOM一致性检测也存在不足,因为浏览器在实现时可以自行决定是否与DOM的功能保持一致,而且使得hasfeature()返回true容易,但是返回true却并不代表着浏览器确实实现了该功能。因此,在使用某个功能之前,还是要进行能力检测。
 
2.2.6 文档写入
document还提供了向文档写入内容的功能,有以下几个方法:
(1)document.write()和document.writeln():这两个的不同之处在于writeln会在每一次调用的末尾写入一个\n符号。如果在文档加载结束后再调用这两个方法,则会重写整个页面。
(2)document.close()和document.open():分别用于关闭和打开网页的输入流。
 
未完待续~~~
 
参考文章:

DOM LEVEL 1 中的那些事儿[总结篇-上]的更多相关文章

  1. DOM LEVEL 1 中的那些事儿[总结篇-下]

    本文承接:DOM LEVEL 1 中的那些事儿[上]   2.3 Element类型 Element类型应该是Document类型之外使用的最多的节点类型了,Element代表XML或HTML文档中的 ...

  2. DOM对象模型接口规范中的四个基本接口

    DOM对象模型的四个基本接口 在DOM对象模型接口规范中,有四个基本的接口:Document,Node,NodeList以及NamedNodeMap.在这四个基本接口中,Document接口是对文档进 ...

  3. DBA避坑宝典:Oracle运维中的那些事儿

    对于Oracle运维中的那些事儿,我的最终目的:不是比谁更惨,而是能够从中吸取经验和教训. 从我的理解来看,我会从下面的几个方面来进行说明DBA运维中的一些事儿. 每个部分都是非常关键的,缺一不可,而 ...

  4. js中this那些事儿

    前几天写东西由于恶趣味作祟将所有的函数全部封装在json中,起初好好的,函数B也可以调用函数A的内容,不过在写一个点击事件时出现了意外, 代码如下: var $ ={ "A":fu ...

  5. 前端开发工程师 - 03.DOM编程艺术 - 第1章.基础篇(上)

    第1章.基础篇(上) Abstract:文档树.节点操作.属性操作.样式操作.事件 DOM (Document Object Model) - 文档对象模型 以对象的方式来表示对应的html,它有一系 ...

  6. JavaScript中的正则表达式(终结篇)

    JavaScript中的正则表达式(终结篇) 在之前的几篇文章中,我们了解了正则表达式的基本语法,但那些语法不是针对于某一个特定语言的.这篇博文我们将通过下面几个部分来了解正则表达式在JavaScri ...

  7. JSP+Servlet中使用jspsmartupload.jar进行图片上传下载

    JSP+Servlet中使用cos.jar进行图片上传 upload.jsp <form action="FileServlet" method="post&quo ...

  8. JSP+Servlet中使用cos.jar进行图片上传(文件上传亦然)

    链接:JSP+Servlet中使用jspsmartupload.jar进行图片上传下载 关于cos.jar,百度百科只有这么几句话(http://baike.baidu.com/subview/406 ...

  9. Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上)

    原文:[置顶] Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上) 我们在用手机的时候可能会发现,即使应用被放到后台再返回到前台数据依然保留(比如说我们正在玩游戏,突然电话 ...

随机推荐

  1. IOS初级:story board的跳转

    本文要实现view1跳到view2,view2又跳回view1. 首先要在视图中拉出一条连接view1和view2的线. 下面是在view1的控制器中实现,从view1跳到view2 //发生跳转前会 ...

  2. OneZero第三周第五次站立会议(2016.4.8)

    1. 时间: 15:10--15:25  共计15分钟. 2. 成员: X 夏一鸣 * 组长 (博客:http://www.cnblogs.com/xiaym896/), G 郭又铭 (博客:http ...

  3. css兼容技巧

    CSS兼容常用技巧 请尽量用xhtml格式写代码,而且DOCTYPE影响 CSS 处理,作为W3C标准,一定要加DOCTYPE声明. 1.div的垂直居中问题 vertical-align:middl ...

  4. tms web core 里面调用pascal 过程。

    procedure show(s:string);begin  showmessage(s);end; procedure TForm3.WebButton1Click(Sender: TObject ...

  5. idea如何将项目以eclipse保存

    会生成 提交到svn     eclipse 导入 首先使用TortoiseSVN下载要导入的项目 导入 已经存在的maven 项目       clean install -DskipTests t ...

  6. mysql 表锁进程非常多的情况

    今天要说的是mysql 的 MYISAM引擎下的表锁问题. 通常来说,在MyISAM里读写操作是串行的,但当对同一个表进行查询和插入操作时,为了降低锁竞争的频率,根据concurrent_insert ...

  7. Amount of Degrees(数位dp)

    题目链接:传送门 思路:考虑二进制数字的情况,可以写成一个二叉树的形式,然后考虑区间[i……j]中满足的个数=[0……j]-[0……i-1]. 所以统计树高为i,中有j个1的数的个数. 对于一个二进制 ...

  8. WORD文档中插入页码的问题

    原文链接:http://www.360doc.com/content/11/0216/15/849254_93539436.shtml 一.页码从第二页开始1.选择“插入-页码”,打开“页码”对话框. ...

  9. Ng第三课:线性代数回顾(Linear Algebra Review)

    3.1  矩阵和向量 3.2  加法和标量乘法 3.3  矩阵向量乘法 3.4  矩阵乘法 3.5  矩阵乘法的性质 3.6  逆.转置 3.1  矩阵和向量 如图:这个是 4×2 矩阵,即 4 行  ...

  10. 给Java开发者的Scala教程

    author:Michel Schinz,Philipp Haller 1. 简介 本文将该要的介绍Scala语言和其编译.这里假设读者已经有一定的java开发经验,需要概要的了解他们可以用Scala ...