所謂事件,就是文檔或閱讀器窗口中產(chǎn)生的1些特定的交互瞬間
在頁(yè)面上,單擊某個(gè)元素的同時(shí),也單擊了它的包括容器。事件流就是描寫的從頁(yè)面中接收事件的順序。IE是事件冒泡流,Netscape是事件捕獲流。
事件冒泡:事件開始時(shí),由最具體的元素接收,然后逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn);(所有現(xiàn)代閱讀器都支持事件冒泡)
事件捕獲:不太具體的節(jié)點(diǎn)最早接收到事件,最具體的節(jié)點(diǎn)最后接收到事件。(老版本閱讀器不支持)
DOM2級(jí)事件規(guī)定的事件流包括3個(gè)階段:1、事件不惑階段;2、處于目標(biāo)階段;3、事件冒泡階段
DOM事件流中,實(shí)際的目標(biāo)在捕獲階段不會(huì)接收到時(shí)間
事件就是用戶或閱讀器本身履行的某種動(dòng)作,如click/load/mousedown,這些都是事件的名字。
事件處理程序:是響應(yīng)某個(gè)事件的函數(shù)
為事件指定事件處理函數(shù)的方法有3種:
某個(gè)元素支持的每種事件,都可以在元素內(nèi)部,使用與事件處理程序同名的HTML屬性來(lái)指定。這個(gè)屬性的值是能夠履行的JavaScript代碼,既可以包括要履行的具體動(dòng)作,也能夠調(diào)用在頁(yè)面其他地方定義的腳本。
<input type="button" value="點(diǎn)我有欣喜" onclick="alert('hello,vicky!')" />
缺點(diǎn):
1、存在時(shí)差,用戶可能會(huì)在HTML元素加載完就觸發(fā)相應(yīng)事件,而這時(shí)候相應(yīng)的事件處理程序還沒(méi)有加載完,就會(huì)報(bào)錯(cuò)
2、使得HTML代碼和JavaScript代碼耦合,所以不推薦使用!
每一個(gè)元素都有自己的事件處理程序屬性,這些屬性通常全部小寫,將這類屬性的值設(shè)置為1個(gè)函數(shù),就能夠指定事件處理程序。
var btn = document.getElementById("btn");//獲得1個(gè)要操作對(duì)象的援用
btn.onclick = function () {
alert("hello vicky!");
}
DOM2級(jí)事件定義了兩個(gè)方法:addEventListener( ) removeEventListener( ),都接受3個(gè)參數(shù),要處理的事件名,事件處理函數(shù),1個(gè)布爾值(true表示在捕獲階段調(diào)用事件處理程序,false表示在冒泡階段)
var btn = document.getElementById("btn");
btn.addEventListener("click", function (){
alert("hello vicky!");
},false);
btn.addEventListener("click",function () {
alert("hello jay!")
}, false);//可以添加多個(gè)事件處理程序,且依照其添加的順序觸發(fā)
通過(guò)addEventListener()添加的事件處理程序只能通過(guò) removeEventListener()來(lái)移出。事件處理程序是在其依附的元素的作用域中運(yùn)行
IE實(shí)現(xiàn)了與DOM中類似的兩個(gè)方法:attachEvent()和detachEvent()。事件處理程序在全局作用域中運(yùn)行,添加的事件處理程序都會(huì)被添加到冒泡階段
var btn = document.getElementById("btn");
btn.attachEvent("onclick",function(){
alert("hello vicky!");
});
btn.attachEvent("onclick",function () {
alert("hello jay!");
});//添加多個(gè)事件處理程序,以添加順序的相反順序履行
var EventUtil = {
//添加事件處理程序
addHandler: function (element,type,handler) {
if (element.addEventListener) {
element.addEventListener(type,handler,false);//DOM2級(jí)
} else if (element.attachEvent) {
element.attachEvent("on" + tye,handler);//IE的方法
} else {
element["on" + tyle] = handler;//DOM0級(jí)
}
},
//取消事件處理程序
removeHandler: function (element,type,handler) {
if (element.removeEventListener) {
element.removeEventListener(type,handler,false);
} else if (element.detachEvent) {
element.detachEvent("on" + tye,handler);
} else {
element["on" + tyle] = null;
}
}
}
在動(dòng)身DOM上的某個(gè)事件時(shí),會(huì)產(chǎn)生要給事件對(duì)象event
兼容DOM的閱讀器會(huì)將1個(gè)event對(duì)象傳入到事件處理程序中。event對(duì)象包括于創(chuàng)建它的特定事件有關(guān)的屬性和方法。
//屬性
bubbles:Boolean //表明事件是不是冒泡
cancelable:Boolean //表明是不是可以取消事件的默許行動(dòng)
currentTarget:Element //事件處理程序當(dāng)前正在處理事件的那個(gè)元素
defaultPrevented:Boolean //是不是調(diào)用了preventDefault()
detail:Integer //細(xì)節(jié)信息
eventPhase: Integer //1,捕獲階段;2,處于目標(biāo)階段;3,冒泡階段
target:Element //事件的目標(biāo)
trusted:Boolean //是不是為閱讀器生成
type:Sting //被觸發(fā)事件的類型
//方法
preventDefault() //取消事件的默許行動(dòng)
stopImmediatePropagation() //取消事件的進(jìn)1步捕獲或冒泡,同時(shí)禁止任何事件處理程序被調(diào)用
stopPropagation() //取消事件的進(jìn)1步捕獲或冒泡。
在事件處理程序內(nèi)部,對(duì)象this始終等于currentTarget的值,target則只包括事件的實(shí)際目標(biāo)
不同的地方:
1、event對(duì)象作為window對(duì)象的1個(gè)屬性存在
2、事件的目標(biāo) window.event.srcElement
3、returnValue=false相當(dāng)于preventDefault()
var EventUtil = {
//獲得事件對(duì)象
getEvent: function (event) {
return event ? event : window.event;
},
//獲得事件目標(biāo)對(duì)象
getTarget: function (event) {
return event.target || event.srcElement;
},
//禁止默許行動(dòng)
preventDefault: function (event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;//取消默許行動(dòng)
}
},
//停止事件冒泡
stopPropagation: function (event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancleBubble = true;
}
}
}
UI事件:指的是那些不1定與用戶操作有關(guān)的事件。主要有:
load事件:頁(yè)面完全加載后再window上面觸發(fā)
unload事件:頁(yè)面完全卸載后在window上觸發(fā)
abort事件:用戶停止下載進(jìn)程時(shí),如果嵌入的內(nèi)容還沒(méi)加載完在object元素上面觸發(fā)
error事件:產(chǎn)生毛病時(shí)觸發(fā)
select事件:用戶選擇文本框時(shí)觸發(fā)
resize事件:窗口或框架的大小變化時(shí)觸發(fā)
scroll事件:用戶轉(zhuǎn)動(dòng)帶轉(zhuǎn)動(dòng)條的元素中的內(nèi)容時(shí)觸發(fā)
當(dāng)頁(yè)面完全加載后,就會(huì)觸發(fā)window上面的load事件
注意:在創(chuàng)建新的img元素時(shí),要在指定其src屬性之前先指定事件。新圖象元素不1定要從添加到文檔后才開始下載,只要設(shè)置了src屬性就會(huì)開始下載。
注意:與圖象不同,只有在設(shè)置了script元素的src屬性并將該元素添加到文檔后,才會(huì)開始下載JavaScript文件,即指定src屬性和指定事件處理程序的前后順序不重要。
在文檔被完全卸載后觸發(fā),只要用戶從1個(gè)頁(yè)面切換到另外一個(gè)頁(yè)面,就會(huì)產(chǎn)生unload事件。
當(dāng)閱讀器窗口被調(diào)劑到1個(gè)新的高度或?qū)挾葧r(shí),就會(huì)觸發(fā)resize事件
注意:不要在這個(gè)事件的處理程序中加入計(jì)算量大的代碼,由于這些代碼很有可能會(huì)被頻繁履行,從而致使閱讀器反應(yīng)明顯變慢。固然,這個(gè)缺點(diǎn)也是有辦法來(lái)解決的,那就是函數(shù)節(jié)流 ,詳情請(qǐng)見之前博客【JavaScript】函數(shù)節(jié)流
blur:在元素失去焦點(diǎn)時(shí)觸發(fā)
focus:在元素取得焦點(diǎn)時(shí)觸發(fā)
這兩個(gè)事件都不冒泡,所有閱讀器都支持它們
click:?jiǎn)螕糁魇髽?biāo)或按下回車鍵觸發(fā)
dbclick:雙擊主鼠標(biāo)時(shí)觸發(fā)
mousedown:用戶按下了任意鼠標(biāo)按鈕時(shí)觸發(fā)
mouseenter:在鼠標(biāo)光標(biāo)從元素外部首次移動(dòng)到元素范圍以內(nèi)時(shí)觸發(fā)。此事件不冒泡,且光標(biāo)移動(dòng)到后代元素上不觸發(fā)
mouseleave:位于元素上的光標(biāo)移動(dòng)到元素范圍以外時(shí)觸發(fā)
mouseover:鼠標(biāo)指針在元素內(nèi)部移動(dòng)時(shí)觸發(fā)
mouseout:鼠標(biāo)指針由1個(gè)元素移到另外一個(gè)元素上時(shí)觸發(fā)
mouseup:釋放鼠標(biāo)按鈕時(shí)觸發(fā)
//鼠標(biāo)事件觸發(fā)順序
(1)mousedown
(2)mouseup
(3)click
(4)mousedown
(5)mouseup
(6)dbclick
1)位置屬性:
clientX,clientY:到閱讀器視口區(qū)的左側(cè)和上邊的值
screenX,screenY:到顯示屏幕左側(cè)和上邊的值
offsetX,offsetY:到元素左側(cè)和上邊的值
2)修改鍵
shiftKey,ctrlKey,altKey,metaKey.
//打印出用戶按下的修改鍵
var text = document.getElementById("text");
EventUtil.addHandler(text,"keydown",function (event) {
var event = EventUtil.getEvent(event);
var keys = new Array();
if (event.shiftKey) {
keys.push("shift")
}
if (event.ctrlKey) {
keys.push("ctrl");
}
console.log(keys);
}) ;
3)相干元素
產(chǎn)生mouseover和mouseout事件時(shí),還會(huì)觸及更多的元素。這兩個(gè)事件都會(huì)觸及把鼠標(biāo)指針從1個(gè)元素的編輯以內(nèi)移動(dòng)到另外一個(gè)元素的邊界以內(nèi)
//獲得相干元素
getRelatedTarget: function (event) {
if (event.relatedTarget) {//DOM
return event.relatedTarget;
} else if (event.toElement) {//mouseout時(shí)IE的toElement保存相干元素
return event.toElement;
} else if (event.fromElement) {//mouseover時(shí)IE的fromElement保存相干元素
return event.fromElement;
} else {
return null;
}
}
4)鼠標(biāo)按鈕
event對(duì)象存在1個(gè)button屬性,其值有3種:0表示主鼠標(biāo)按鈕,1表示中間的鼠標(biāo)按鈕,2表示次鼠標(biāo)按鈕
將mousewheel事件處理程序指定給頁(yè)面中的任何元素或document對(duì)象,便可處理鼠標(biāo)滾輪交互操作
使用鼠標(biāo)事件應(yīng)注意的問(wèn)題:
(1)使用click事件履行代碼
(2)不要使用onmouseover向用戶顯示新的選項(xiàng)。緣由是 屏幕瀏覽器中,沒(méi)法觸發(fā)mousedown和mouseover事件
(3)不要使用dbclick履行重要的操作。由于鍵盤沒(méi)法觸發(fā)這個(gè)事件
keydown:用戶按下鍵盤上的任意鍵時(shí)觸發(fā)
keypress:用戶按下鍵盤上的字符鍵時(shí)觸發(fā)
keyup:用戶釋放鍵盤上的鍵時(shí)觸發(fā)
textInput:在文本插入文本框之前觸發(fā)
在產(chǎn)生keydown和keyup事件時(shí),event對(duì)象的keyCode屬性中會(huì)包括1個(gè)代碼,與鍵盤上1個(gè)特定的鍵對(duì)應(yīng)。
產(chǎn)生keypress事件意味著按下的鍵會(huì)影響到屏幕中文本的顯示。
charCode屬性:只有在產(chǎn)生keypress事件時(shí)才包括值,而且值是ASCII編碼。要想跨閱讀器獲得字符編碼,必須首先檢測(cè)charCode屬性是不是可用,如果不可用則使用keyCode
//獲得charCode
getCharCode: function (event) {
if (typeof event.charCode == "number") {
return event.charCode;
} else {
return event.keyCode;
}
}
用戶在可編輯區(qū)域中輸入字符時(shí),就會(huì)觸發(fā)這個(gè)事件
textInput事件的event對(duì)象中包括1個(gè)data屬性,這個(gè)屬性的值就是用戶輸入的字符(不是編碼)。
var textbox = document.getElementById("textbox");
EventUtil.addHandler(textbox,"textInput",function (event) {
event = EventUtil.getEvent(event);
alert(event.data);
})
contextmenu事件表示什么時(shí)候應(yīng)當(dāng)顯示上下文菜單,以便開發(fā)人員取消默許的上下文菜單而提供自定義的菜單
//contextmenu事件
EventUtil.addHandler(window,"load",function (event) {
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "contextmenu", function (event) {
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
var menu = div.nextElementSibling;
menu.style.left = event.clientX + "px";
menu.style.right = event.clientY + "px";
menu.style.visibility = "visible";
});
EventUtil.addHandler(document, "click", function (event) {
document.getElementById("myMenu").style.visibility = "hidden";
})
});
右鍵出現(xiàn)自定義的上下文信息
readystatechange事件的目的是提供與文檔或元素的加載狀態(tài)有關(guān)的信息
可能的狀態(tài)有5種:
uninitialized(未初始化):對(duì)象存在但還沒(méi)有初始化
loading(正在加載):對(duì)象正在加載數(shù)據(jù)
loaded(加載終了):對(duì)象加載數(shù)據(jù)完成
interactive(交互):可以操作對(duì)象了,但還沒(méi)有完全加載
complete(完成):對(duì)象已加載終了
并不是所有對(duì)象都會(huì)經(jīng)歷readyState的這幾個(gè)階段
栗子:
//readystatechange事件,肯定外部js是不是加載終了
EventUtil.addHandler(window, "load", function () {
var script = document.createElement("script");
EventUtil.addHandler(script, "readystatechange", function (event) {
var event = EventUtil.getEvent(event);
var target = event.getTarget(event);
if (target.readyState == "loaded" || target.readyState == "complete") {
EventUtil.removeHandler(target, "readystatechange", arguments.callee);
alert("event.js is loaded");
}
});
script.src = "test.js";
document.body.appendChild(script);
});
//readystatechange 事件,肯定外部css是不是加載終了
EventUtil.addHandler(window, "load", function () {
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
EventUtil.addHandler(link,"readystatechange", function (event) {
var event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
if (target.readyState == "loaded" || target.readyState == "complete") {
EventUtil.removeHandler(target, "readystatechange", arguments.callee);
}
});
link.href = "test.css";
document.getElementsByTagName("head")[0].appendChild(link);
});
//以上兩個(gè)函數(shù),最重要的是1并檢測(cè)readyState的兩個(gè)狀態(tài),并在調(diào)用了1次事件處理程序后就將其移除
對(duì)”事件處理程序過(guò)量“這個(gè)問(wèn)題的解決方案就是事件拜托,事件拜托利用了事件冒泡,只指定1個(gè)事件處理程序,就能夠管理某1類型的所有事件。比如,click事件會(huì)冒泡到document對(duì)象上,所以可以為全部頁(yè)面指定1個(gè)onclick事件處理程序,而沒(méi)必要給每一個(gè)可單擊的元素分別添加。
事件拜托的優(yōu)點(diǎn):
(1)在頁(yè)面中設(shè)置時(shí)間處理程序所需的時(shí)間更少。只添加1個(gè)事件處理程序所需的DOM援用更少,花費(fèi)時(shí)間少
(2)全部頁(yè)面占用的內(nèi)存空間更少,能夠提升整體性能。
合適使用時(shí)間拜托技術(shù)的事件有:click/mousedown/mouseup/keydown/keyup/keypress
內(nèi)存中留有那些過(guò)時(shí)不用的“空事件處理程序”,也是造成Web利用程序內(nèi)存與性能問(wèn)題的主要緣由,解決問(wèn)題的1種方法就是移除這些事件處理程序。
btn.onclick = null;
在頁(yè)面卸載之前,使用onunload事件,移除所有事件處理程序
String.fromCharCode( ): 可接受1個(gè)指定的Unicode值,返回對(duì)應(yīng)的字符串
/\d/.test(String.fromCharCode(EventUtil.getCharCode(event)))//判斷按鍵按下的是不是為數(shù)字
hasArrtibute( ):如果存在指定屬性,則hasAttribute方法返回true,否則返回false。
specified屬性:HTML DOM屬性,查明是不是已規(guī)定某屬性
PS.《JavaScript高級(jí)程序設(shè)計(jì)》書又刷了1遍,還是又學(xué)習(xí)了很多新的知識(shí),我覺(jué)著寫博客是1種鞏固學(xué)習(xí)的好方法,看書看1遍,把書上的代碼敲1遍,再在博客中梳理1遍,全部知識(shí)框架就會(huì)很清晰。最近心里也有點(diǎn)著急,看書速度有些慢了,又買了好幾本新書,不知道內(nèi)推之前還來(lái)不來(lái)的及看完了。英雄不打無(wú)準(zhǔn)備之仗,所以,加油!