精通JavaScript第五章:dom

一、遍历dom

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>introduction to the dom</title>
    <script type="text/javascript">
   1:  
   2:         window.onload = function() {
   3:            document.getElementById("div_").innerHTML= document.documentElement.firstChild.nextSibling.firstChild.firstChild.nodeValue;
   4:         }
   5:     
</script>
</head>
<body>
<h1>介绍dom</h1>
<p class="text">
    这是一个dom的p标签测试
</p>
<ul>
    <li id="everywhere">it can be found everywhere</li>
    <li class="test">it is easy to user.</li>
    <li class="test">it can help you to find what you want, really quickly.</li>
</ul>
 
<div id="div_"></div>
</body>
</html>
IE和其他的浏览器有个地方不同: 该文档下,body下如果使用childNodes.length那么得到的是4,而firefox得到的是9. 因为火狐更加严格,每两个标签之间如果有换行,那么算是一个#text节点。因此遍历节点有了困难。
比如说
document.documentElement.firstChild.nextSibling.firstChild
在ie得到是<h1>,而FF得到是body和h1之间的换行(\n,其nodeType为1)
为什么document.documentElement.firstChild.nextSibling能顺利找到body呢,请看FF下html标签内的innerHTML
 
可以清楚的看到, head和body之间没有换行符。
解决:判断node的nodeType
        function preNode(elem) {
            do { elem = elem.previousSibling; } while (elem && elem.nodeType != 1)
            return elem;
        }
        function nexNode(elem) {
            do { elem = elem.nextSibling; } while (elem && elem.nodeType != 1)
            return elem;
        }
        /*找到第一个标签子节点    首先找到第一个子节点,判断其是不是标签;如果不是,则用
        nexNode一直找到其不是文本的排在它后面的第一个兄弟节点*/
        function firstChildNode(elem) {
            elem = elem.firstChild; return elem && elem.nodeType == 3 ? nexNode(elem) : elem;
        }
        /*获得这个标签内的文本(非换行)    首先找到第一个子节点,    如果是文本标签而且不是换行,
        那么直接返回nodeValue;    如果不是,则用nexNode一直找到其不是文本的排在它后面的第一个兄弟节点,
        再递归调用本身*/
        function nodeText(elem) {
            elem = elem.firstChild;
            return elem && elem.nodeType == 3 && elem.nodeValue != "\n" ?
            elem.nodeValue : nodeText((nexNode(elem) || elem));
        }
.        function first(elem) {
            elem = elem.firstChild;
            return elem && elem.nodeType == 1 ? elem : nexNode(elem);
        }
        function last(elem) {
            elem = elem.lastChild;
            return elem && elem.nodeType == 1 ? elem : preNode(elem);
        }
        function tag(tagname, elem) {
            return (elem || document).getElementsByTagName(tagname);
        }
        function hasClass(classname, tagname) {
            var r = [];
            var re = new RegExp("(^|\\s)" + name + "(\\s|$)");
            var e = document.getElementsByTagName(tagname || "*");
            for (var j = 0; j < e.length; j++) {
                if (re.test(e[j])) r.push(e[j]);
            }
            return r;
        }

通过这几个辅助方法,可以很方便地结合html dom 内置方法跨浏览器操作dom

 

(路过的知识点)HTMLElement

HTMLElement 对象表示 HTML 中的一个元素。

HTMLElement 对象的属性

一个 HTML 文档中的每个元素都有和元素的 HTML 属性对应的属性。这里列出了所有 HTML 标记都支持的属性。其他的属性,都特定于某种具体的 HTML 标记。HTMLElement 对象继承了 NodeElement 对象的标准属性

document.getElementById("div_") instanceof HTMLElement //output true
document.getElementById("div_").constructor  //output HTMLDivElement

通过上面的代码, 我们可以得出html elements 元素都是HTMLElement类型的。

那么,我们直接扩展HTMLElement类型的prototype,是不是每个元素将可以直接使用我们的扩展方法呢?

答案肯定是yes。

.   HTMLElement.prototype.next=function(){ 
        do { 
            elem = elem.nextSibling; 
        } while (elem && elem.nodeType != 1)
        return elem; 
    }
