js和HTML之間交互是通過事件實現的。事件會有事件流。事件描述的是從頁面接受事件的順序。IE和網景提出了差不多相反的事件流概念。IE提出事件冒泡流。網景提出事件捕獲流。
事件冒泡:事件開始時由最具體的元素接收,然后逐級向上傳播到較不具體的節點。所有現代瀏覽器幾乎都支持冒泡。
事件捕獲:不具體的節點更早的接收事件,最具提的節點最后接收到事件。IE9以上可以支持捕獲。
DOM2級規定的事件流包括三個階段(IE8及更早版本不支持事件流):
- 事件捕獲階段
- 處于目標階段
- 事件冒泡階段。
事件處理程序:
- HTML事件處理程序
- DOM0級事件處理程序
- DOM2級事件處理程序
HTML事件處理程序
<input type='button' id='btn' onclick=clickMe() value='click me'>
function clickMe (){
alert('hi')
} //這種處理程序代碼耦合度太高,修改時需要修改兩處。存在時差問題,有些事件可能需要HTML元素一出現在頁面上就觸發,但當時的事件處理程序可能尚不具備條件。
DOM0級事件處理程序:
var btn =document.getElementById('btn')
btn.onclick = function () {//每個事件只支持一個事件處理程序
alert('hi')
}
btn.onclick = null //刪除事件處理程序
DOM2級事件處理程序:IE9及以上支持
使用DOM2級事件處理程序的好處是可以為一個元素綁定多個事件處理程序
var btn =document.getElementById('btn')
btn.addEventListener('click',function(){
alert('hi')
},false) //click事件在冒泡階段觸發
IE事件處理程序:IE8及以下只支持事件冒泡
var btn =document.getElementById('btn')
btn.attachEvent('onclick',funtion(){ //第一個參數為onclick,并不是click。
alert('hi') //attachEvent()添加的事件處理程序都會被添加到冒泡階段
})
在IE中使用attachEvent()與使用DOM0級方法的主要區別:事件處理程序運行的作用域不一樣。DOM0級事件處理程序會在其所屬元素的作用域下運行,而attachEvent()的事件處理程序會在全局作用域運行。attachEvent()也可以為一個元素添加多個事件處理程序,執行順序與DOM2級事件處理程序的執行順序相反。
跨瀏覽器事件處理程序
var EventUtil = {
addEvent:function (element,type,handler) {
if (element.addEventListener) { //ie9及以上
element.addEventListener(type,handler, false)
} else if (element.attachEvent) { //ie8及以下
element.attachEvent('on'+type,handler)
} else {
element['on'+type] = handler
}
},
removeEvent:function(element, type,handler) {
if (element.removeEventListener) {//ie9及以上
element.removeEventListener(type,handler, false)
} else if (element.detachEvent) { //ie8及以下
element.detachEvent('on'+type,handler)
} else {
element['on'+type] = null
}
}
}
<input type='button' id='btn' value='click me'>
var btn =document.getElementById('btn')
var handler = function () {
alert('hi')
}
EventUtil.addEvent(btn,'click',handler)
EventUtil.removeEvent(btn,'click',handler)
事件對象
在觸發DOM上的某個事件時,會產生事件對象event。這個對象包含與這個事件有關的信息。
DOM中的事件對象
兼容DOM的瀏覽器會將一個event對象傳入到事件處理程序中,無論是DOM0級還是DOM2級。
var btn = document.getElementByid('btn')
btn.onclick = function (event) {
alert(event.type) //click
}
btn.addEventListener('click',function (event) {
alert(event.type) //click
}, false)
- cancelable 表示是否可以取消事件的默認行為
- preventDefault() 阻止默認操作 cancelable屬性需要設置為true
- bubbles 表示事件是否冒泡
- stopPropagation() 取消事件的捕獲或冒泡。如果bubbles為true
- event.target 時間的目標
- event.type 事件類型
- event.currentTarget 正在處理事件的元素
- event.eventPhase 確定事件當前正處于事件流的那個階段 1表示捕獲階段 2 處于目標對象上 3 冒泡階段
只有在事件處理程序執行期間,event對象才會存在,一旦事件處理程序執行完成,event對象就會被銷毀
IE中的事件對象
要訪問IE中的event對象有幾種不同的方式,取決于事件處理程序的方法。DOM0級事件處理程序,event對象作為window屬性存在。
使用attachEvent()的情況下,可以使用event對象,也可以通過window 對象來訪問event對象
- cancelBubble 默認值是false,設置為true可以取消冒泡 與stoppropagation()作用相同
- returnValue 默認是false,設置為true表示取消事件默認行為 與* preventDefault()作用相同
- srcElement 事件的目標 與target屬性相同
- type 事件類型
btn.onclick = function () {
alert (window.event.srcElement === this) //true
}
btn.attachEvent('onclick', function (event) {
alert(event.srcElement === this) //false
})
跨瀏覽器事件對象
var EventUtil = {
addEvent:function (element,type,handler) {
if (element.addEventListener) {
element.addEventListener(type,handler, false)
} else if (element.attachEvent) {
element.attachEvent('on'+type,handler)
} else {
element['on'+type] = handler
}
},
removeEvent:function(element, type,handler) {
if (element.removeEventListener) {
element.removeEventListener(type,handler, false)
} else if (element.detachEvent) {
element.detachEvent('on'+type,handler)
} else {
element['on'+type] = null
}
},
getEvent: function (event) {
return event ? event : window.event
} ,
getTarget: function (event) {
return event.target || event.srcElement
},
preventDefault: function (event) {
if (event.preventDefault) {
event.preventDefault ()
} else {
event.returnValue = false
}
},
stopPropagation: function (event) {
if (event.stopPropagation) {
event.stopPropagation ()
} else {
event.cancelBubble = true
}
}
}
btn.onclick = function (event) {
event = EventUtil.getEvent (event)
var target = EventUtil.getTarget (event)
EventUtil.preventDefault()
EventUtil.stopPropagation()
}
事件類型
UI事件(用戶與頁面上的元素交互時觸發)/ 焦點事件 /鼠標事件 /滾動事件/鍵盤事件/文本事件/變動事件/合成事件
UI事件指的是那些不一定與用戶操作有關的事件。
- load事件 頁面完全加載后window上觸發
- unload事件 頁面完全卸載后window上觸發,只要用戶從一個頁面切換到另一個頁面就會觸發
- abort事件 用戶停止下載過程時,如果嵌入的內容沒有加載完<object>上觸發
- error事件 當js發生錯誤時觸發 當無法加載圖片時在img上觸發 當無法加載嵌入的內容時在<object>上觸發
- select事件 當用戶選中文本框中的一個或多個字符時觸發
- resize事件 當窗口或框架的大小變化時在window或框架上觸發
- scroll事件 當用戶滾動帶滾動條的元素中的內容時在該元素上觸發
- load事件中:圖片img可以實現預加載,新圖像元素不一樣要等到添加到文檔后才開始加載,只要設置了它的src屬性就會開始下載。而<script>標簽也支持load事件,只不過只有設置了<script>標簽的src屬性并且添加到文檔后,才會開始下載js文件。
焦點事件
blur focus主要的兩個事件,可以在捕獲階段偵聽到它們但是它們不支持冒泡。focusin和focusout與blur focus等價,但是支持冒泡。
鼠標事件
- click:用戶單擊主鼠標或者按下回車鍵時觸發。
- dblclick:用戶雙擊主鼠標時出大。屬于DOM3級事件標準
- mouseover:當鼠標指針位于一個元素外部,用戶將其首次移入另一個元素邊界訪問時觸發,不能通過鍵盤觸發這個事件
- mouseout:當鼠標指針位于一個元素上方,然后用戶將其移入另一個元素時觸發。不能通過鍵盤觸發這個事件
- mousedown:用戶按下任意鼠標按鈕時觸發,不能通過鍵盤觸發這個事件
- mouseup:當用戶釋放鼠標按鈕時觸發,不能通過鍵盤觸發這個事件
- mousemove:當鼠標在元素內部移動時重復觸發,不能通過鍵盤觸發這個事件
- mouseenter:在鼠標光標從外部首次移動到元素范圍內觸發,不支持冒泡,在光標移動到后代元素上不會觸發。屬于DOM3級事件標準。
- mouseleave:在位于元素上方的鼠標光標移動到元素范圍之外時觸發,不支持冒泡,在光標移動到后代元素上不會觸發。屬于DOM3級事件標準。
鼠標事件都是在瀏覽器視口的特定位置上發生的。這個位置信息保存在事件對象的clientX,clientY屬性中。它們的值表示事件發生時鼠標指針在視口的水平和垂直坐標。這些值不包含頁面滾動的距離,因此這個位置不表示鼠標在頁面上的實際位置。
pageX,pageY這兩個屬性可以告訴你鼠標是在頁面的什么位置發生的。這兩個屬性表示鼠標在頁面上的位置,因此坐標時相當于頁面本身而非視口的左邊和頂邊計算的。在沒有滾動的狀況下,pageX pageY 和clientX clientY的值相等。
pageX =clientX + scrollLeft
pageY= clientY + scrollTop
screenX和screenY 相對于整個電腦屏幕的位置
offsetX offsetY:表示鼠標相對于目標元素邊界的坐標(僅IE支持)
滾輪事件
mousewheel:這個事件可以在任何元素上觸發。當用戶通過鼠標滾輪與頁面上交互,在垂直方向上滾動頁面時就會觸發。特有屬性wheelDelta 。當用戶向上滾動時wheelDelta是120的倍數,當用戶向下滾動時wheelDelta是-120的倍數。通過wheelDelta的正負號就可以知道鼠標滾輪的滾動方向。
觸摸設備
在面向iPhone和iPod中的Safari開發時需要注意:
1.不支持dblclick,雙擊瀏覽器窗口會放大畫面
2.兩個手指放在屏幕上且頁面隨著手指的移動而滾動時,會觸發mouseWheel和scroll事件
3.mousemove事件也會觸發mouseover和mouseout事件
鍵盤事件
- keydown 當用戶按下鍵盤上任意鍵的時候觸發,如果按住不放,會重復觸發
- keypress 當用戶按下鍵盤上字符鍵的時候觸發,如果按住不放,會重復觸發
- keyup 當用戶釋放鍵盤上的鍵的時候觸發
在發生keydown和keyup事件時,event對象的keyCode會包含一個代碼。event.keyCode - keyCode:按下鍵的字符編碼
文本事件
textInput事件:主要是對keypress事件補充。用意是將文本顯示給用戶之前更容易攔截文本。在文本插入文本框之前會觸發textInput事件。包含data屬性,保存用戶輸入輸入的字符。
HTML5事件
contextmenu
beforeunload
DOMContentLoaded