javascript_dom_总结

javascript_dom_小结

 

Dom是浏览器管理这么一个html文档的方式,如同对xml文件一样,只不过这里用javascript来操作而不是其他语言如java、ruby。

 

下面是又看一遍Professional.JavaScript.for.Web.Developers后,对dom的一个总结,参考了一些笔记。

 

一、dom是什么

    Dom:英文全称-Document Object Model 译成中文即是:文档对像模型.听起来很术语,其实就是文档内容的结构关系.文档类型可以是HTML或XML。

    熟悉xml的大都清楚,xml就是一个文档,由节点、属性等组成,我们可以利用sax或者dom4j等分析这个文档,对元素执行遍历和CRUD操作。对html也是一样,可以把javascript中操作html 理解为 用java操作xml。

 

二、dom的接口和元素

dom是文档对象模型,我们更关心dom的节点层次,节点操作。

dom的节点关系或者类层次如下(只是理解,详细情况官方的文档):

                  

Node 是所有节点的父接口

    Node的子接口或实现如下:

❑ Node.ELEMENT _NODE (1)
❑ Node.ATTRIBUTE _NODE (2)
❑ Node.TEXT _NODE (3)
❑ Node.CDATA_SECTION_NODE (4)
❑ Node.ENTITY_REFERENCE_NODE (5)
❑ Node.ENTITY_NODE (6)
❑ Node.PROCESSING_INSTRUCTION_NODE (7)
❑ Node.COMMENT _NODE (8)
❑ Node.DOCUMENT _NODE (9)
❑ Node.DOCUMENT_TYPE_NODE (10)
❑ Node.DOCUMENT_FRAGMENT_NODE (11)
❑ Node.NOTATION_NODE (12)

具体到这些接口有哪些方法,子node有哪些方法,需要查看api文档。(可以下载一个javascript dom 文档)

 

三、核心的dom的接口操作(节点操作)


1,    创建节点。
createElement ():
var a = document.createElement(“p”);
它创建的是一个元素节点,所以 nodeType 等于 1 。
a.nodeName 将返回 p ;
注意;createElement()方法创建出来的新元素节点不会被自动添加到文档里,既然没添加到文档里,说明它还是一个游离的状态。所以它也没有nodeParent属性。
如果想把它添加到文档里,可以使用 appendChild()或者insertBefore()方法或者replaceChild()方法。当然我们在前面的例子中,自己写了一个insertAfter()方法;
比如:
var a = document.createElement(“p”);
document.body.appendChild(a);
注意: appendChild()默认是添加到文档的最后。也就是lastChild子节点。
如果想添加到某个地方,可以使用insertBefore()。
如果想在元素插入之前给元素添加属性。可以这么做:
var a = document.createElement(“p”);
a.setAttribute(“title”,”my demo”);
document.body.appendChild(a);

 

createTextNode ():
var b = document.createTextNode(“my demo”);
它创建的是一个文本节点,所以nodeType等于 3 。
b.nodeName 将返回 #text ;
跟createElement()一样,用createTextNode()创建的节点也不会自动添加到文档里。需要使用appendChild()或者insertBefore()方法或者replaceChild()方法。
他经常与createElement()配合使用,知道为什么吗?(一个元素节点,一个文本节点。)
var mes = document.createTextNode(“hello world”);
var container = document.createElement(“p”);
container.appendChild(mes);
document.body.appendChild(container);


2,    复制节点。
cloneNode (boolean ) :
它有一个参数。
var mes = document.createTextNode("hello world");
var container = document.createElement("p");
container.appendChild(mes);
document.body.appendChild(container);
var newpara = container.cloneNode(true);//true和false的区别
document.body.appendChild(newpara );
注意:
true的话:是<p>aaaa</p> 克隆。
false: 只克隆 <p></p> ,里面的文本不克隆。

可以自己写个例子,然后用 firebug 看看。

克隆后的新节点,和createTextNode()一样 不会被自动插入到文档 。需要appendChild();
另外还有一个注意: 如果克隆后,id一样,不要忘记用 setAttribute(“id” , “ another_id “);
改变新的节点的ID。

 

