DOM基礎+domReady+元素節點類型判斷

DOM節點類型  nodeTypehtml

element  1    Node.ELEMENT_NODE   元素節點node

attr  2   Node.ATTRIBUTE_NODE  屬性節點jquery

text  3    Node.TEXT_NODE   文本節點(標籤之間的空白區域也屬於文本節點)數組

comment   8     Node.COMMENT_NODE   註釋節點瀏覽器

document   9     Node.DOCUMENT_NODE   文檔節點(全部文檔之上,即一個頁面中最最前面的位置,在文檔定義的前面)dom

documentType   10    Node.DOCUMENT_TYPE_NODE   文檔類型節點(DOCTYPE)函數

documentFragment   11    Node.DOCUMENT_FRAGMENT_NODE  文檔片斷節點(不屬於文檔樹,是最小片斷,能夠做爲臨時佔位符,將它插入文檔時,只會插入它的子孫元素,而不是它自己)spa

注意:IE8及如下沒有node,使用常量來判斷nodeType會報錯:「Node」未定義3d

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>

</head>
<body>
    <div id="container"></div>
    <script>
        window.onload=function(){

            var container=document.getElementById("container");
            if(container.nodeType==Node.ELEMENT_NODE){
                alert("是元素節點");
            }
        }    
    </script>
</body>
</html>

 

 所以不建議使用常量來判斷,建議使用數值code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>

</head>
<body>
    <div id="container"></div>
    <script>
        window.onload=function(){

            var container=document.getElementById("container");
            // if(container.nodeType==Node.ELEMENT_NODE){
            //     alert("是元素節點");
            // }
            if(container.nodeType==1){
                alert("是元素節點");
            }
        }    
    </script>
</body>
</html>

 

 nodeName  節點名稱

nodeValue  節點值

.attributes 保存元素的全部屬性,可使用數組下標訪問某一個具體的屬性

.chilsNodes 獲取元素的全部子節點,可使用數組下標訪問某一個具體的屬性

document.doctype  獲取文檔類型節點

document.createDocumentFlagment()  建立文檔片斷

 

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>

</head>
<body>
    <!-- 這是一段註釋哈 -->
    <div id="container">這是裏面的文本鴨</div>
    <script>
        window.onload=function(){

            var container=document.getElementById("container");
            console.log("元素節點:"+container.nodeName+"/"+container.nodeValue);//元素節點:DIV/null
            var attr=container.attributes[0];//獲取元素的第一個屬性
            console.log("屬性節點:"+attr.nodeName+"/"+attr.nodeValue);//屬性節點:id/container
            var text=container.childNodes[0];//獲取元素的第一個子元素節點
            console.log("文本節點:"+text.nodeName+"/"+text.nodeValue);//文本節點:#text/這是裏面的文本鴨
            var comment=document.body.childNodes[1];//獲取body元素的第二個子元素節點(第一個子元素節點是空白文本節點)
            console.log("註釋節點:"+comment.nodeName+"/"+comment.nodeValue);//註釋節點:#comment/ 這是一段註釋哈 
            var doctype=document.doctype;//獲取body元素的第二個子元素節點(第一個子元素節點是空白文本節點)
            console.log("文檔類型節點:"+doctype.nodeName+"/"+doctype.nodeValue);//文檔類型節點:html/null
            var docFragment=document.createDocumentFragment();//獲取body元素的第二個子元素節點(第一個子元素節點是空白文本節點)
            console.log("文檔片斷節點:"+docFragment.nodeName+"/"+docFragment.nodeValue);//文檔片斷節點:#document-fragment/null
        }    
    </script>
</body>
</html>

 

 當script腳本在DOM元素以前,會沒法獲取到DOM元素

由於把js代碼放在head中,代碼順序執行,當頁面在瀏覽器中打開時,會先執行js代碼,再執行body裏面的dom結構。若是js執行時要獲取body中的元素,那麼就會報錯,由於頁面的結構尚未加載進來。

可使用window.onload解決

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>
    <script>
        window.onload=function(){

            var container=document.getElementById("container");
            console.log(container);
        }    
    </script>
</head>
<body>
    <!-- 這是一段註釋哈 -->
    <div id="container">這是裏面的文本鴨</div>

</body>
</html>

window.onload缺點:等待DOM樹的加載和外部資源所有加載完成

若是頁面引用了不少外部資源,會致使加載慢,影響用戶體驗


 

最佳解決方案,jquery的$(document).ready()

此處使用原生js仿寫該方法


 

DOMContentLoaded  加載完dom樹,但尚未開始加載外部資源

IE不支持該方法,使用:document.documentElement.doScroll("left")


 

監聽document的加載狀態  document.onreadystatechange

document加載完成  document.readyState=="complete"

arguments.callee  調用函數自身

本身寫的DomReady.js

function myReady(fn){

    /*
    現代瀏覽器操做
    */
    if(document.addEventListener){
        //現代瀏覽器操做
        document.addEventListener("DOMContentLoaded",fn,false);//false表示在冒泡階段捕獲
    }else{
        //IE環境操做
        IEContentLoaded(fn);
    }

    /*
    IE環境操做
    */
    function IEContentLoaded(fn){

        // init()--保證fn只調用一次
        var loaded=false;
        var init=function(){
            if(!loaded){
                loaded=true;
                fn();
            }
        }

        // 若是DOM樹加載還沒完成,就不停嘗試
        (function(){
            try{
                // 若是DOM樹加載還沒完成,會拋出異常
                document.documentElement.doScroll("left");
            }catch(e){
                // 嘗試失敗,則再次嘗試
                setTimeout(arguments.callee,50);
                return;//實現遞歸
            }
            //若是沒有拋出異常,則馬上執行init()
            init();
            
        })();

        // DOM樹加載完成以後,調用init()方法
        document.onreadystatechange=function(){
            if(document.readyState=="complete"){
                document.onreadystatechange=null;//清除監聽事件
                init();
            }
        }
    }
}

