通常写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水平。在这一遍学习过程当中我也在总结一些自己的东西。当这个系列结束的时候也是这个总结写完的时候,我想到那个时候我能够有点自己的见解吧。
                    
                
                
            
        
浙公网安备 33010602011771号