javascript之DOM技术【转】

 首先需要理解的一点是,DOM是针对XML的基于树的API,它的实现有很多(各语言基本都有自己的实现),我们讨论的是javascript中或者说xhtml(html)对DOM的实现。

一、使用DOM
考虑一个html文件:
<html>
<head><title>测试</title></head>
<body>
<p>测试</p>
</body>
</html>

1.访问节点:
访问html元素:var oHtml=document.documentElement;
获取head元素:var oHead=oHtml.firstChild;
获取body元素:var oBody=oHtml.lastChild; 或者 var oBody=document.body;

也可以通过childNodes来做同样的工作:
var oHead=oHtml.childNodes[0] 或者 oHtml.childNodes.item(0);
var oBody=oHtml.childNodes[1] 或者 oHtml.childNodes.item(1);

判断节点间关系:
alert(oHead.parentNode==oHtml);  
alert(oBody.previousSibling
==oHead);
alert(oHead.nextSibling
==oBody);
alert(oHead.ownerDocument
==document);

2.检测节点类型:
通过节点的nodeType属性来检验节点类型:
alert(document.nodeType);  //输出9
需要注意的是,DOM兼容的浏览器(以FF2.0为例),拥有Node.DOCUMENT_NODE、Node.ELEMENT_NODE等常量。各常量名称与数值对照表如下:
ELEMENT_NODE                                 1
ATTRIBUTE_NODE                            
2
TEXT_NODE                                        
3
CDATA_SECTION_NODE                
4
ENTITY_REFERENCE_NODE            
5
ENTITY_NODE                                    
6
PROCESSING_INSTRCTION_NODE       
7
COMMENT_NODE                              
8
DOCUMENT_NODE                           
9
DOCUMENT_TYPE_NODE               
10
DOCUMENT_FRAGMENT_NODE   
11
NOTATION_NODE                             
12

IE6不支持,不过你可以自定义一个JS对象Node。

3.处理特性
处理特性可以使用标准的NameNodeMap中的方法:
getNamedItem(name) removeNamedItem(name)  setNamedItem(node)    item(pos)

比如:<p id="test">测试</p>
假设变量oP是上面的p节点的引用,我们要访问oP的id属性:
var sId=oP.attributes.getNamedItem("id").nodeValue;

这些方法用起来很累赘,所以DOM又定义了三个方法来简化:
getAttribute(name)         ——返回名称为name的属性的值
setAttribute(name,value)   ——顾名思义
removeAttribute(name)      ——顾名思义 

上面的例子可以改写为:
var sId=oP.getAttribute("name");

4.访问指定节点:
熟知的getElementByTagName(name),getElementByName(name),getElementById(id)三个方法,不再展开。

5.创建和操作节点:
(1)创建新节点,一张IE(6.0)和FF对DOM Level1的创建新节点方法支持的对照表:
方法                                                               IE                               FF
createAttribute(name)                                 Y                                Y
createCDATASection(text)                        N                                Y
createComment(text)                                    Y                                Y
createDocumentFragment()                        Y                                Y
createElement(tagName)                             Y                                 Y
createEntityReference(name)                     N                                 Y
createProcessingInstruction(
target,data)                                                   N                                  Y
createTextNode(text)                                  Y                                   Y


下面介绍常用的几个方法

(2)createElement(),createTextNode(),appendChild()
例子:
<html>
    
<head>
        
<title>createElement() Example</title>
        
<script type="text/javascript">
            
function createMessage() {
                
var oP = document.createElement("p");
                
var oText = document.createTextNode("Hello World!");
                oP.appendChild(oText);
                document.body.appendChild(oP);
            }

        
</script>
    
</head>
    
<body onload="createMessage()">
    
</body>
</html>

在页面载入后,创建节点oP,并创建一个文本节点oText,oText通过appendChild方法附加在oP节点上,为了实际显示出来,将oP节点通过appendChild方法附加在body节点上。此例子将显示Hello World!

(3)removeChild(),replaceChild()和insertBefore()
从方法名称就知道是干什么的:删除节点,替换节点,插入节点。需要注意的是replaceChild和insertBefore两个参数都是新节点在前,旧节点在后。

(4)createDocumentFragment()
此方法主要是为了解决大量添加节点时,速度过慢。通过创建一个文档碎片节点,将要添加的新节点附加在此碎片节点上,然后再将文档碎片节点append到body上面,替代多次append到body节点。
例子:
<html>
    
