1. 程式人生 > >你不知道的JavaScript--Item32 DOM基礎詳解2

你不知道的JavaScript--Item32 DOM基礎詳解2

先上幾張圖簡要看看DOM的一些方法屬性:

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

大概這些就是常用的,下面具體聊聊。

節點型別的判斷

其中元素節點Element的判定最為重要,下面給出4個主要的方法;

1、如何判斷節點是元素節點

可以用isElement()方法

<div id="test">aaa</div>
<!--這是一個註釋節點-->
<script>
var isElement = function (el){
    return !!el && el.nodeType === 1;
}
var a = {
   nodeType: 1
} console.log(isElement(document.getElementById("test")));//true console.log(isElement(document.getElementById("test").nextSibling));//false //但是很容易偽造一個假的“物件節點” console.log(isElement(a));
</script>

所以要避免這個的偽造,可以重寫isElement()方法

<div id="test">aaa</div>
<!--這是一個註釋節點-->
<script
>
var testDiv = document.createElement('div'); var isElement = function (obj) { if (obj && obj.nodeType === 1) {//先過濾最簡單的 if( window.Node && (obj instanceof Node )){ //如果是IE9,則判定其是否Node的例項 return true; //由於obj可能是來自另一個文件物件,因此不能輕易返回false } try {//最後以這種效率非常差但肯定可行的方案進行判定
testDiv.appendChild(obj); testDiv.removeChild(obj); } catch (e) { return false; } return true; } return false; } var a = { nodeType: 1 } console.log(isElement(document.getElementById("test"))); console.log(isElement(document.getElementById("test").nextSibling)); console.log(isElement(a));
</script>

2、如何判斷節點是html或xml元素節點

XML與html物件均支援createElement()方法,通過比較建立的元素時傳入引數的【大小寫】不同的情況下,元素的nodeName是否相同來判斷是哪一種文件物件。如果nodeName相同則為html物件,反之為XML物件。

1、首先看一下Sizzle, jQuery自帶的選擇器引擎

//Sizzle, jQuery自帶的選擇器引擎
var isXML = function(elem) {
    var documentElement = elem && (elem.ownerDocument || elem).documentElement;
    return documentElement ? documentElement.nodeName !== "HTML" : false;
};
console.log(isXML(document.getElementById("test")));

//但這樣不嚴謹,因為XML的根節點,也可能是HTML標籤,比如這樣建立一個XML文件
try {
    var doc = document.implementation.createDocument(null, 'HTML', null);
    console.log(doc.documentElement);
    console.log(isXML(doc));
} catch (e) {
    console.log("不支援creatDocument方法");
}

2、我們看看mootools的slick選擇器引擎的原始碼:

var isXML = function(document) {
  return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]')
          || (document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
};

//精簡版
var isXML = window.HTMLDocument ? function(doc) {
  return !(doc instanceof HTMLDocument);
} : function(doc) {
  return "selectNodes" in doc;
}

3、自己實現的方法—最簡單

var isXML = function(doc) {
    return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
}

那接下來判斷html節點時,就非常簡單了

var isHTML = function(doc) {
   return doc.createElement("p").nodeName === doc.createElement("P").nodeName;
}
console.log(isHTML(document));

3、判斷節點間的包含關係:

現代瀏覽器可以用contains()方法,aNode.contains(bNode)判斷是否包含a>b。

<div id="p-node">
    <div id="c-node">子節點內容</div>
</div>
<script>
    var pNode = document.getElementById("p-node");
    var cNode = document.getElementById("c-node").childNodes[0];

    alert(document.contains(pNode));//但是在IE8瀏覽器不支援
    alert(pNode.contains(cNode));
</script>

但IE不支援文件型別節點和文字型別節點包含關係的判斷,可以自定義實現一個相容各瀏覽器的判斷方法。

自定義實現fixContains()方法是對這個問題的修復。

  <div id="p-node">
<div id="c-node">子節點內容</div>
</div>
<script>
//判斷節點a包含節點b的方法,即a和b的父節點比較;
function fixContains(a, b) {
    try {
        while ((b = b.parentNode)){
            if (b === a){
                return true;
            }
        }
        return false;
    } catch (e) {
        return false;
    }
}
var pNode = document.getElementById("p-node");
var cNode = document.getElementById("c-node").childNodes[0];
alert(fixContains(pNode, cNode));
//alert(fixContains(document, cNode));
</script>

節點繼承層次與巢狀規則

1、DOM節點繼承層次

1、文字節點繼承層次—-有6層關係

2、元素節點繼承層次—-有7層關係

console.log(Object.getOwnPropertyNames(document.createElement("p").__proto__));//第一層有兩個屬性
console.log(Object.getOwnPropertyNames(document.createElement("p").__proto__.__proto__));//第二層有82個屬性

1個空div的自有屬性有如此之多

所以就有了現在的一些MVVM框架來管理這些DOM節點層次,比如reactjs 虛擬dom加速。

2、HTML巢狀規則

1、塊狀元素和內聯元素

塊狀元素

一般是其他元素的容器,可容納內聯元素和其他塊狀元素,塊狀元素排斥其他元素與其位於同一行,寬度(width)高度(height)起作用。

常見塊狀元素塊級元素—h1,h2,h3,h4,h5,h6,hr,div,fieldset,form,dl,address,ol,p,table,ul,pre

block元素的特點:

    1. 總是另起一行開始;
    1. 高度,行高以及頂、底邊距都可控制;
    1. 寬度預設是它所在容器的100%,除非設定一個寬度。

內聯元素

內聯元素只能容納文字或者其他內聯元素,它允許其他內聯元素與其位於同一行,但寬度(width)高度(height)不起作用。

常見內聯元素為—a,b,br,em,i,img,input,strong,textarea,span,label等常見

inline元素的特點:

    1. 和其它元素都在一行上;
    1. 高度,行高以及頂、底邊距不可改變;
    1. 寬度就是它所容納的文字或圖片的寬度,不可改變。

他們兩個的區別:

  1. 塊級元素一般用來搭建網站架構、佈局、承載內容
  2. 內聯元素一般用來在網站內容中的某些細節或者部位,用以“強調、區分樣式、上標、下標、錨點”等等。
  3. 它們可以互相轉換。display:inline|block
  4. 塊級元素的特點:每一個塊級元素都識從一個新行開始顯示,其後的元素需要另起一行

好了 簡單地說了一下塊級元素和內聯元素,下面我們開始我們的重點—–巢狀規則:

3、巢狀規則

塊級元素可以包含內聯元素或某些塊級元素,但內聯元素不能包含塊級元素,它只能包含其它內聯元素。
塊級元素不能放在p裡面。
有幾個特殊的塊級元素只能包含內聯元素,不能包含塊級元素。如h1,h2,h3,h4,h5,h6,p,dt
li內可以包含div
塊級元素與塊級元素並列、內聯元素與內聯元素並列。(錯誤的:<div><h2></h2><span></span></div>

一張圖瞭解OUTHTML和innerText、innerHTML:

這裡寫圖片描述