放自己用DOM寫的作品鏈接
寫于2017.08.07
一敛腌、關于DOM
- 什么是DOM
DOM是JavaScript操作網頁的接口祭饭,全稱為“文檔對象模型”(Document Object Model)瓮床。它的作用是將網頁轉為一個JavaScript對象盹舞,從而可以用腳本進行各種操作(比如增刪內容)。
瀏覽器會根據DOM模型隘庄,將結構化文檔(比如HTML和XML)解析成一系列的節(jié)點踢步,再由這些節(jié)點組成一個樹狀結構(DOM Tree)。所有的節(jié)點和最終的樹狀結構丑掺,都有規(guī)范的對外接口获印。所以,DOM可以理解成網頁的編程接口街州。
嚴格地說兼丰,DOM不屬于JavaScript玻孟,但是操作DOM是JavaScript最常見的任務,而JavaScript也是最常用于DOM操作的語言 - DOM的節(jié)點
DOM的最小組成單位叫做節(jié)點(node)地粪。文檔的樹形結構(DOM樹)取募,就是由各種不同類型的節(jié)點組成。每個節(jié)點可以看作是文檔樹的一片葉子蟆技。
節(jié)點的類型有七種玩敏。
*Document:整個文檔樹的頂層節(jié)點
*DocumentType:doctype標簽(比如<!DOCTYPE html>)
*Element:網頁的各種HTML標簽(比如<body>、<a>等)
*Attribute:網頁元素的屬性(比如class="right")
*Text:標簽之間或標簽包含的文本
*Comment:注釋
*DocumentFragment:文檔的片段
DOM樹如下圖:
具體DOM學習建議參考鏈接:http://javascript.ruanyifeng.com/#dom
二质礼、事件模型
什么是事件
事件是一種異步編程的實現方式旺聚,本質上是程序各個組成部分之間的通信。一般來講眶蕉,有一下特點:
1砰粹、某某訂閱了/關注/監(jiān)聽了×××
2、×××發(fā)生變化
3造挽、某某得到通知
體現在DOM機制里就是:用戶的操作發(fā)生變化碱璃,代碼得到通知事件EventTarget接口
DOM的事件操作(監(jiān)聽和觸發(fā)),都定義在EventTarget接口饭入。Element節(jié)點嵌器、document節(jié)點和window對象,都部署了這個接口谐丢。此外爽航,XMLHttpRequest、AudioNode乾忱、AudioContext等瀏覽器內置對象讥珍,也部署了這個接口。
該接口就是3個方法:
1窄瘟、addEventListener:綁定事件的監(jiān)聽函數
例:
target.addEventListener(type, listener[, useCapture]);
type:事件名稱衷佃,大小寫敏感。
listener:監(jiān)聽函數寞肖。事件發(fā)生時纲酗,會調用該監(jiān)聽函數。
useCapture:布爾值新蟆,默認為false(監(jiān)聽函數只在冒泡階段被觸發(fā))觅赊。true是在捕獲階段觸發(fā)
addEventListener方法可以為當前對象的同一個事件,添加多個監(jiān)聽函數琼稻。這些函數按照添加順序觸發(fā)吮螺,即先添加先觸發(fā)。如果為同一個事件多次添加同一個監(jiān)聽函數,該函數只會執(zhí)行一次鸠补,多余的添加將自動被去除(不必使用removeEventListener方法手動去除)萝风。
2、removeEventListener:移除事件的監(jiān)聽函數
例:
div.addEventListener('click', listener, false);
removeEventListener方法移除的監(jiān)聽函數紫岩,必須與對應的addEventListener方法的參數完全一致规惰,而且必須在同一個元素節(jié)點,否則無效泉蝌。
3歇万、dispatchEvent:觸發(fā)事件
dispatchEvent方法在當前節(jié)點上觸發(fā)指定事件,從而觸發(fā)監(jiān)聽函數的執(zhí)行勋陪。該方法返回一個布爾值贪磺,只要有一個監(jiān)聽函數調用了Event.preventDefault(),則返回值為false诅愚,否則為true
例:
para.addEventListener('click', hello, false);
var event = new Event('click');
para.dispatchEvent(event);
上面代碼在當前節(jié)點觸發(fā)了click事件-
3種綁定監(jiān)聽函數的方法
1寒锚、HTML標簽的on-屬性
例:元素標簽的屬性中,直接定義某些事件的監(jiān)聽代碼
<body onload="doSomething()">
<div onclick="console.log('觸發(fā)事件')">
上面代碼為body節(jié)點的load事件违孝、div節(jié)點的click事件刹前,指定了監(jiān)聽函數。
使用這個方法指定的監(jiān)聽函數雌桑,只會在冒泡階段觸發(fā)另外腮郊,Element元素節(jié)點的setAttribute方法,其實設置的也是這種效果筹燕。
el.setAttribute('onclick', 'doSomething()');
2、Element節(jié)點的事件屬性
Element節(jié)點對象有事件屬性衅鹿,同樣可以指定監(jiān)聽函數撒踪。
例:
window.onload = doSomething;
div.onclick = function(event){
console.log('觸發(fā)事件');
};
使用這個方法指定的監(jiān)聽函數,只會在冒泡階段觸發(fā)大渤。
3制妄、addEventListener方法
window.addEventListener('load', doSomething, false);(詳解如上)
總結:第一種“HTML標簽的on-屬性”,違反了HTML與JavaScript代碼相分離的原則泵三;第二種“Element節(jié)點的事件屬性”的缺點是耕捞,同一個事件只能定義一個監(jiān)聽函數,也就是說烫幕,如果定義兩次onclick屬性俺抽,后一次定義會覆蓋前一次。 事件的捕獲與冒泡階段
1较曼、操作系統最先知道用戶點擊了鼠標磷斧,瀏覽器次之
2、child被點擊了,意味著parent也被點擊了
3弛饭、那么如果同時監(jiān)聽了child和parent冕末,誰先通知我
例子:如果對parent和child同時設置了監(jiān)聽,那么當我點擊child侣颂,誰先通知我
捕獲階段:parent先通知档桃,child后通知(一般不用)
冒泡階段:child先通知,parent后通知e.target與e.currentTarget
e.target代表你點擊的那個元素憔晒,而e.currentTarget代表你監(jiān)聽的那個元素藻肄,如果你處于捕獲或者冒泡階段,二者是不一樣的阻止默認事件
document.querySelector("a").addEventListener('click',function(e){
e.preventDefault()
})
這樣的話a就不會跳轉了丛晌。如果在父元素阻止默認事件仅炊,那a也不跳轉了,所以一般不建議這樣做停止冒泡
e.stopPropagation( )(在子元素加入澎蛛,則不通知爸爸了抚垄,不會再向上傳播)事件委托
由于事件會在冒泡階段向上傳播到父節(jié)點,因此可以把子節(jié)點的監(jiān)聽函數定義在父節(jié)點上谋逻,由父節(jié)點的監(jiān)聽函數統一處理多個子元素的事件呆馁。這種方法叫做事件委托
例:
HTML代碼:
<ul>
<li>選項1</li>
<li>選項2</li>
<li>選項3</li>
<li>選項4</li>
</ul>
JS代碼:
var ul =document.querySelector('ul')
function fn(e){
if(e.target.tagName ==="LI"){
console.log("ok")(如果li里面裹一層span,點擊span就不能執(zhí)行監(jiān)聽函數)
}
}
ul.addEventListener('click',fn)
優(yōu)化執(zhí)行函數:
function fn(e){
var el = e.target
while(el.tagName !=="LI"){
el =el.parentNode(向上遍歷父元素)
}
if(el){
console.log('yes')
}
}
但是實際上我只需要遍歷到我監(jiān)聽的元素就可以了毁兆,如果直到遍歷到監(jiān)聽的元素還沒有的話浙滤,就認為沒有了
例:
HTML代碼:
<div>
<p>我是<span>p</span></p>
<hi>我是<span>h1</span></hi>
</div>
JS代碼:
var div =document.querySelector('div')
function fn(e){
var el = e.target
while(el.tagName !=="H1"){
el =el.parentNode(向上遍歷父元素)
if(el===div){
el=null
break;
}
}
if(el){
console.log('yes')
}
}
div.addEventListener('click',fn(e))