订阅 订阅  :: 管理

JavaScript 学习笔记之二----DOM(1)

Posted on 2010-05-10 23:53  hfCoder  阅读(386)  评论(0)    收藏  举报

         通常写JavaScript都对应到对DOM的操作,久而久之就显得对DOM的操作是JS的核心所在,虽然很多不同意这个看法,但是真正在写js的时候更多就是查找到dom元素,然后经过一部分的运算和处理,然后再给dom赋值。这个过程中可能会传回server端。

一、查找dom元素

a)         对根元素的查找<html>是通常html文档中的根元素。使用document.documentElement即可找到。

b)         通过一个element去查找相关element的属性有:firstChild、lastChild、nextSibling、previousSibling、parentNode等。

c)         document.body是html dom中一个通用的方法。可以定位的html中的body元素

d)         document.getElementById和document.getElementsByTagName这2个方法是javascript dom强大支撑。

e)         通过类的值查找元素

function hasClass(name,type)         {

         var r = [];

         var re = new RegExp(“(^|\\s)” + name + “(\\s|$)”);

         

         var e = document.getElementByTagName(type || “*”);

         

         for(var j = 0; j < e.length; j++)  {

                   if (re.test(e[j].className))      

                             r.push(e[j]);

         }

          return r;

}


f)          使用CSS选择器:cssQuery: http://dean.edwards.name/my/cssQuery及jQuery:http://jquery.com/

这里有几点需要注意的是

1、              DOM指针(即b)不仅仅指向的是元素节点,也会指向文本节点,因此在指向的时候会出现一个“臭虫”即空格元素。往往在使用这些指针查找想要的元素节点时却发现不是最近想要的,往往就是因为被空格元素给打乱了。另外文本节点也不是我们需要的对象。《pro javascript tech》给出了如下的方法来帮助我们使用指针查找节点元素。

function cleanWhitespace(element) {

  element = element || document;

  var cur = element.firstChild;

  

  while(cur != null)      {

         if (cur.nodeType == 3 && ! /\S/.test(cur.nodeValue) )     {

                element.removeChild(cur);

          }        else if (cur.nodeType ==1)        {

                cleanWhitespace(cur);

          }

 

           cur = cur.nextSibling;

   }

}


当然这个方法肯定不是我们想要的,一方面是因为他效率低下,另一方面我们没有必要去遍历这整个文档来剔除空格。于是又改进下。

function prev(elem)   {

  do {

         elem = elem.previousSibling;

   }        while(elem && elem.nodeType != 1);

   return elem;

}


怎么样,是不是很熟悉,对了这个就是jQuery的prev()方法的源泉,感谢John Resig。其他的三个方法next()、first()、last()与其同理。

function parent(elem,num)        {

   num = num || 1;       //需要递归的层数

  for(var i = 0; i < num;i++) {

         if(elem != null) {

              elem = elem.parentNode;

         }

    }

    return elem;

}


2、              元素节点的nodeType == 1,文本节点的nodeType == 3,文档节点的nodeType == 9(根元素)。

3、              FF和opera下存在一个原型对象HTMLElement。通过原型继承我们可以做到类似jQuery的链式。

HTMLElement.prototype.next = function()       {

  var elem = this; //这种获取元素的方法涉及到上下文,将在后期补上相关内容

  do     {

        elem = elem.nextSibling;

   } while(elem && elem.nodeType != 1);

   return elem;

};

这个时候我们就可以document.body.next()这样的获取DOM了。Jason Karl Davis 的http://www.browserland.org/scripts/htmlelement/实现了HTMLElement。

4、              (d)的方法仅仅是javascript DOM的自定义函数。document.getElementsByTagName()返回的是NodeList这样的一个类数组。他拥有索引器和遍历,但是没有数组的一些方法。

5、              a || b这种写法在js中非常常用,作用是提供默认值。

 

二、等待dom加载

在浏览器中,一个页面的执行顺序如下:

HTML解析à外部脚本和样式表加载à脚本在文档(document)解析并运行àDOM完全构造à图片和外部内容加载à完成加载。

由于这个顺序问题,我们不能简单是使用js来直接操作DOM,为了解决这个问题,1、我们通常的做法是

window.onload = function()     {…};

也可以这样写

addEvent(window,”load”,function()         {…});

其目的都是在完成加载之后来执行操作DOM的js。然而这样做往往有自己的弊端,比如页面如果外部内容和图片过多,势必会大幅减缓js的执行及时性。

2、我们也可以将js代码放到文档的下面来执行。但是这样做也有弊端,就是代码的混乱。

3、document、document.getELementById及document.getElementsByTagName、document.body可用用来确定DOM是否可用John Resig又一次为我们提出了解决的办法。

function domReady(f)      {

         if(domReady.done)  return f();

         

         if(domReady.timer) {

               domReady.ready.push(f);

         }        else  {

         addEvent(window,”load”,isDOMReady);

         domReady.ready = [f];

         domReady.timer = setInterval(isDOMReady,13);

         }

}

 

function isDOMReady()   {

         if (domReady.done) return false;

         if(document&&document.getElementById && document.getElementsByTagName && document.body) {

                   clearInterval(domReady.timer);

                   domReady.timer = null;

 

                   for(var i = 0; i < domReady.ready.length; i++) {

                   domReady.ready[i]();

        }        

 

        domReady.ready = null;

        domReady.done = true;

}

}


这个解决方案设计的很巧妙,虽然里面没有一句代码是我们看不懂的,但是思路却很清晰,基本上我们可以拿来套用,如果你不希望使用一些现成的库的话。

三、获取元素的内容

a)         文本

元素中可能包含其他元素节点和文本节点。所以获取其中的内容不能直接使用nodeValue。当然在FF以外可以使用innerText,但是不建议这样做,因为兼容性受到比较大的影响,因此可以考虑使用一个通用的方法

function text(e)        {

         var e = e.childNodes || e;

 

         for (var j = 0; j < e.length; j++) {

               t += e[j].nodeType != 1 ? e[j].nodeValue : text(e[j]);/*书中为e[j].childNodes,疑有误。*/

         }

         return t;

}


这样的结果就是在xml DOM中也可以正常使用了。

b)         HTML

innerHTML在所有的浏览器中都支持,但是臭虫也滋生于此。主要的BUG有

1、  FF中innerHTML不会返回<style>元素

2、  IE中innerHTML返回的元素都是大写

3、  Xml DOM不支持。

可以构建一个通过识别浏览器的方式来处理innerHTML。

四、操作元素特性

function hasAttribute(elem,name) {

         return elem.getAttribute(name) != null;

}


                   getAttribute/setAttribute可以用来获取和设置特性,同时还有setter/getter方式(html dom only)来做同样的事情。这其中唯一的问题在于某些特性名于js的保留字冲突,比如for(htmlFor)、class(className)等。因此需要注意记忆。因此设计一个通用函数是必要的

function attr(elem, name, value)    {

         if (!name || name.constructor != String)         return ‘’;

         name = {“for”:”htmlFor”, “class”:”className”}[name] || name;

         if(type value != ‘undefined’)    {

                elem[name] = value;

                if (elem.setAttribute)       {

                      elem.setAttribute(name,value);

                }

         }

         return elem[name] || elem.getAttribute(name) || “”;

}

在这里json的这种写法可能是比较酷。

 

PS:写到现在感觉大部分的内容的抄这几本书里的内容,而思想也在其中。其实我很明白我现在的js水平。在这一遍学习过程当中我也在总结一些自己的东西。当这个系列结束的时候也是这个总结写完的时候,我想到那个时候我能够有点自己的见解吧。