3,    插入节点。
appendChild () :
给元素追加一个子节点, 新的节点 插入到 最后。
var container = document.createElement("p");
var t = document.createTextNode("cssrain");
container.appendChild(t);
document.body.appendChild(container);
他经常跟createElement()和createTextNode(),cloneNode()配合使用。
另外 appendChild()不仅可以用来追加新的元素,也可以你 挪动 文档中现有的元素
看下面的例子:
<p id="msg">msg</p>
<p id="content">content</p>
<p id="aaa">aaaaaaaa</p>
<script>
var mes = document.getElementById("msg");
var container = document.getElementById("content");
container.appendChild(mes);
</script>
//发现msg放到 content 后面去了 。
Js内部处理方式:
先把ID为msg的从文档中删除,然后再插入到content 后,作为content的最后一个节点。
结果为:
<p id="content">
content
<p id="msg">msg</p>
</p>
<p id="aaa">aaaaaaaa</p>

 

insertBefore () :
顾名思义,就是把一个新的节点插入到目标节点的前面。
Element. insertBefore( newNode , targerNode ); // 也可以你 挪动 文档中现有的元素

第二个参数是可选,如果第二个参数不写,将默认添加到文档的最后,相当于appendChild();
我们看看insertBefore()怎么使用:
<div id="cssrian">
<p id="content">1111</p>
<div id="msg">msg<div>test</div></div>
<p id="content">222</p>
<p id="aaa">aaaaaaaa</p>
</div>
<script>
var msg = document.getElementById("msg");
var aaa = document.getElementById("aaa");
var test = document.getElementById("cssrian");
test.insertBefore( msg , aaa );
</script>
// 我们发现ID为msg的 插入到了 aaa的前面。
Js内部处理方式跟 appendChild()相似。


4,    删除节点。
removeChild()    :
<body>
<div id="cssrain">
<div id="a">a </div>
<div id="b">b </div>
<div id="c">c </div>
</div>
</body>
<script>
var msg = document.getElementById("cssrain");
var b = document.getElementById("b");
msg.removeChild(b);
</script>
如果不知道要删除的节点的父节点是什么?可以使用parentNode 属性。
比如:
<body>
<div id="cssrain">
<div id="a">a </div>
<div id="b">b </div>
<div id="c">c </div>
</div>
</body>
<script>
var b = document.getElementById("b");
var c = b.parentNode;
c.removeChild(b);
</script>

注意: 你如果想把某个节点从一处移动到另一个地方,不必使用removeChild()。
可以使用前面的 appendChild()和insertBefore(),他们都会自动先删除节点,然后移动到你指定的地方。、


5,    替换节点。
Element.repalceChild( newNode , oldNode );
OldNode必须是Element的一个子节点。
<body>
<div id="cssrain">
<div id="a">a </div>
<div id="b">b </div>
<div id="c">c </div>
</div>
</body>
<script>
var cssrain = document.getElementById("cssrain");
var msg = document.getElementById("b");
var para = document.createElement("p");
cssrain.replaceChild( para , msg );
</script>


6,    设置/获取节点属性。
setAttribute ();//设置
例子:
var a = document.createElement(“p”);
a.setAttribute(“title”,”my demo”);
不管以前有没有title属性,以后的值是 my demo。

getAttribute();//获取
例子:
var a =document.getElementById(“cssrain”);
var b = a.getAttribute (“title”);
获取的时候,如果属性不存在,则返回空,注意ie和ff返回不同,可以看我以前的例子。
返回虽然不同,但是可以用一个方法来判断。
if(a.getAttribute(“title”) ){   }


7,    查找节点。
getElementById ();
返回一个对象, 对象拥有 nodeName , nodeType , parentNode , ChildNodes 等属性。

getElementsByTagName() 查找标签名的所有元素。
返回一个集合,可以用循环取出每个对象,对象拥有 nodeName , nodeType , parentNode , ChildNodes 等属性。
例子:
var ps = document.getElementsByTagName(“p”);
for(var i=0 ; i< ps.length ; i++){
           ps[i].setAttribute(“title”,”hello”);
//也可以使用: ps.item(i).setAttribute("title","hello");
}


