DOM爲document object model三個單詞的縮寫,直譯過來即文檔對象模型。
DOM的地位
我們知道,一個網頁是由html來搭建結構的,通過css來定義網頁的樣式,而javascript賦予了頁面的行爲,通過它我們可以與頁面進行交互,實現頁面的動畫效果等等。那javascript究竟通過什麼來實現的呢?通過ECMAScript這個標準,我們可以編寫程序讓瀏覽器來解析,利用ECMAScript,我們可以通過BOM對象(即browser object model)來操作瀏覽器窗口、瀏覽器導航對象、屏幕分辨率、瀏覽器歷史、cookie等等。但這個通過BOM來實現的交互遠遠不夠。要實現頁面的動態交互和效果,操作html纔是核心。那如何操作html呢?對,就是DOM,簡單的說,DOM給我們提供了用程序來動態控制html的接口,也就是早期的DHTMl的概念。因此,DOM處在javascript賦予html具備動態交互和效果的能力的核心地位上。
首先我們通過一個案例認識一下DOM在實際開發中是如何應用的;其次來了解什麼是DOM,以及與DOM相關的基礎概念;然後重新認識一下html與xml的兩種文檔類型以及文檔的各種節點類型;接着來詳細的實現DOMReady;接着瞭解如何判斷元素節點的類型以及什麼是元素節點的繼承層次;最後瞭解各種元素節點的分類和規則。
在深入學習DOM之前,先做一個熱身,做一個小案例感受一下DOM在web特效開發中是如何應用的。
DOM操作案例——滑動門特效
需求:把鼠標放到想要展示的圖片上,當前圖片伸展打開,其他的圖片堆疊關閉。
實現:搭建結構——定義樣式——着手編寫交互效果代碼(js+DOM)
效果圖
(1).搭建結構:index.html
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>sliding doors</title>
<link rel="stylesheet" href="styles/slidingdoors.css" />
<script src="scripts/slidingdoors.js"></script>
</head>
<body>
<div id='container'>
<img src="images/door1.png" alt="1080P神器" title="1080P神器" />
<img src="images/door2.png" alt="5.5寸四核" title="5.5寸四核" />
<img src="images/door3.png" alt="四核5寸" title="四核5寸" />
<img src="images/door4.png" alt="5.7寸機皇" title="5.7寸機皇" />
</div>
</body>
</html>
(2).定義樣式:slidingdoors.css
* {
margin:0;
padding:0;
}
#container {
height: 477px;
margin: 0 auto;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
overflow: hidden;
position: relative;
}
#container img {
position: absolute;
display: block;
left: 0;
border-left: 1px solid #ccc;
}
(3).編寫交互效果:
第一步先定義頁面加載完畢再進行DOM操作的方法。
window.οnlοad=function(){
};
window.onload方法表示當頁面所有的元素都加載完畢,並且所有要請求的資源也加載完畢才觸發執行function這個匿名函數裏邊的具體內容。這裏的onload就是DOM範疇的其中一部分內容——事件。我們要實現和頁面進行交互,就要通過js來操作頁面元素或者說操作DOM,而要想操作DOM,就必須先找到DOM元素的節點,也就是要找到操作的對象
我們先來獲得div這個容器對象,再通過獲得的div對象,獲得四張圖片的對象集合。
//獲得容器對象
var box=document.getElementById("container");
//獲得圖片nodeList對象集合
var imgs=box.getElementsByTagName("img");
先看效果圖,當前狀態是第一張圖片打開,我們來看四張圖片的具體位置,第一張圖片的位置距離容器左側爲0;第二張圖片的位置距離容器左側爲一張圖片的寬度;第三張圖片的位置距離容器左側爲一張圖片的寬度+1個堆疊的寬度;第四張圖片的位置距離容器左側爲一張圖片的寬度+2個堆疊的寬度;以此類推。
返回代碼,根據剛纔直觀的查看,想要設置我們四張圖片的位置就需要知道單張圖片的寬度和需要定義我們堆疊的寬度
//獲得單張圖片的寬度(這裏的每張圖片大小一致,所以可以取得任意一張圖片獲得其寬度,這裏取第一張圖片imgs[0]的寬度)
var imgWidth=imgs[0].offsetWidth;
//設置掩藏門體露出的寬度
var exposeWidth=160; //這個值可按需求自定義
我們返回到效果,我們要設置每張圖片的具體位置,我們有必要將我們的總盒子的寬度設置爲他應該的值,這樣的話,我們的盒子才正好的將我們所有的圖片包含在內。那麼我們盒子的總寬度應該等於我們單張打開的圖片的寬度+我們剩餘的圖片的堆疊的寬度的和。
回到代碼
//設置容器總寬度
var boxWidth=imgWidth+(imgs.length-1)*exposeWidth;
box.style.width=boxWidth+'px';
寫到這,我們可以先看看效果。目前我們四張圖片還是堆疊在一起,但容器的寬度已經設置好了,下面我們就讓圖片歸位。
回到代碼,我們來設置每道門的初始位置,這裏通過for循環一併爲所有的圖片來進行定位。由於第一道門距離容器左側爲0,我們無需設置它的位置,因此我們循環的累加變量初始值爲1。
//設置每道門的初始位置
function setImgsPos(){
for(var i=1,len=imgs.length;i<len;i++){
imgs[i].style.left=imgWidth+exposeWidth*(i-1)+'px';
}
}
setImgsPos(); //需要調用執行一下
現在我們來瀏覽器中看一下效果,此時四張圖片已經歸位,下面我們來實現門體的滑動。鼠標滑過以後,每個應該滑動的門體滑動的距離是多少呢?我們仔細觀察不難看出,這個距離就是我們圖片的寬度減去我們堆疊露出的寬度。
回到代碼,我們首先計算每道門打開時應移動的距離
//計算每道門打開時應移動的距離
var translate=imgWidth-exposeWidth;
//爲每道門綁定事件
for(var i=0,len=imgs.length;i<len;i++){
//使用立即調用的函數表達式,爲了獲得不同的i值
(function(i){
imgs[i].οnmοuseοver=function(){
//先將每道門復位
setImgsPos();
};
})(i);
}
下面我們來實現開門滑動的效果,回到瀏覽器觀察一下,當我們所有的圖片都歸位以後,當我們鼠標滑到我們想打開的門的時候,比如說第三張,我們只需要將第二張和第三張圖片向左滑動即可,其他圖片的滑動規律類似。比如我們放到第四張,那麼我們需要將第二張、第三張、第四張圖片都向左滑動,這就是我們圖片滑動的規律。根據得出的規律,我們要實現打開門,只需要處理第二張到當前圖片之間所有的圖片即可。
回到代碼
//爲每道門綁定事件
for(var i=0,len=imgs.length;i<len;i++){
//使用立即調用的函數表達式,爲了獲得不同的i值
(function(i){
imgs[i].οnmοuseοver=function(){
//先將每道門復位
setImgsPos();
//打開門
for(var j=1;j<=i;j++){
imgs[j].style.left=parseInt(imgs[j].style.left,10)-translate+'px';
}
};
})(i);
}
到此,這個案例的js代碼和DOM操作的代碼就編寫完畢了。
完整的js代碼:slidingdoors.js
window.onload = function() {
//容器對象
var box = document.getElementById('container');
//獲得圖片NodeList對象集合
var imgs = box.getElementsByTagName('img');
//單張圖片的寬度
var imgWidth = imgs[0].offsetWidth;
//設置掩藏門體露出的寬度
var exposeWidth = 160;
//設置容器總寬度
var boxWidth = imgWidth + (imgs.length - 1) * exposeWidth;
box.style.width = boxWidth + 'px';
//設置每道門的初始位置
function setImgsPos() {
for (var i = 1, len = imgs.length; i < len; i++) {
imgs[i].style.left = imgWidth + exposeWidth * (i - 1) + 'px';
}
}
setImgsPos();
//計算每道門打開時應移動的距離
var translate = imgWidth - exposeWidth;
//爲每道門綁定事件
for (var i = 0, len = imgs.length; i < len; i++) {
//使用立即調用的函數表答式,爲了獲得不同的i值
(function(i) {
imgs[i].onmouseover = function() {
//先將每道門復位
setImgsPos();
//打開門
for (var j = 1; j <= i; j++) {
imgs[j].style.left = parseInt(imgs[j].style.left, 10) - translate + 'px';
}
};
})(i);
}
};
認識DOM
DOM(文檔對象模型)是針對xml經過擴展用於html的應用程序編程接口,我們又叫API。DOM把整個頁面映射爲一個多層的節點結構,html或xml頁面中的每個組成部分都是某種類型的節點,這些節點又包含着不同類型的數據。
DOM級別
(1).DOM1級:由兩個模塊組成,即DOM Core(DOM核心)和DOM HTML。其中DOM Core規定的是如何映射基於xml的文檔結構,以便簡化對文檔中任何部分的訪問和操作;DOM HTML模塊則在DOM Core的基礎上加以擴展,添加了針對html的對象和方法。
其實DOM並不是針對javascript,很多別的語言也都實現了DOM,不過在web瀏覽器中基於ECMAScript實現的DOM的確已經成爲javascript這門語言的一個重要組成部分。如果說DOM1級的目標主要是映射文檔的結構,那麼DOM2級的目標就要寬泛很多了。
(2).DOM2級:由四個模塊組成,即DOM Views(DOM 視圖)、DOM Events(DOM事件)、DOM Style、DOM Traversal and Range(DOM遍歷和範圍),DOM Views定義了跟蹤不同文檔視圖的接口,比如跟蹤應用css之前和應用css之後的文檔視圖;DOM Events定義了事件和事件處理的接口;DOM Style定義了基於css爲元素應用樣式的接口;DOM Traversal and Range定義了遍歷和操作文檔樹的接口。
(3).DOM3級:進一步擴展了DOM,引入了以統一方式加載和保存文檔的方法,它在DOM Load And Save這個模塊中定義;同時新增了驗證文檔的方法,是在DOM Validation這個模塊中定義的。
我們在閱讀DOM標準的時候,經常會看到DOM0級這樣的字眼,實際上DOM0級這個標準是不存在的。所謂DOM0級只是DOM歷史座標系中的一個參照點而已,具體地說DOM0級就是指IE4.0和Netscape navigator4.0最初支持的那個DHTML。
瀏覽器 | DOM兼容性 |
---|---|
Netscape Navigator 1.~4.x | - |
Netscape 6+(Mozilla 0.6.0+) |
1級、2級(幾乎全部)、3級(部分) |
IE2~IE4.x |
- |
IE5 |
1級(最小限度) |
IE5.5~IE8 |
1級(幾乎全部) |
IE9+ |
1級、2級、3級 |
Opera 1~6 |
- |
Opera7~8.x |
1級(幾乎全部)、2級(部分) |
Opera9~9.9 |
1級、2級(幾乎全部)、3級(部分) |
Opera 10+ |
1級、2級、3級(部分) |
Safari 1.0.x |
1級 |
Safari 2+ |
1級、2級(部分) |
Chrome 1+ |
1級、2級(部分) |
Firefox 1+ |
1級、2級(幾乎全部)、3級(部分) |
DOM文檔類型
DOM節點類型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DocumentFragment文檔片段節點</title>
</head>
<body>
<ul id="list-node"></ul>
<script>
var frag = document.createDocumentFragment();
for (var i = 0; i < 10; i++) {
var li = document.createElement("li");
li.innerHTML = "List item" + i;
frag.appendChild(li);
}
document.getElementById("list-node").appendChild(frag);
</script>
</body>
</html>
這段代碼在瀏覽器查看元素時就會發現,頁面中並沒有插入DocumentFragment節點自身,它只作爲一個臨時佔位符存在。
(1).DOM nodeType
通過DOM節點類型,我們可知,可以通過某個節點的nodeType屬性來獲得節點的類型,節點的類型可以是數值常量或者字符常量。示例代碼如下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>nodeType</title>
</head>
<body>
<div id="container">這是一個元素節點</div>
<script>
var divNode = document.getElementById('container');
/*IE中只支持數值常量,其他瀏覽器數值常量和字符常量都支持,因此可以直接用數值常量判斷,
*這裏爲了比較兩種寫法,便都寫在了這裏
*/
if (divNode.nodeType == Node.ELEMENT_NODE || divNode.nodeType == 1) {
alert("Node is an element.");
}
</script>
</body>
</html>
先看示例代碼
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>nodeName,nodeValue</title>
</head>
<body>
<!--nodeName,nodeValue實驗-->
<div id="container">這是一個元素節點</div>
<script>
var divNode = document.getElementById('container');
console.log(divNode.nodeName + "/" + divNode.nodeValue);
//結果: DIV/null
var attrNode = divNode.attributes[0];
console.log(attrNode.nodeName + "/" + attrNode.nodeValue);
//結果: id/container
var textNode = divNode.childNodes[0];
console.log(textNode.nodeName + "/" + textNode.nodeValue);
//結果: #text/這是一個元素節點
var commentNode = document.body.childNodes[1];
//表示取第二個註釋節點,因爲body下面的第一個註釋節點爲空白符。
console.log(commentNode.nodeName + "/" +commentNode.nodeValue);
//結果: #comment/nodeName,nodeValue實驗
console.log(document.doctype.nodeName + "/" + document.doctype.nodeValue);
//結果: html/null
var frag = document.createDocumentFragment();
console.log(frag.nodeName + "/" + frag.nodeValue);
//結果: #document-fragment/null
</script>
</body>
</html>
根據實驗,得出以下彙總表格。
節點中的nodeName和nodeValue
domReady
function myReady(fn){
//對於現代瀏覽器,對DOMContentLoaded事件的處理採用標準的事件綁定方式
if ( document.addEventListener ) {
document.addEventListener("DOMContentLoaded", fn, false);
} else {
IEContentLoaded(fn);
}
//IE模擬DOMContentLoaded
function IEContentLoaded (fn) {
var d = window.document;
var done = false;
//只執行一次用戶的回調函數init()
var init = function () {
if (!done) {
done = true;
fn();
}
};
(function () {
try {
// DOM樹未創建完之前調用doScroll會拋出錯誤
d.documentElement.doScroll('left');
} catch (e) {
//延遲再試一次~
setTimeout(arguments.callee, 50);
return;
}
// 沒有錯誤就表示DOM樹創建完畢,然後立馬執行用戶回調
init();
})();
//監聽document的加載狀態
d.onreadystatechange = function() {
// 如果用戶是在domReady之後綁定的函數,就立馬執行
if (d.readyState == 'complete') {
d.onreadystatechange = null;
init();
}
}
}
}
在頁面中引入donReady.js文件,引用myReady(回調函數)方法即可。<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>domReady與window.onload</title>
<script src="domReady.js"></script>
</head>
<body>
<div id="showMsg"></div>
<div>
<img src="1.jpg" />
<img src="2.jpg" />
<img src="3.jpg" />
<img src="4.jpg" />
<img src="5.jpg" />
<img src="6.jpg" />
</div>
<script>
var d = document;
var msgBox = d.getElementById("showMsg");
var imgs = d.getElementsByTagName("img");
var time1 = null, time2 = null;
myReady(function(){
msgBox.innerHTML += "dom已加載!<br>";
time1 = new Date().getTime();
msgBox.innerHTML += "時間戳:" + time1 + "<br>";
});
window.onload = function(){
msgBox.innerHTML += "onload已加載!<br>";
time2 = new Date().getTime();
msgBox.innerHTML += "時間戳:" + time2 + "<br>";
msgBox.innerHTML +="domReady比onload快:" + (time2 - time1) + "ms<br>";
};
</script>
</body>
</html>
如何判斷元素節點類型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isElement</title>
</head>
<body>
<div id="test">aaa</div>
<!--這是一個註釋節點-->
<script>
var isElement = function (el){
return !!el && el.nodeType === 1;
}
var a = { //隨意定義一個變量,設置nodeType爲1
nodeType: 1
}
console.log(isElement(document.getElementById("test")));
//結果: true
console.log(isElement(document.getElementById("test").nextSibling));//這裏的nextSibling屬性查找下一個相鄰節點,即註釋節點
//結果: false
console.log(isElement(a));
//結果: true
</script>
</body>
</html>
!!一般用來將後面的表達式轉換爲布爾型的數據(boolean).
因爲javascript是弱類型的語言(變量沒有固定的數據類型)所以有時需要強制轉換爲相應的類型,類似的如:
a=parseInt("1234");
a="1234"+0 //轉換爲數字
b=1234+"" //轉換爲字符串
c=someObject.toString() //將對象轉換爲字符串
其中第1種、第4種爲顯式轉換,2、3爲隱式轉換.
布爾型的轉換,javascript約定和c類似,規則爲 :
false、undefinded、null、0、"" 爲 false ;
true、1、"somestring"、[Object] 爲 true .
!!el表示判斷el是否存在,存在爲true,反之爲false.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isElement</title>
</head>
<body>
<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")));
//結果: true
console.log(isElement(document.getElementById("test").nextSibling));
//結果: false
console.log(isElement(a));
//結果: false
</script>
</body>
</html>
這樣,在判斷a是否是元素節點時,結果就是false了。(2).HTML文檔元素節點的判定和XML文檔元素節點的判定:isHTML and isXML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isXML</title>
</head>
<body>
<script>
//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方法");
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isXML</title>
</head>
<body>
<script>
//我們看看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;
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isXML</title>
</head>
<body>
<script>
var isXML = function(doc) {
return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
}
</script>
</body>
</html>
我們知道,無論是HTML文檔,還是XML文檔都支持createELement()方法,我們判定創建的元素的nodeName是區分大小寫的還是不區分大小寫的,我們就知道是XML還是HTML文檔,這個方法是目前給出的最嚴謹的函數了。
判斷是不是HTML文檔的方法如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isHTML</title>
</head>
<body>
<script>
var isHTML = function(doc) {
return doc.createElement("p").nodeName === doc.createElement("P").nodeName;
}
console.log(isHTML(document));
</script>
</body>
</html>
有了以上判斷XML和HTML文檔的方法,我們就可以實現一個元素節點屬於HTML還是XML文檔的方法了,實現代碼如下:<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isHTMLElement</title>
</head>
<body>
<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 isHTML = function(doc) {
return doc.createElement("p").nodeName === doc.createElement("P").nodeName;
}
var isHTMLElement = function(el){
if(isElement){
return isHTML(el.ownerDocument);
}
return false;
}
console.log(isHTMLElement(testDiv));
</script>
</body>
</html>
(3).判斷節點的包含關係
元素之間的包含關係,用自帶的contains方法,只有兩個都是元素節點,才能兼容各個瀏覽器,否則ie瀏覽器有的版本是不支持的,可以採用hack技術,自己寫一個contains方法去兼容。
元素之間的包含關係:contains()方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>contains</title>
</head>
<body>
<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(pNode.contains(cNode)); //true
</script>
</body>
</html>
兼容各瀏覽器的contains()方法<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>contains</title>
</head>
<body>
<div id="p-node">
<div id="c-node">子節點內容</div>
</div>
<script>
//兼容的contains方法
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)); //true
alert(fixContains(document, cNode)); //true
</script>
</body>
</html>
繼承層次與嵌套規則
(1).DOM節點繼承層次
DOM節點是一個非常複雜的東西,對它的每一個屬性的訪問,不走運的話,就可能會向上溯尋到N多個原型鏈,因此DOM操作是個非常耗性能的操作。風頭正盛的react爲了解決這個問題,提出了虛擬DOM的概念,合併和屏蔽了很多無效的DOM操作,效果非常驚人。接下來看看DOM節點究竟是如何繼承的。
(1).例如使用document.createElement("p")創建p元素,其實document.createElement("p")是HTMLParagraphElement的一個實例,而HTMLParagraphElement的父類是HTMLElement,HTMLElement的父類是Element,Element的父類是Node,Node的父類是EventTarget,
EventTarget的父類是Function,Function的父類是Object。
創建一個p元素一共溯尋了7層原型鏈
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOM inheritance hierarchy</title>
</head>
<body>
<script>
console.log(Object.getOwnPropertyNames(document.createElement("p").__proto__));
//訪問p元素上一層原型控制檯打印: ["align","constructor"]
console.log(Object.getOwnPropertyNames(document.createElement("p").__proto__.__proto__));
/*訪問p元素上一層原型的再上一層原型,控制檯會打印很多屬性,感興趣的夥伴可以自己貼代碼到控制檯看一下,它要比訪*問第一層原型的屬性多得多。這也就是說,每往上一層,原型鏈就爲它添加一些屬性。
*/
</script>
</body>
</html>
HTML存在許多種類型的標籤,有的標籤下面只允許特定的標籤存在,這就叫HTML嵌套規則。
不按HTML嵌套規則寫,瀏覽器就不會正確解析,會將不符合嵌套規則的節點放到目標節點的下面,或者變成純文本。
關於HTML嵌套規則,一定要掌握塊狀元素和內聯元素的區別。
塊狀元素:一般是其他元素的容器,可容納內聯元素和其他塊狀元素,塊狀元素排斥其他元素與其位於同一行,寬度(width)高度(height)起作用。常見塊狀元素爲div和p
內聯元素:內聯元素只能容納文本或者其他內聯元素,它允許其他內聯元素與其位於同一行,但寬度(width)高度(height)不起作用。常見內聯元素爲a.
塊狀元素與內聯元素嵌套規則:
(1).塊元素可以包含內聯元素或某些塊元素,但內聯元素卻不能包含塊元素,它只能包含其他的內聯元素
例:
<div><h1></h1><p></p></div>
<a href="#"><span></span></a>
(2).塊級元素不能放在<p>裏面
例:<p><ol><li></li></ol></p><p><div></div></p>
(3).有幾個特殊的塊級元素提倡只能包含內聯元素,不能再包含塊級元素,這幾個特殊的標籤是
h1、h2、 h3、h4、 h5、 h6、 p 、dt
(4).li標籤可以包含div標籤
(5).塊級元素與塊級元素並列,內聯元素與內聯元素並列