第 4 部分 DOM 查询与操作.docx
- 文档编号:5800605
- 上传时间:2023-01-01
- 格式:DOCX
- 页数:16
- 大小:27.90KB
第 4 部分 DOM 查询与操作.docx
《第 4 部分 DOM 查询与操作.docx》由会员分享,可在线阅读,更多相关《第 4 部分 DOM 查询与操作.docx(16页珍藏版)》请在冰豆网上搜索。
第4部分DOM查询与操作
第4部分:
DOM查询与操作
简介:
DOM查询和操作是Ajax应用中的常见用法,是Ajax应用中页面动态和局部刷新的实现基础。
本文详细介绍了DOM的基本概念,以及如何使用DOM基本API和Dojo来对页面文档树进行查询和操作,重点介绍了dojo.query和dojo.NodeList。
最后介绍了DOM操作性能、dojo.NodeList插件和dojo.behavior等高级话题。
DOM的全称是文档对象模型(DocumentObjectModel)。
它是HTML和XML文档的API。
它定义了文档的逻辑结构,以及对文档进行访问和操作的方式。
通过DOM,开发人员可以在文档中自由导航,也可以添加、更新和删除其中的元素和内容。
基本上文档中的任何内容都是可以通过DOM进行访问和操作的。
本文详细介绍了如何使用DOM基本API和Dojo来进行DOM查询和操作。
使用的Dojo版本是1.4。
下面首先介绍DOM的基本概念。
DOM基本概念
DOM是给脚本语言(如JavaScript和VBScript等)来使用的API。
在互联网的早期,HTML页面都是静态的。
开发人员没有办法对页面进行动态修改。
DOM的出现解决了这个问题。
DOM给出了一种描述HTML文档结构的方式,并且允许开发人员通过DOM提供的API来对文档结构进行修改。
DOM目前是W3C的推荐规范。
主流的浏览器都实现或部分实现该规范。
下面首先介绍DOM规范的版本历史。
DOM规范的版本历史
DOM从出现之后,经过了不断的发展变化,以及W3C组织的标准化工作,因此目前的版本比较多,具体如下所示:
∙DOM级别0:
1996年,Netscape公司的NetscapeNavigator2.0浏览器中率先引入了JavaScript这一脚本语言。
开发人员可以利用JavaScript来操作页面上的元素。
此时的DOM称为DOM级别0。
它只支持对页面中的表单、链接和图像进行操作。
∙中间DOM:
中间DOM(IntermediateDOM)指的是DOM级别0和DOM级别1之间的一个中间版本。
在这个版本中,可以通过JavaScript来改变页面的样式表。
另外,页面上更多的元素可以通过DOM来进行操作。
∙DOM级别1:
DOM级别1是由W3C制定的DOM规范标准,在1998年发布。
DOM级别1的规范定义了访问和操作HTML页面中元素的基本方式。
∙DOM级别2:
DOM级别2在DOM级别1的基础上增加了getElementById()方法、DOM遍历和范围、名称空间和CSS的支持。
∙DOM级别3:
DOM级别3在DOM级别2的基础上增加了adoptNode()和textContent等方法和属性、文档保存和加载、文档验证和XPath等。
本文中将重点介绍DOM级别1和级别2的部分。
这些部分的内容目前在不同浏览器之间的兼容性较好,而且也很常用。
下面重点介绍DOM规范中的基本元素。
DOM基本元素
对于HTML文档中的基本元素,DOM都有一个抽象的接口与它对应。
∙文档(Document):
文档接口用来表示整个HTML文档。
对文档中其它元素和内容的访问和操作,都是从这个接口出发的。
∙文档片段(DocumentFragment):
文档片段用来表示整个文档树中的一个部分。
∙节点(Node):
节点接口用来表示HTML文档树中的一个节点。
这是一个抽象的接口,在文档树中具体存在的都是该接口的子类型,如元素、属性和文本节点等。
∙节点列表(NodeList):
节点列表表示的是节点的一个有序集合。
它的作用类似于Java中的java.util.List接口。
可以通过节点在集合中的序号来获取集合中的某个节点。
∙命名节点映射表(NamedNodeMap):
命名节点映射表表示的是可以根据名称来进行存取的节点集合。
它的作用类似于Java中的java.util.Map接口。
∙元素(Element):
元素是节点的一种子类型,可以包含子节点和属性。
∙属性(Attr):
属性用来描述元素的特征。
它并不是文档树的一部分。
∙文本(Text):
文本表示元素和属性的文本内容。
∙DOM异常(DOMException):
DOM异常用来表示DOM操作无法执行时的错误情况。
DOM异常中定义了一系列的出错条件与错误代码。
∙DOM实现(DOMImplementation):
DOM实现表示与DOM接口对应的具体实现。
这里需要注意的是节点列表中的节点是动态的,它反映的是最新的文档结构。
比如通过DOMAPI获得了某个元素的子节点列表,如果其中的某个子节点被删除,此节点就不会出现在之前的节点列表中。
在介绍完DOM的基本概念之后,下面介绍如何使用DOM对当前文档树进行查询。
DOM查询
通过DOM提供的API来对当前文档树进行查询,是操作文档的前提。
由于文档树结构可能很复杂,查询到所需节点的操作有可能会比较繁琐。
这里介绍两种方法来进行查询,一种是利用DOM规范中定义的基本API,另外一种是使用Dojo。
下面先从基本API开始。
使用基本API
使用DOM规范中提供的API,就可以对文档进行查询,以及在文档中自由导航。
下面给出一些常用的方法和属性。
首先介绍的是两个用来在文档树中快速查找元素的方法:
getElementById()和getElementsByTagName()。
文档接口的getElementById(elementId)方法是在DOM级别2中引入的。
该方法的作用是在文档中查找标识符为elementId的元素。
如果有,则返回该元素;否则返回null。
对HTML文档来说,元素的标识符是通过属性id来指定的。
如document.getElementById("mySpan")在当前文档中查找标识符为mySpan的元素。
文档和元素接口的getElementsByTagName(tagname)方法用来查找标签名为tagname的子元素。
该方法的返回结果是节点列表,其中子元素的排列顺序是树遍历时的先序顺序。
通过指定tagname的值为*,可以匹配所有标签。
如document.getElementsByTagName("div")查找当前文档中所有的div元素。
下面介绍在查找到单个节点之后,如何查找其相邻节点。
在文档树中,每个节点的具体类型不尽相同。
在节点接口中定义了属性nodeType用来获取当前节点的具体类型。
该属性的值是一系列预定义的常量值。
属性nodeName和nodeValue的值也与节点的具体类型相关。
如对于元素节点来说,nodeName的值是标签名称,nodeValue的值是null;对于属性节点来说,nodeName和nodeValue的值分别是属性的名称和值;对于文本节点来说,nodeName的值是#text,nodeValue的值是文本的内容。
在访问文档树的时候,一个常见的需求是访问当前节点的父节点、兄弟节点和子节点。
节点接口中提供了相应的属性用来获取这些节点。
∙parentNode:
获取当前节点的父节点。
除了文档、文档片段和属性之外的其它节点都可以拥有父节点。
∙childNodes:
获取当前节点的子节点,是一个节点列表。
∙hasChildNodes():
该方法用来判断当前节点是否有子节点。
∙firstChild:
获取当前节点的第一个子节点。
如果没有则返回null。
∙lastChild:
获取当前节点的最后一个子节点。
如果没有则返回null。
∙previousSibling:
获取出现在当前节点正前面的兄弟节点。
如果没有则返回null。
∙nextSibling:
获取出现在当前节点正后面的兄弟节点。
如果没有则返回null。
节点接口还提供了attributes属性用来获取节点的属性。
对于元素节点,返回的是一个命名节点映射表;对于其它类型的节点,返回的是null。
通过属性ownerDocument可以获取节点所在的文档。
上面介绍的这些基本API是由浏览器来实现的。
下面介绍Dojo提供的dojo.query。
使用dojo.query
使用上面提到的DOM规范定义的基本API,可以完成对HTML文档的查询。
不过基本API的主要问题在于所提供的方法粒度较细。
即便是满足一些简单的查询需求,也需要相当多的代码量。
比如查找某个div元素下面所有的span元素,就需要用到getElementById()和getElementsByTagName()两个方法。
而对DOM进行查询又是十分常用的操作,因此开发人员需要更加方便的进行DOM查询的方法。
Dojo中提供了dojo.query库,用来方便的进行DOM查询。
dojo.query的基本用法是使用CSS3的选择器语法来选择HTML文档中的节点。
对于复杂的查询条件,可以用复杂的CSS选择器来描述。
使用dojo.query可以极大的降低代码量。
比如上面提到的例子,用dojo.query的话只需要一行代码就足够了:
dojo.query("#myDivspan")。
另外dojo.query使用的是CSS的选择器语法,这对于开发人员来说并不陌生。
代码清单1中给出了一些常用的dojo.query的用法。
清单1.常用的dojo.query用法
dojo.query("#header>h1")//ID为header的元素的直接子节点中的h3元素
dojo.query("span[title^='test']")//属性title以字符串test开头的span元素
dojo.query("div[id$='widget']")//属性id以字符串widget结尾的div元素
dojo.query("input[name*='value']")//属性name包含子串value的input元素
dojo.query("#myDiv,.error")//组合查询,结果中包含ID为myDiv的元素和CSS类为error的元素
dojo.query(".message.info")//同时包含了CSS类message和info的元素,注意两个类之间不包含空格
dojo.query("tr:
nth-child(even)")//出现在父节点的偶数位置的tr元素
dojo.query("input[type=checkbox]:
checked")//所有选中状态的复选框
dojo.query(".message:
not(:
nth-child(odd))")//嵌套子查询,选中包含CSS类message,
//并且不出现在父节点的奇数位置的元素
dojo.query方法除了第一个必须的参数用来表示所用的选择器语法之外,还有一个可选的参数用来指定查询的范围,可以是一个ID或是元素。
如果传入该参数,则查询结果中只包含该元素的子节点。
默认的查询范围是整个文档树。
如dojo.query("span.info","myDiv")只在ID为myDiv的元素的子节点中查询包含CSS类info的span元素。
熟练使用dojo.query的前提条件是对CSS3规范定义的选择器语法比较熟悉。
关于CSS3选择器语法的更多信息,请见参考资料。
dojo.query的另外一个强大功能是可以对选择出来的节点进行统一处理。
通过方法级联还可以写出非常简洁的代码。
下面的章节中将会详细介绍dojo.query的这一能力。
在介绍完使用基本API和dojo.query进行DOM查询之后,下面介绍如何进行DOM操作。
DOM操作
在通过上面介绍的基本API或是dojo.query查询到所需的节点之后,下面就可以对这些节点进行操作了。
查询是为操作服务的。
对DOM的操作包括对节点的创建、插入、更新和删除操作。
下面将具体介绍如何使用基本API和Dojo来完成DOM操作。
使用基本API
创建新的节点的统一入口是定义在文档接口中的一系列方法。
这些方法都以create开头。
常用的方法有createElement(tagName)用来创建一个标签名为tagName的元素;createTextNode(data)用来创建一个内容为data的文本节点;createAttribute(name)用来创建一个名称为name的属性节点;createDocumentFragment()用来创建一个文档片段。
创建出新的节点之后,就需要将其插入到当前文档树中。
节点接口定义了两个方法用来完成插入的操作。
∙appendChild(newChild):
把节点newChild添加到当前节点的子节点列表中。
∙insertBefore(newChild,refChild):
与appendChild()类似的是都是把节点newChild添加到当前节点的子节点列表中,不同的是可以通过参数refChild来指定位置。
节点newChild出现在节点refChild的正前面。
节点接口的replaceChild(newChild,oldChild)方法用来将当前节点的子节点oldChild替换成新的节点newChild。
方法removeChild(oldChild)用来删除当前节点的子节点oldChild。
对于元素节点来说,可以对其属性进行操作。
方法setAttribute(name,value)用来设置名为name的属性的值为value。
方法removeAttribute(name)用来删除名为name的属性。
如果一个节点已经在文档树中存在,通过上面提到的appendChild()、insertBefore()和replaceChild()方法改变其在文档树中的位置的时候,该节点会首先被从文档树中删除,然后再被插入到新的位置中。
在插入文档片段的时候,文档片段本身并不会被插入,只有其子节点被插入到文档树中。
使用Dojo
Dojo也提供了一系列的API用来执行DOM操作。
下面介绍常用的方法。
dojo.place(node,refNode,position)方法用来插入节点到文档树中的指定位置。
该方法的参数node用来指定待插入元素的ID或引用;refNode用来指定插入元素时的参照元素;position用来指定相对于参照元素的位置,可选的值有before、after、replace、only、first和last,分别表示在参照元素之前、之后、替换掉参照元素、替换掉参照元素的全部子节点、作为参照元素的第一个子元素,以及作为参照元素的最后一个子元素。
也可以传入表示在参照元素的子节点中的序号位置。
last是默认值,其作用相当于之前介绍的appendChild()方法。
如果该方法的第一个参数是以“<”开头的字符串,则创建一个以该字符串为内容的文档片段并插入此片段。
Dojo提供了3个与元素的属性相关的方法。
dojo.attr(node,name,value)用来获取或设置元素的属性。
该方法的参数node用来指定元素的ID或是引用;name用来指定要获取或设置的属性的名称,也可以是一个包含“属性/值”名值对的JSON对象;value用来指定要设置的属性的值。
传入两个参数可以是获取单个属性的值,也可以是设置一组属性的值。
如dojo.attr(node,"title")用来获取属性title的值,dojo.attr(node,{"title":
"MyTitle","tabIndex":
1})用来同时设置属性title和tabIndex的值。
传入三个参数用来设置单个属性的值,如dojo.attr(node,"name","username")用来设置属性name的值。
在设置属性的时候,可以传入方法作为参数用来绑定事件处理。
dojo.hasAttr(node,name)用来判断元素是否有名为name的属性。
dojo.removeAttr(node,name)用来删除元素的名为name的属性。
dojo.create(tag,attrs,refNode,pos)方法用来创建新元素,并且可以指定元素的属性和在文档树中的位置。
该方法可以有4个参数,只有第一个表示标签名的参数tag是必须的。
第二个参数attrs指定元素的属性,实现时使用dojo.attr()方法。
最后两个参数指定新创建的元素在文档树中的位置,实现时使用dojo.place()方法。
前面在介绍dojo.query的时候提到可以对选择出来的节点进行处理,下面进行具体介绍。
dojo.query()方法返回的结果是dojo.NodeList对象。
dojo.NodeList继承自JavaScript中的数组类型,并添加了很多实用的方法,可以很方便的对选择出来的节点集合进行操作。
其中的很多方法的返回结果也是dojo.NodeList对象。
这样多个方法的调用就可以级联起来,使得代码更加简单。
在这一点上,dojo.query的用法与jQuery比较类似。
具体的级联用法见dojo.query级联一节。
dojo.NodeList中包含了与数组元素处理、DOM操作、CSS样式处理和事件绑定相关的很多方法,下面具体介绍其中的实用方法,如下所示。
∙forEach()、map()、filter()、slice()、splice()、indexOf()、lastIndexOf()、every()和some():
这些是对节点数组本身进行操作的方法。
dojo.NodeList的这些方法与操作数组的对应方法的含义相同,只是操作的对象被隐式指定为当前的节点数组。
∙attr()和removeAttr():
这两个是用来操作元素属性的方法,可以为节点数组中每个元素设置属性值或删除属性值。
如dojo.query("a").attr("target","_blank")查找页面中所有的a元素,并把其属性target的值设成_blank。
∙style()、addClass()、removeClass()和toggleClass():
这些方法用来设置节点数组中每个元素的样式和CSS类。
如dojo.query("p").style("fontSize","1.2em")把页面上所有的p元素的字体大小设成1.2em。
∙append()、prepend()、after()和before():
这四个方法为节点数组中的每个元素添加内容,只是新添加内容的位置不同,分别位于节点的最后一个子节点、第一个子节点、之后和之前。
这四个方法的参数可以是HTML字符串、DOM节点引用和dojo.NodeList对象。
如dojo.query("p").after("Hello")在每个p元素之后添加一个新的span元素。
∙appendTo()、prependTo()、insertBefore()和insertAfter():
这四个方法与上面四个方法是分别对应的,不同的是其参数是一个dojo.query查询字符串,节点数组中的元素被添加到由该查询指定的节点的对应位置上。
可以看成是上面四个方法的逆操作。
如dojo.query("span.message").appendTo("#main")把包含CSS类message的span元素添加为ID为main的元素的最后一个子节点。
∙wrap()、wrapAll()和wrapInner():
这三个方法用来包装节点数组中的元素。
wrap()和wrapInner()都是对节点中的每个元素添加包装,不同的是前者包装的是元素本身,而后者包装的是元素的子节点。
wrapAll()是包装的节点数组中的全部元素。
代码清单2中给出了这三个方法的用法。
∙children()、parent()、next()和prev():
这四个方法用来查询节点数组中元素的子节点、父节点、后面和前面的相邻节点。
这些方法都接受一个查询条件作为参数来进一步过滤结果。
如dojo.query("#myDiv").chidren(".message")查询ID为myDiv的元素的包含CSS类message的子节点。
清单2.wrap()、wrapAll()和wrapInner()的用法
//原始的HTML文档片段
//执行dojo.query(".item").wrap("