<head>
        
<title>insertBefore() Example</title>
        
<script type="text/javascript">
            
function addMessages() {
                
var arrText = ["first""second""third""fourth""fifth""sixth""seventh""eighth""ninth""tenth"];
                
                
var oFragment = document.createDocumentFragment();
                
                
for (var i=0; i < arrText.length; i++{
                    
var oP = document.createElement("p");
                    
var oText = document.createTextNode(arrText[i]);
                    oP.appendChild(oText);
                    oFragment.appendChild(oP);
                }

                
                document.body.appendChild(oFragment);

            }

        
</script>
    
</head>
    
<body onload="addMessages()">

    
</body>
</html>



二、HTML DOM的特征功能

HTML DOM的特性和方法不是标准的DOM实现,是专门针对HTML同时也让一些DOM操作变的更加简便。

1.让特性像属性一样
访问某元素的特性需要用到getAttribute(name)方法,HTML DOM扩展,可以直接使用同样名称的属性来获取和设置这些值:
比如  <img src="test.jpg"/>
假设oImg是此元素的引用
(oImg.getAttribute("src")可以直接写成:oImg.src,设置值简化为:
oImg.src="test2.gif";
唯一特殊的class属性,因为class是ECMAScript的保留字,所以替代的属性名是className.

2.table的系列方法:
为了简化创建表格,HTML DOM提供了一系列的表格方法,常用几个:
cells  ——返回</tr>元素中的所有单元格
rows   ——表格中所有行的集合
insertRow(position) ——在rows集合中指定位置插入新行
deleteRow(position) ——与insertRow相反
insertCell(position) ——在cells集合的指定位置插入一个新的单元格
deleteCell(position) ——与insertCell相反

三。遍历DOM
DOM的遍历是DOM Level2中提出的标准,IE6没有实现,Mozilla和Safari已经实现,最新IE7不清楚是否实现。不再展开,具体请见《JavaScript高级程序设计》

 

javascript之DOM技术(一)

一。样式编程
1.页面中的每一个元素都具有一个style对象,此对象管理元素的CSS样式。这是在IE4.0引入的,后来作为DOM标准被接受。使用方法:
var oDiv=document.getElementById("div1");
alert(oDiv.style.backgroundColor);
style对象拥有一个cssText属性,返回描述元素样式的CSS字符串。

2.样式对象style的方法(IE6并不支持这些方法):
(1)getPropertyValue(propertyName)——返回CSS特性propertName的字符串值,比如this.style.getPropertyValue("background-color");这里的propertyName必须按照CSS的样式定义。

(2)getPropertyPriority()——返回important字符串或者为空
(3)item(index)——返回给定索引处的CSS特性名称
(4)removeProperty(propertyName)——移除某CSS特性
(5)setProperty(propertyName,value,priorty)——按照执行优先级设定CSS特性的值

3.通过隐藏层实现自定义鼠标提示的例子:

<html>
    
<head>
        
<title>Style Example</title>
          
<script type="text/javascript" src="detect.js"></script>
        
<script type="text/javascript" src="eventutil.js"></script>
        
<script type="text/javascript">
            
function showTip() {
                
var oDiv = document.getElementById("divTip1");
                oDiv.style.visibility 
= "visible";
                
var oEvent=EventUtil.getEvent();
                oDiv.style.left 
= oEvent.clientX + 5;
                oDiv.style.top 
= oEvent.clientY + 5;
            }

            
function hideTip() {
                
var oDiv = document.getElementById("divTip1");
                
var oEvent=EventUtil.getEvent();
                oDiv.style.visibility 
= "hidden";
            }
        
</script>
    
</head>
    
<body>
        
<p>Move your mouse over the red square.</p>
        
<div id="div1" 
             style
="background-color: red; height: 50px; width: 50px"
             onmouseover
="showTip()" onmouseout="hideTip()"></div>

         
<div id="divTip1" 
              style
="background-color: yellow; position: absolute; visibility: hidden; padding: 5px">
            
<span style="font-weight: bold">Custom Tooltip</span><br />
            More details can go here.
         
</div>
    
</body>
</html>


这里使用了我在《javascript事件模型框架》中摘记的JS文件。实现可折叠区域的道理与此相同,很常用的功能,不再细说。

4.访问样式表,因为style对象只能访问一个元素的CSS样式,而对于<style/>定义的或者外部CSS文件定义的CSS规则没办法访问,这就引出了如何访问样式表的问题。我们可以通过下面的方式访问:

var cssRules=document.styleSheets[0].cssRules||document.styleSheets[0].rules;



document.styleSheets返回页面上所有样式表的引用,标准DOM中规定每个样式表的规则集合叫cssRules,而IE中叫rules,所以我们用上面的表达式来处理浏览器兼容问题。一个访问的例子:

<html>
    
<head>
        
<title>Accessing Style Sheets Example</title>
        
<style type="text/css">
            div.special 
{
                background-color
: red;
                height
: 10px;
                width
: 10px;
                margin
: 10px;
            
}
        
</style>
        
<script type="text/javascript">
            
function changeBackgroundColor() {
                
var oCSSRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
                oCSSRules[
0].style.backgroundColor = "blue";
            }
        
</script>
    
</head>
    
<body>
        
<div id="div1" class="special"></div>
        
<div id="div2" class="special"></div>
        
<div id="div3" class="special"></div>
        
        
<input type="button" value="Change Background Color" onclick="changeBackgroundColor()" />
    
</body>
</html>


点击按钮时将三个div的背景色都设置为蓝色。

5.最终样式:顾名思义,就是样式规则(外部定义和内联的)综合计算之后呈现给用户的样式信息,用来告诉我们元素最终是如何显示在屏幕上的。IE和标准的DOM也有区别:
(1)IE中的最终样式称为currentStyle对象,与style对象不同的是它是只读的,你只能读而不能给它赋值。
(2)DOM中的最终样式,通过document.defaultView.getComputedStyle(元素对象,伪元素对象或者null)方法获得

二。innerHTML和innerText
很常用的功能,特别是在AJAX应用中,经常采用的手段是从服务端返回一小段HTML代码,通过innerHTML嵌入某个层当中来动态显示下拉框等。一个比较常见的用法:
oDiv.innertText=oDiv.innerText;
表示从指定元素中删除所有的HTML标签。

三。outerText和outerHTML

与innerHTML和innerText,不过替换的是整个目标节点,仅在IE和opera中支持此特性

四。范围
叫选区也许更为恰当,range用来选择文档的某个部分而不管节点的边界。也有两种的范围实现:DOM和IE的
1.DOM的range
(1)在DOM中创建选区的方法:

var supportDOMRange=document.implementation.hasFeature("Range","2.0");
if(supportDOMRange)
  var oRange=document.createRange();

先判断是否支持DOM,然后使用createRange()方法创建范围

(2)简单选区
考虑下面的代码:

<id="p1"><b>hello</b>world</p>


我们通过下面的JS代码来访问上面这段代码:

var oRange1=document.createRange();
var oRange2=document.createRange();
var op1=document.getElementById("p1");
oRange1.selectNode(op1);
oRange2.selectNodeContents(op1);


两个范围,通过selectNode和selectNodeContents方法来选区,有什么不同呢?oRange1选中的范围包括<p/>节点以及它的全部子节点,而oRange2只包含op1的子节点和文本节点(就是"<b>hello</b>world")。

(3)范围的特性:
<1>startContainer——范围是从哪个节点开始的,也就是第一个节点的父节点
<2>startOffset——在
startContainer的偏移位置。
<3>endContainer——最后一个节点的父节点
<4>endOffset——在
endContainer中范围结束的偏移位置
<5>commonAncestorContainer——startContainer和endContainer都处于哪个最小的节点
演示这些特性的例子:

<html>
    
<head>
        
<title>DOM Range Example</title>
        
<script type="text/javascript">
            
function useRanges() {
                
var oRange1 = document.createRange();
                
var oRange2 = document.createRange();
                
var oP1 = document.getElementById("p1");
                oRange1.selectNode(oP1);
                oRange2.selectNodeContents(oP1);
                
                document.getElementById(
"txtStartContainer1").value = oRange1.startContainer.tagName;
                document.getElementById(
"txtStartOffset1").value = oRange1.startOffset;
                document.getElementById(
"txtEndContainer1").value = oRange1.endContainer.tagName;
                document.getElementById(
"txtEndOffset1").value = oRange1.endOffset;
                document.getElementById(
"txtCommonAncestor1").value = oRange1.commonAncestorContainer.tagName;

                document.getElementById(
"txtStartContainer2").value = oRange2.startContainer.tagName;
                document.getElementById(
"txtStartOffset2").value = oRange2.startOffset;
                document.getElementById(
"txtEndContainer2").value = oRange2.endContainer.tagName;
                document.getElementById(
"txtEndOffset2").value = oRange2.endOffset;
                document.getElementById(
"txtCommonAncestor2").value = oRange2.commonAncestorContainer.tagName;
            }
        
</script>
    
</head>
    
<body><id="p1"><b>Hello</b> World</p>
        
<input type="button" value="Use Ranges" onclick="useRanges()" />        
        
<table border="0">
        
<tr>
            
<td>
                
<fieldset>
                    
<legend>oRange1</legend>
                    Start Container: 
<input type="text" id="txtStartContainer1" /><br />
                    Start Offset: 
<input type="text" id="txtStartOffset1" /><br />
                    End Container: 
<input type="text" id="txtEndContainer1" /><br />
                    End Offset: 
<input type="text" id="txtEndOffset1" /><br />
                    Common Ancestor: 
<input type="text" id="txtCommonAncestor1" /><br />    
                
</fieldset>
            
</td>
            
<td>
                
<fieldset>
                    
<legend>oRange2</legend>
                    Start Container: 
<input type="text" id="txtStartContainer2" /><br />
                    Start Offset: 
<input type="text" id="txtStartOffset2" /><br />
                    End Container: 
<input type="text" id="txtEndContainer2" /><br />
                    End Offset: 
<input type="text" id="txtEndOffset2" /><br />
                    Common Ancestor: 
<input type="text" id="txtCommonAncestor2" /><br />
                
</fieldset>
            
</td>
        
</tr>
        
</table>
        
<p><strong>Note:</strong> This example uses DOM ranges and will only work in browsers that support DOM ranges. This example will fail in Internet Explorer.</p>

    
</body>
</html>


(4)复杂选区
通过setStart和setEnd来实现复杂选区,两个方法都接受两个参数:节点引用和偏移量。

(5)与范围对象的交互
<1>deleteContents(),删除范围内容
<2>extractContents,与deleteContents()相似,只不过返回被删除的文档碎片
<3>cloneContents(),创建范围内容副本
<4>surroundContents(node),插入包围范围的内容
<5>insertNode(node),在选区开头插入节点
<6>cloneRange(),复制范围
<7>detach(),释放系统资源
<8>compareBoundaryPoints()方法,比较范围,两个参数,一个比较规则(Range.START_START,
Range.START_TO_END,Range.END_TO_START,Range.END_TO_END),一个是比较的范围引用


2.IE中的范围
IE的范围并不标准,主要用来处理文本节点,调用<body/>,<button/>,<input/>,<textarea>节点的createTextRange方法来创建范围,建议用document.body.createTextRange()来创建,因为其他元素创建的范围仅能用于它们内部。
(1)简单选区:
同样以下面这段代码为例子:

<id="p1"><b>hello</b>world</p>


要选择hello,可以使用:

var oRange=document.body.createTextRange();
oRange.findText("hello");


findText方法还可以接受第2个参数,如oRange.findText("hello",1);将选择hello之后再次找到的hello文本节点。
与DOM中的selectNode方法最相似的是IE的moveToElementText()方法,比如我们要选中p1节点以及它的所有子节点:

var oRange=document.body.createTextRange();
var oP1=document.getElementById("p1');
oRange.moveToElementText(oP1);
alert(oP1.htmlText);


另外,oRange.parentElement()返回选区的父节点。

(2)复杂选区:
move(),moveStart(),moveEnd(),expand()方法实现复杂选区,这些方法都接受两个参数:移动的单位("character","word","sentence","textedit")和移动的单位的个数。

(3)与范围交互
<1>text属性,比如oRange.text="hello";
<2>pasteHTML(),插入HTMl代码,比如oRange.pasteHTML("<em>test</em>");
<3>duplicate(),复制范围
<4>compareEndPoints() 方法,比较范围,第一个参数也是比较规则("StartToStart","StartToEnd,EndToStart","EndToEnd")和比较的范围引用。也可以通过isEqual()和isRange()方法来比较。

3.范围的常见应用,比如搜索引擎中,搜索出来的链接中的关键字用特别的颜色包围起来,另外就是网页广告比较常用。

posted @ 2009-06-29 16:22  Devbar  阅读(488)  评论(2编辑  收藏  举报