现在的位置: 首页 > 综合 > 正文

Professional javascript For Web Developers 第2版读书笔记第4集DOM

2012年09月28日 ⁄ 综合 ⁄ 共 9794字 ⁄ 字号 评论关闭

DOM即文档对象模型,是由ECMA定义的操作html/xml的API,但是值得注意的是IE中的DOM对象都是由COM对象来表示的,也就是说他们和原生的js对象在操作上可能会不同。

浏览器渲染的顺序为:

1 HTML解析完毕。
2 外部脚本和样式表加载完毕。
3 脚本在文档内解析并执行。
4 HTML DOM 完全构造起来。
5 图片和外部内容加载。
6 网页完成加载。
 

HTML可以由树形结构表示,如:

 

1.节点NODE对象

  有以下值:

 (感觉有点象枚举,不过js没有枚举的概念)

  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)  
 如要判断节点类型:

 

if (someNode.nodeType == Node.ELEMENT_NODE){   //won’t work in IE
    alert(“Node is an element.”);

//IE没有暴露NODE的构造函数,上面会报错

if (someNode.nodeType == 1){   //works in all browsers
    alert(“Node is an element.”);

//为了使代码有更好的兼容性,用比较值的方式

 

node对象有2个属性nodeName和nodeValue可以得到关于节点的信息

if (someNode.nodeType == 1){
    value 
= someNode.nodeName;   //will be the element’s tag name

nodeValue基本上就是null值,nodeValue就是标签名(tag name)

 

node有个childNodes属性来访问子节点,可以认为chidNodes是一个NodeList(节点序列),NodeList感觉上像一个数组能够通过索引来访问每个子节点,但实际上它 并不是一个数组的实例,Nodelist实际上是在运行时动态的去查询DOM树。

var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length; 

访问子节点的方式如上

 

如果要将NodeList转换成Array

//won’t work in IE
var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);  

function convertToArray(nodes){
    
var array = null;
    
try {
        array 
= Array.prototype.slice.call(nodes, 0);  //non-IE需要手动的去遍历,ie是用COM实现,前面说过
    } catch (ex) {
        array 
= new Array();
        
for (var i=0, len=nodes.length; i  <  len; i++){
            array.push(nodes[i]);
        }
    }
                   
    
return array;

同辈元素

 

if (someNode.nextSibling === null){
    alert(“Last node 
in the parent’s childNodes list.”);
else if (someNode.previousSibling === null){
    alert(“First node 
in the parent’s childNodes list.”);

// Note that if there ’ s only one child node, both   nextSibling  and   previousSibling  will be   null . 

node之间的关系如下图

 

   hasChildNodes()方法判断是否有子节点,比访问childNodes.length>0效率高,前面说过childNodes是动态查询的

  ownerDocument属性指向当前node对象所在文档的Document对象,node是不能脱离document而存在的。

 

 操作节点:

节点的关系指针都是只读的

 

var returnedNode = someNode.appendChild(newNode);//返回添加的节点对象,始终添加到最后一个位置,并且跟这个新插入节点有关系的节点的指针都会被更新,如新插入节点的父节点,兄弟节点
alert(returnedNode == newNode);         //true
alert(someNode.lastChild == newNode);   //true 

如果appendChild方法加入参数,且这个参数是DOM中已经存在的节点,那么它就会从原来的位置移除,然后添加到指定节点的子节点的最后一个位置

 

var returnedNode = someNode.appendChild(someNode.firstChild);
alert(returnedNode 
== someNode.firstChild);  //false
alert(returnedNode == someNode.lastChild);   //true  

insertBefore()接受2个参数,第一个参数是要待加入的节点对象,第2个参数是一个节点对象的引用,待加入第一个参数的节点将会添加到第2个参数的节点的前面

//insert as last child
returnedNode = someNode.insertBefore(newNode, null);
alert(newNode 
== someNode.lastChild);  //true
                   
//insert as the new first child
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode 
== newNode);         //true
alert(newNode == someNode.firstChild);  //true
                   
//insert before last child
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
alert(newNode 
== someNode.childNodes[someNode.childNodes.length-2]);  //true  

如果第2个参数为null,此方法等同与appendChild。

 

replaceChild()接受2个参数,第一个参数为要添加的节点,第2个参数为被替换的节点

//replace first child
var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
                   
//replace last child
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);  
//被替换的节点作为函数返回值,并且从文档树上移除,新添加的节点将复制原来被替换节点的关系指针

严格来说被替换的节点仍然被文档对象拥有,但是在文档对象中已经没有具体的位置

 

removeChild()用来移除子节点,参数为要移除的子节点对象,同样被删除的节点仍然被文档对象拥有,但是在文档对象中已经没有具体的位置。

并不是所有的节点类型都能拥有子节点,如果没有子节点的类型调用上述方法将会抛出错误。

 

2.文档类型(document type)

 document对象是一个HTMLDocument(继承Document)对象的实例,并且代表的是整个HTML页面,同时也属于window全局的属性

document的特性有:

  nodeType是9.
  nodeName是“ #document ” .  
  nodeValue是null .
  parentNode是null.
  子节点可能是DocumentType  (maximum of one),   Element  (maximum of one), ProcessingInstruction , or   Comment .  
  The   Document  type constructor and prototype are accessible in script for all browsers
except IE. The   HTMLDocument   type constructor and prototype are accessible in all
browsers, including IE beginning with version 8.

document的domain属性是可以设置的,出于安全性考虑,一个页面上的js对象是不能被另外一个页面访问到的,但如果2个页面在不同的子域中,则设置document.domain是可以实现的

 如www.wrox.com  和    p2p.wrox.com,若2个页面的document.domain=wrox.com则可以互相访问,另外设置了wrox.com后再设置更具体的域是不行的

 document.domain = “wrox.com”;        //loosen - succeeds
                   
document.domain = “p2p.wrox.com”;    //tighten - error! 

 

 定位元素的方法有  getElementById()和getElementsByTagName()。

getElementById()需要注意的是

  ie8之前版本对id是不区分大小写的

  如果有多个相同的id的元素,则返回第一个出现的

  IE8之前版本使用getElementById()方法,也会返回name有相同名称的元素

   < input type=”text” name=”myElement” value=”Text field” >
   < div id=”myElement” > A div < /div >

getElementsByTagName() 返回一个HTMLCollection集合,这个对象和前面提到的NodeList很像(严格来说W3C标准规定返回的应该是NodeList),它是一个动态查询的

var images = document.getElementsByTagName(“img”);
alert(images.length);        
//output the number of images
alert(images[0].src);        //output the src attribute of the first image
alert(images.item(0).src);   //output the src attribute of the first image  
var myImage = images.namedItem(“myImage”);
//总是选出第一个匹配的
var myImage = images[“myImage”];
 
//2者效果一样,images[“myImage”]调用的是images.namedItem(“myImage”),而images[0]调用的是images.items[0]

 

getElementsByTagName('*')返回所有标签

 

  getElementsByName()是定义在HTMLDocument上的方法,常用来选择单选按钮表示要post服务器上的值

 

 < fieldset > 
     
< legend >  Which color do you prefer?  < /legend > 
     
< ul > 
         
< li >  < input type=”radio” value=”red” name=”color” id=”colorRed” > 
             
<  label for=”colorRed”  > Red < /label >  < /li > 
         
< li >  < input type=”radio” value=”green” name=”color” id=”colorGreen” > 
             
<  label for=”colorGreen”  > Green < /label >  < /li > 
         
< li >  < input type=”radio” value=”blue” name=”color” id=”colorBlue” > 
             
<  label for=”colorBlue”  > Blue < /label >  < /li > 
     
< /ul > 
 
< /fieldset > 

  document.forms等同于document.getElementsByTagName( “ form ” ).
  document.images等同于document.getElementsByTagName( “ img ”  ).
  document.links   Contains all    <  a  >    elements with an   href  attribute in the document.  
 

 3.元素类型(element type)

元素类型的特性:

  nodeType 是 1.
  nodeName  是元素的标签名 tag name,等效与tagName属性.
  nodeValue是null .
  parentNode可能是Document  or   Element .
  Child nodes may be   Element ,   Text ,   Comment ,   ProcessingInstruction ,   CDATASection , or
  EntityReference .  

 在HTML中,tagName的值总是大写的标签名

if (element.tagName == “div”){  //AVOID! Error prone!
    //do something here
}
                   
if (element.tagName.toLowerCase() == “div”){ //Preferred - works in all documents
    //do something here

元素标准的5个属性

   id   —  A unique identifier for the element in the document.
  title   —  Additional information about the element, typically represented as a tooltip.
  lang   —  The language code for the contents of the element (rarely used).
  dir   —  The direction of the language,    “ ltr ”    (left - to - right) or    “ rtl ”    (right - to - left); also rarely
used.
  className   —  The equivalent of the   class  attribute, which is used to specify CSS classes on an
element. The property could not be named   class  because   class  is an ECMAScript reserved
word

 元素的属性名不是区分大小写的所以“ID”和“id”一样

 操作元素属性的方法有  getAttribute() ,   setAttribute() , removeAttribute()

自定义的属性不会添加到元素对象上作为属性,自带的可以,但是IE会添加,如:

 < div id=”myDiv” align=”left” my_special_attribute=”hello” >  < /div > 

alert(div.id);                    
//”myDiv”
alert(div.my_special_attribute);  //undefined (except in IE)
alert(div.align);                 //”left” 

NOTE:当getAttribute()作用于style时返回结果为css的文本值,而用div.style返回的是一个js对象,另外一个具有同样特点的属性就是事件处理程序如onclick等,有鉴于此,js操作DOM是优先使用属性值读取,对自定义的属性采用getAttribute()方法。

 In IE versions 7 and earlier, the   getAttribute()  method for the  
style  attribute and event handling attributes such as   onclick  always return the same
value as if they were accessed via a property. So,   getAttribute( “ style ” )   returns an
object and   getAttribute( “ onclick ”  )  returns a function. Though fixed in IE 8.0, this
inconsistency is another reason to avoid using   getAttribute()  for HTML attributes.

 

  setAttribute()设置属性值,第一个参数为属性名,第2个为值,如果存在则覆盖,不存在则创建,但是属性名被标准化为小写 ,

 元素的attributes对象

    getNamedItem()
  removeNamedItem()

  setNamedItem()

  item()

 

 

var id = element.attributes.getNamedItem(“id”).nodeValue;  

var id = element.attributes[“id”].nodeValue; 
 
element.attributes[“id”].nodeValue 
= “someOtherId”;  

attrbutes属性很重要的用途是用来遍历DOM

function outputAttributes(element){
    
var pairs = new Array();
    
for (var i=0, len=element.attributes.length; i  <  len; i++){
        
var attrName = element.attributes[i].nodeName;
        
var attrValue = element.attributes[i].nodeValue;
        pairs.push(attrName 
+ “=\”” + attrValue + “\””);
    }
    
return pairs.join(“ “);

如果要遍历设置了值的属性,则

function outputAttributes(element){
    
var pairs = new Array();
    
for (var i=0, len=element.attributes.length; i  <  len; i++){
        
var attrName = element.attributes[i].nodeName;
        
var attrValue = element.attributes[i].nodeValue;
        
if (element.attributes[i].specified){
            pairs.push(attrName 
+ “=\”” + attrValue + “\””);
        }
    }
    
return pairs.join(“ “);

元素的创建可以通过createElement方法,使用此方法后,被创建的元素的  ownerDocument属性会被自动设置

 

var div = document.createElement(“div”); 
div.id 
= “myNewDiv”;
div.className 
= “box”; 

要注意的是虽然元素被创建了,但是并没有添加到DOM树中来,使用appendChild() ,   insertBefore() , 或   replaceChild() 可以添加进来

document.body.appendChild(div);

当元素被添加到DOM树中后,浏览器会马上渲染,此后对此元素的操作都会在浏览器中反映出来。

 

NodeList对象是一个动态的对象,文档结构的任何改变都能及时的得以体现,它是运行时动态的去读取数据,类似的还有   NamedNodeMapHTMLCollection

 

var divs = document.getElementsByTagName(“div”);
                   
for (var i=0; i  <  divs.length; i++){
    
var div = document.createElement(“div”);
    document.body.appendChild(div);

此例会造成死循环,因为divs对象是一个HTMLCollection集合,因此divs.length每次访问时都会动态变化,如要遍历NodeList等对象,需要构造一个中间变量

var divs = document.getElementsByTagName(“div”);
                   
for (var i=0, lens=divs.length; i  <  len; i++){
    
var div = document.createElement(“div”);
    document.body.appendChild(div);

 

 

 

 

抱歉!评论已关闭.