調用該js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>
    <script src="DomReady.js"></script>
    <script>
        myReady(function(){
            var container=document.getElementById("container");
            console.log(container);
        });
    </script>
</head>
<body>
    <!-- 這是一段註釋哈 -->
    <div id="container">這是裏面的文本鴨</div>

</body>
</html>

實現各瀏覽器都能成功獲取到~

下面來真實感覺下window.onload 和domReady的區別!!!

使用多張大圖圖片來模擬加載時長

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>
    <script src="DomReady.js"></script>

</head>
<body>
    <!-- 這是一段註釋哈 -->
    <div id="container">這是裏面的文本鴨</div>
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">
    <img src="source/cat.jpg">

    <script>

        myReady(function(){
            alert("domReady!");
            domready=new Date().getTime();
        });

        window.onload=function(){
            alert("windowLoaded!");
            windowload=new Date().getTime();
        }

    </script>
</body>
</html>

發現先彈出domReady

等到圖片加載完成以後,才彈出windowLoaded

證明windowLoaded耗時比較久


 

元素節點的類型判斷

isElement() 判斷是不是元素節點

isHTML() 判斷是不是html文檔的元素節點

isXML() 判斷是不是xml文檔的元素節點

contains()  判斷元素節點之間是不是包含關係

.nextSibling  獲取元素的兄弟節點

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>
    <script src="DomReady.js"></script>

</head>
<body>
    
    <div id="container">這是裏面的文本鴨</div><!-- 這是一段註釋哈 -->

    <script>

        myReady(function(){
            
            function isElement(el){
                return !!el && el.nodeType===1;
            }

            console.log(isElement(container));
            console.log(isElement(container.nextSibling));
        });

    </script>
</body>
</html>

該方法有一個Bug,即若是有一個對象設置了nodeType屬性,會致使判斷錯誤

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>
    <script src="DomReady.js"></script>

</head>
<body>
    
    <div id="container">這是裏面的文本鴨</div><!-- 這是一段註釋哈 -->

    <script>
        
        myReady(function(){
            
            function isElement(el){
                return !!el && el.nodeType===1;
            }

            var obj={
                nodeType:1
            }
            console.log(isElement(obj));//true
        });

    </script>
</body>
</html>

isXML() 最嚴謹的寫法

.createElement() 建立元素

若是不區分大小寫,則爲html文檔的元素節點;

若是區分大小寫,則爲xml文檔的元素節點

.ownerDocument返回元素自身的文檔對象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>
    <script src="DomReady.js"></script>

</head>
<body>
    
    <div id="container">這是裏面的文本鴨</div><!-- 這是一段註釋哈 -->

    <script>
        
        myReady(function(){
            // 判斷是不是元素節點
            function isElement(el){
                return !!el && el.nodeType==1;
            }
            // 判斷是不是xml文檔
            function isXML(el){
                return el.createElement("p").nodeName!==el.createElement("P").nodeName;
            }
            // 判斷是不是html文檔
            function isHTML(el){
                return el.createElement("p").nodeName===el.createElement("P").nodeName;
            }
            // 判斷是不是html文檔的元素節點
            function isHTMLNode(el){
                if(isElement(el)){
                    return isHTML(el.ownerDocument);
                }
                return false;
            }
            console.log(isXML(document));//false
            console.log(isHTML(document));//true
            console.log(isHTMLNode(container));//true
        });

    </script>
</body>
</html>

.containers 判斷某個節點是否包含另外一個節點

谷歌瀏覽器表現正常,而IE瀏覽器要求兩個節點都必須是元素節點

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>
    <script src="DomReady.js"></script>

</head>
<body>
    
    <div class="parent" id="parent">
        <div class="child" id="child">這是文本節點</div>
    </div>

    <script>
        
        myReady(function(){
            var parent=document.getElementById("parent");
            var child=document.getElementById("child");
            console.log(parent.contains(child));//true

            var text=child.childNodes[0];
            console.log(parent.contains(text));//谷歌瀏覽器true,IE瀏覽器爲false
        });

    </script>
</body>
</html>

接下來給出兼容性寫法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width:100%;
            height:100%;
        }
    </style>
    <script src="DomReady.js"></script>

</head>
<body>
    
    <div class="parent" id="parent">
        <div class="child" id="child">這是文本節點</div>
    </div>

    <script>
        
        myReady(function(){
            var parent=document.getElementById("parent");
            var child=document.getElementById("child");
            console.log(parent.contains(child));//true

            var text=child.childNodes[0];
            console.log(parent.contains(text));//谷歌瀏覽器true,IE瀏覽器爲false

            function fixContains(pNode,cNode){
                try{
                    while(cNode=cNode.parentNode){
                        if(pNode===cNode) return true;
                    }
                    return false;
                }catch(e){
                    return false;
                }
            }
            console.log(fixContains(parent,text));//谷歌瀏覽器true,IE瀏覽器爲true
        });

    </script>
</body>
</html>

在全部瀏覽器裏都能返回true,哪怕不是元素節點

相關文章
相關標籤/搜索