那么document.body.first().next()将很容易地获得P元素
 
书上是这么写的, 也说明只有FF,Safari,opera支持。(可惜,我用任何一个浏览器都没有作用 - -)
 
 

二、判断dom何时加载完毕

浏览器的渲染和操作顺序大致如下:

1、 html解析完毕

2、 外部脚本和样式表加载完毕

3、 html dom完全构造起来

4、 图片和外部内容加载

5、 网页加载完成

因为网页头部并且从外部文件加载的脚本会在html真正构造之前执行,还不能访问并不存在的dom,所以这有个问题需要解决。

一般是等待整个页面加载完成再执行,比如window.onload=function(){}.

部分加载

伪实现。 即把js代码写在html文档的最后。(因为html文档是流形式地加载)

监听dom加载状态(如下图解释)

 

.      function isDOMReady() {
            if (domReady.done) 
                return false;
            if (document 
                && document.getElementsByTagName
                && document.getElementById
                && document.body) //关键的if判断
            { 
                domReady.timer = null;
                for (var i = 0; i < domReady.ready.length; i++)
                    domReady.ready[i]();
 
                domReady.ready = null;
                domReady.done = true;
 
                clearInterval(domReady.timer);
            }
        }
        function domReady(f) {
            if (domReady.done)
                return f();
            if (domReady.timer) {
                domReady.ready.push(f);
            } else {
                domReady.ready = [f];
                domReady.timer = setInterval("isDOMReady()", 13);
            }
        }
    
        domReady(function() {
            alert('dom is loaded!');
            document.getElementsByTagName("h1")[0].style.border = '4px solid red';
        });

三、获得元素的内容

预备知识:

null : 表示无值;
undefined : 表示一个
            未声明的变量
            已声明但没有赋值的变量
            一个并不存在的对象属性。
使用if (!object){}两者就都包含了
 
==运算符将两者看作相等。
typeof运算符类型相等。
===运算符 全相等(值和类型都相等)。
 
.        function hasAttribute(elem, attrName) {
            return elem.getAttribute(attrName) != null;
        }
        /*读取,设置属性*/
        function attr(elem, attrName, attrValue) {
            if (!attrName || attrName.constructor != String) return "";
            attrName = { "for": "htmlFor", "class": "className"}[attrName] || attrName;
            if (typeof attrValue != undefined) {
                elem[attrName] = attrValue;
                if (elem.setAttribute)
                    elem.setAttribute(attrName, attrValue);
            }
            return elem[attrName] || elem.getAttribute(attrName, attrValue) || "";
        }
        //包装为dom节点数组
        function checkElem(arr) {
            var ret = [];
            if (!arr)
                arr = "";
            if (arr.constructor != Array) arr = [arr];
            for (var i = 0; i < arr.length; i++) {
                if (arr[i].constructor == String) {
                    var tempdiv = document.createElement("div");
                    tempdiv.innerHTML = arr[i];
                    for (var j = 0; j < tempdiv.childNodes.length; j++)
                        ret.push(tempdiv.childNodes[j]);
                }
                else if (arr[i].length) {
                    for (var j = 0; j < arr[i].length; j++)
                        ret.push(arr[i][j])
                } else
                    ret.push(arr[i]);
            }
            return ret;
        }
        /* 修改dom 扩展 insertBefore和append 两个方法*/
        function before(parent, before, elem) {
            if (typeof elem == undefined) {
                parent.appendChild(before);
            }
            else {
                var arr = checkElem(elem);
                for (var j = arr.length; j >= 0; j--)
                    parent.insertBefore(arr[j], before);
            }
        }
        function append(parent, elem) {
            var arr = checkElem(elem);
            for (var j = 0; j < arrlength; j++)
                parent.appendChild(arr[j]);
        }
        /* 删除dom的两个方法 */
        function remove(elem) {
            if (elem) elem.parentNode.removeChild(elem);
        }
        function empty(elem) {
            if (elem) {
                while (elem.childNodes && elem.firstChild) {
                    elem.removeChild(elem.firstChild);
                }
            }
        }
        
posted @ 2010-04-08 00:29  MyCoolDog  阅读(400)  评论(0编辑  收藏  举报