hasChildNodes :
由名字就可以知道,是判断元素是否有子节点。
返回boolean类型。
文本节点和属性节点不可能有子节点,所以他们的hasChildNodes 永远返回false;
hasChildNodes经常跟 childNodes 一起使用。
比如:
<body>
<div id="cssrain">
<div id="a">a </div>
<div id="b">b </div>
<div id="c">c </div>
</div>
</body>
<script>
var ps = document.getElementById("cssrain")
if(ps.hasChildNodes){
        alert( ps.childNodes.length );    
}
</script>

 

8, DOM属性:

 

document ,这是window的子对象,可以直接使用,表示整个页面

var nodeHtml = document.documentElement ;//可以获得<html />元素dom的根节点

var nodeHead = document.childNodes[0];//<head />元素

var nodeBody = document.childNodes[1];//<body />元素

alert(document.childNodes[0] == document.firstChild);//true

alert(document.childNodes[1] == document.lastChild);//true

 

nodeName 属性 : 节点的名字
如果节点是元素节点,那么返回这个元素的名字。此时,相当于tagName属性。
比如:
<p>aaaa</p> : 则返回 p ;
如果是属性节点,nodeName将返回这个属性的名字。
如果是文本节点,nodeName将返回一个#text的字符串。

另外我要说的是: nodeName属性是一个只读属性,不能进行设置.(写)

 

nodeType属性 : 返回一个整数,代表这个节点的类型。
我们常用的3中类型:
nodeType == 1 : 元素节点
nodeType == 2 : 属性节点
nodeType == 3 : 文本节点
如果想记住的话,上面的顺序我们可以看做是从 前到后。
比如: <p title="cssrain" >test</p>   从前往后读: 你会发现 先是元素节点,然后是属性节点,最后是文本节点,这样你就很容易记住了 nodeType分别代表什么类型了。

nodeType属性经常跟 if 配合使用,以确保不会在错误的节点类型上 执行错误的操作。
比如:
function cs_demo(mynode){
      if(mynode.nodeType == 1){
              mynode.setAttribute("title","demo");
        }
}
代码解释: 先检查mynode的nodeType属性,以确保它所代表的节点确实是 一个元素节点。
和nodeName属性一样,他也是只读属性,不能进行设置.(写)。

 

nodeValue属性 : 返回一个字符串,这个节点的值。
如果节点是元素节点,那么返回null;(注意下)
如果是属性节点,nodeName将返回这个属性的值。
如果是文本节点,nodeName将返回这个文本节点的内容。
比如:
<div id="c">aaaaaaaaaaaaaaaa</div>
<SCRIPT LANGUAGE="JavaScript">
var c= document.getElementById("c");
alert( c.nodeValue );//返回null
</SCRIPT>
nodeValue是一个可以读、写的属性。 但它不能设置元素节点的值。
看下面的例子:
<div id="c">aaaaaaaaaaaaaaaa</div>
<SCRIPT LANGUAGE="JavaScript">
   var c= document.getElementById("c");
   c.nodeValue =" dddddddddddd"; //不能设置
   //alert( c.firstChild.nodeValue ) //元素节点 包括属性节点和文本节点。
   c.firstChild.nodeValue = "test"//能设置
</SCRIPT>
当然我们为了确保能正确运行:可以加一段代码:
<div id="c">aaaaaaaaaaaaaaaa</div>
<SCRIPT LANGUAGE="JavaScript">
   var c= document.getElementById("c");
   c.nodeValue =" dddddddddddd"; //不能设置
   //alert( c.firstChild.nodeValue )
   if( c.firstChild.nodeType==3 ){ //判断是不是 文本节点
       c.firstChild.nodeValue = "test"//能设置
   }
</SCRIPT>
//可以看出,如果要设置元素节点,不能直接设置,而必须先使用firstChild或者lastChild等 然后设置nodeValue.
nodeValue一般只用来设置 文本节点的值。如果要刷新属性节点的值,一般使用setAttribute().


childNodes属性 : 返回一个数组,数组由元素节点的子节点构成。
由于文本节点和属性节点都不可能再包含任何子节点,
所以他们的childNodes属性永远返回一个空数组。


可以使用hasChildNodes方法,它用来判断某个元素有没有子节点。
或者 if (container.childNodes.length < 1) ;

childNodes也是一个只读属性。如果要增加节点,可以使用appendChild()或者insertBefore() ,
删除节点可以使用removeChild(); 操作后,childNodes属性会自动刷新。

 

firstChild 属性
由于文本节点和属性节点都不可能再包含任何子节点,
所以他们的firstChild属性永远返回一个空数组。 如果没有子节点,将返回null;
node.firstChild 等价于 node.childNodes[0] ;
firstChild属性是一个只读属性。


lastChild属性
由于文本节点和属性节点都不可能再包含任何子节点,
所以他们的lastChild属性永远返回一个空数组。 如果没有子节点,将返回null;
node.lastChild 等价于 node.childNodes[ node.childNodes.length - 1 ] ;
lastChild属性是一个只读属性。

 

nextSibling 属性 :
返回目标节点的下一个兄弟节点。
如果目标节点后面没有同属于一个父节点的节点,nextSibling 将返回null ;
nextSibling 属性是一个只读属性。

 

previousSibling属性 :
返回目标节点的前一个兄弟节点。
如果目标节点前面没有同属于一个父节点的节点,previousSibling 将返回null ;
previousSibling 属性是一个只读属性。

 

parentNode 属性 :
注:parentNode属性返回的节点永远是一个元素节点,因为只有元素节点才有可能有子节点。
当然有个例外:
document节点,他没有父节点。所以document节点的parentNode属性将返回null;
parentNode 属性是一个只读属性。

 

 

四、Html的dom的接口操作_是dom核心操作的扩展

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

1.让特性像属性一样特性指:node_attribute; 属性指:一个对象的field,例如person.age=28
访问某元素的特性需要用到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的其他(高级技术)

 

一。样式编程


1.样式对象style

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

2.样式对象style的操作:

通过function来操作 (函数操作)(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特性的值

通过field来操作 (属性操作)(都支持)

alert(oDiv.style .backgroundColor );

oDiv.style .backgroundColor = "green" ;

 

3. 样式表

    因为style对象只能访问一个元素的CSS样式,而对于<style />定义的或者外部CSS文件定义的CSS规则没办法访问,这就引出了如何访问样式表的问题。

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

 

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

 

cssRules 是个数组,保存了外部定义的每一个css样例。下面是改进的一个例子。

<html>
<head>
    <title>Accessing Style Sheets Example</title>
    <style type="text/css">
        div.special {
            background-color: red;
            height: 10px;
            width: 10px;
            margin: 10px;
        }

        div.sub1 {
            background-color: green;
            float: left;
        }

        div.sub2 {
            background-color: yellow;
            float: right;
        }
    </style>
    <script type="text/javascript">
        function changeBackgroundColor() {
            var oCSSRules = document.styleSheets[0].cssRules || document.styleSheets[0].rules;
            oCSSRules[0].style.backgroundColor = "blue";
            //遍历输出div.special、div.sub1、div.sub2的css设置
            for (var i = 0; i < oCSSRules.length; i++) {
                var r = oCSSRules[i];
                alert("r:" + r.style.cssText)
            }
        }
    </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>
 

4. 最终样式

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

 

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

  firefox仅仅支持innerHTML,其实innerText也没啥用。

  另外也有outerText和outerHTML,但很不好用了。

 

三。范围

叫选区也许更为恰当,range用来选择文档的某个部分而不管节点的边界。也有两种的范围实现:DOM和IE的。

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

-->>范围是个比较特殊的应用,高级而复杂,本人不打算深究,如果哪天需要,再研究了~

 

 

参考1:

http://hi.baidu.com/kbsy/blog/item/5b0ffdcb5c474ff453664f1f.html

http://hi.baidu.com/kbsy/blog/item/9e3b8c1f1bb4d4fce1fe0b18.html

http://hi.baidu.com/kbsy/blog/item/fdd6ed8f1a71f1f3503d9219.html

参考2:

http://www.web666.net/dom/index.html

参考3:

http://hi.baidu.com/fxlijun/blog/item/28699825970cec6d34a80f86.html

 

I

T

-

E

Y

E