事件流
IE和Netscape開發(fā)團隊提出了完全相反的兩種事件流的概念,事件冒泡流和事件捕獲流宛瞄。
事件冒泡
事件由最具體的元素開始缤骨,逐級向上傳播到較不具體的元素爱咬,最終到文檔。
事件捕獲
事件捕獲從document開始荷憋,逐級向下台颠,最后傳到最具體的節(jié)點。
DOM事件流
DOM2級事件定義的事件流包含3個階段:事件捕獲階段勒庄,處于目標(biāo)階段串前,事件冒泡階段。
捕獲階段會從文檔節(jié)點自上而下傳遞直到目標(biāo)節(jié)點的上一個節(jié)點实蔽;處于目標(biāo)階段時傳到目標(biāo)節(jié)點荡碾,冒泡階段開始向上傳遞知道文檔節(jié)點。
規(guī)定是捕獲階段事件不傳遞到目標(biāo)節(jié)點局装,但是大多數(shù)瀏覽器就傳遞到了坛吁,這就意味著有2次機會在目標(biāo)對象上操作事件。
事件處理程序
響應(yīng)某個事件的函數(shù)
HTML事件處理程序
可以使用HTML特性來指定铐尚。
<input type="button" value="Click Me" onclick="alert(event.type)">
<input type="button" value="Click Me" onclick="alert(this.value)">
<input type="button" value="hahaah" onclick="clickButton(this)">
function clickButton(element) {
alert(element.value);
}
這里注意JS代碼中如果出現(xiàn)&""<>要使用轉(zhuǎn)義字符拨脉。
這樣寫事件處理程序是很不靈活的,HTML代碼和JS代碼耦合度太高宣增。
不過這樣寫是有一些方便的地方的玫膀,這樣寫的JS語句會被包含在一個動態(tài)創(chuàng)建的函數(shù)中,這個函數(shù)中會存在一個局部變量event事件對象爹脾,而且通過this這個變量可以訪問到元素本身帖旨。這個函數(shù)還會使用with拓展作用域,讓你更方便的直接訪問document及元素本身的成員:
function(){
with(document){
with(this){
//你的代碼
}
}
}
//于是可以直接這樣寫
<input type="button" value="Click Me" onclick="alert(value)">
如果要調(diào)用函數(shù)灵妨,這個函數(shù)在JS中要處于全局作用域哦解阅,而且要使用this對象要將this作為參數(shù)傳進去,否則是訪問不到的泌霍。
這樣寫事件處理程序是有問題的货抄,一個是緊耦合的問題,一個是時間差,如果你的JS文件是放在最下面的碉熄,有可能會出現(xiàn)函數(shù)已經(jīng)綁在事件上了可是JS卻還沒給出函數(shù)定義桨武,這樣就會報錯,為了避免這樣的情況出現(xiàn)锈津,我們使用try-catch:
<input type="button" value="Click Me" onclick="try{clickButton(this);}catch(ex){}">
不過還是不那么理想是吧呀酸。
DOM0級事件處理程序
每個元素都有自己的事件處理程序?qū)傩裕赃@種方式添加的事件會在事件流的冒泡階段被處理琼梆。傳入的處理函數(shù)是在元素的作用域中運行性誉。將這個屬性指向空就取消了事件綁定,值得一提的是茎杂,如果你使用上面的HTML特性指定事件處理函數(shù)错览,這個屬性里就包含著HTML里你寫的事件函數(shù)的代碼,置空也同樣可以取消綁定煌往。
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(this.id); //"myBtn"
};
btn.onclick = null;
DOM2級事件處理程序
IE8及以下不支持DOM2級事件
DOM2級事件定義了兩種方法:addEventListener() removeEventListener()倾哺。這兩個方法接受3個參數(shù),要處理的事件名刽脖,處理函數(shù)羞海,和一個布爾值。這個布爾值代表在捕獲節(jié)點調(diào)用事件處理程序(true)還是在冒泡過程中調(diào)用曲管。
這樣添加意味著可以添加多個事件處理程序却邓,在事件觸發(fā)時會按照添加的順序來執(zhí)行。傳入的處理函數(shù)是在元素的作用域中運行院水。
注銷時要傳入完全相同的函數(shù)才能注銷腊徙,這就意味著如果你的處理函數(shù)是以匿名函數(shù)的方式傳遞進去的,那就不可能注銷了哦檬某,因為再傳進去一個匿名函數(shù)也不是原先那個了:
var btn = document.getElementById("myButton");
var body = document.body;
//冒泡階段
body.addEventListener("click", function(){
alert("Hello world!");
}, false);
//捕獲階段
body.addEventListener("click", function(){
alert("Hello world!");
}, true);
//如果是使用匿名函數(shù)注冊的
btn.addEventListener("click", function(){
alert(this.id + "匿名");
}, false);
//注銷不掉
btn.removeEventListener("click", function(){
alert(this.id);
}, false);
//這樣就能注銷掉了
var handler = function(){
alert(this.id + "非匿名");
};
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);
IE事件處理程序
IE8及以下不支持DOM2級事件撬腾,但是支持兩個類似方法attachEvent()、detachEvent()
只支持冒泡階段
傳入的處理函數(shù)是在全局作用域中運行
添加多個事件時觸發(fā)順序與添加順序相反
注銷時同樣需要傳入相同的參數(shù)恢恼,匿名函數(shù)無法注銷时鸵。
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(){
alert(this === window); //true
});
var handler = function(){
alert("Clicked");
};
btn.attachEvent("onclick", handler);
btn.detachEvent("onclick", handler);
跨瀏覽器事件處理程序
優(yōu)先使用DOM2級的,再不行使用IE專有的厅瞎,最后使用DOM0級的(一般不可能用到)
var EventUtil = {
addHandler: 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;
}
},
removeHandler: 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;
} }
};
var btn = document.getElementById("myButton");
var handler = function(){
alert("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
EventUtil.removeHandler(btn, "click", handler);
事件對象
事件被觸發(fā)時會產(chǎn)生一個事件對象,這個對象中包含著所有與事件有關(guān)的信息初坠,包括導(dǎo)致事件的元素和簸,事件的類型以及其他各個事件特定的信息。所有瀏覽器都支持event對象碟刺,但是實現(xiàn)不同锁保。
DOM中的事件對象
兼容DOM的瀏覽器會將一個event對像傳入到事件處理程序中,三種方式都有
btn.onclick = function(event){
alert(event.type); //"click"
};
btn.addEventListener("click", function(event){
alert(event.type); //"click"
}, false);
<input type="button" value="Click Me" onclick="alert(event.type)"/>
所有的event對象都會有下面的方法:
屬性/方法 | 類型 | 讀寫 | 說明 |
---|---|---|---|
bubbles | Boolean | 只讀 | 事件是否冒泡 |
cancelable | Boolean | 只讀 | 是否可以取消事件的默認(rèn)行為 |
currentTarget | Element | 只讀 | 當(dāng)前正在處理事件的那個元素 |
defaultPrevented | Boolean | 只讀 | 是否已經(jīng)調(diào)用了preventDefault()。DOM3 |
detail | Integer | 只讀 | 與事件相關(guān)的細節(jié)信息 |
eventPhase | Integer | 只讀 | 觸發(fā)事件的階段爽柒,1捕獲吴菠,2處于目標(biāo),3冒泡 |
preventDefault() | Function | 只讀 | 取消事件的默認(rèn)行為 |
stopImmediatePropagation() | Function | 只讀 | 取消進一步的捕獲或冒泡浩村,同時阻止任何事件處理程序被調(diào)用做葵。DOM3 |
stopPropagation() | Function | 只讀 | 取消進一步的捕獲或冒泡 |
target | Element | 只讀 | 事件的目標(biāo) |
trusted | Boolean | 只讀 | true表示是由瀏覽器生成的事件,false說明是JS創(chuàng)建的心墅。DOM3 |
type | String | 只讀 | 事件的類型 |
view | AbstractView | 只讀 | 與事件關(guān)聯(lián)的抽象視圖酿矢,等同于發(fā)生事件的window對象 |
關(guān)于currentTarget的解釋
在事件處理程序的內(nèi)部,this始終指向currentTarget的值怎燥,而target則只包含事件的實際目標(biāo)瘫筐。
//當(dāng)事件處理函數(shù)就在按鈕上時可能看不出什么區(qū)別,但是當(dāng)在按鈕的父元素上時就不同了
document.body.onclick = function(event){
alert(event.currentTarget === document.body); //true
alert(this === document.body); //true
alert(event.target === document.getElementById("myBtn")); //true
};
preventDefault()
比如a標(biāo)簽的默認(rèn)行為就是跳轉(zhuǎn)到URL铐姚,使用event.preventDefault()可以阻止策肝。
cancelable是true的事件才可以阻止。
var link = document.getElementById("myLink");
link.onclick = function(event){
event.preventDefault();
};
IE中的事件對象
event在IE中是window的一個屬性隐绵,可以直接獲取
var btn = document.getElementById("myBtn");
btn.onclick = function(){
var event = window.event;
alert(event.type); //"click"
};
btn.attachEvent("onclick", function(event){
alert(event.type); //"click"
});
屬性/方法 | 類型 | 讀寫 | 說明 |
---|---|---|---|
cancelBubble | Boolean | 讀寫 | 默認(rèn)為false之众,將其設(shè)置為true就可以取消冒泡 |
returnValue | Boolean | 讀寫 | 默認(rèn)為true,設(shè)為false可以取消事件的默認(rèn)行為 |
srcElement | Element | 只讀 | 與target相同 |
type | String | 只讀 | 事件的類型 |
要注意在IE中的事件處理程序最好不要使用this氢橙,使用event.srcElement比較保險
btn.attachEvent("onclick", function(event){
alert(event.srcElement === this); //false
});
跨瀏覽器的事件對象
根據(jù)瀏覽器之間的區(qū)別酝枢,在剛才的EventUtil中添加下列方法:
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;
}
}
這樣使用~~
var link = document.getElementById("link");
var body = document.body;
var handler = function (event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
EventUtil.preventDefault(event);
EventUtil.stopPropagation(event);
alert(target);
alert(event.target);
}
link.addEventListener("click", handler, false);
body.addEventListener("click", handler, false);
事件類型
DOM3級事件規(guī)定了如下幾類事件:
- UI事件
- 焦點事件
- 鼠標(biāo)事件
- 滾輪事件
- 文本事件
- 鍵盤事件
- 合成事件
- 變動事件
除了這幾類事件,HTML5也定義了一組事件悍手,有的瀏覽器還有一些專有事件帘睦。
UI事件
- DOMActivate:表示元素已經(jīng)被用戶操作,DOM3已經(jīng)棄用了
- load:當(dāng)頁面完全加載后在window上觸發(fā)坦康,當(dāng)所有框架加載完畢時在框架集上觸發(fā)竣付,圖像加載完時在img上觸發(fā),當(dāng)嵌入內(nèi)容加載完畢時在object元素上觸發(fā)
- unload:load對應(yīng)的那些滞欠,完全卸載后觸發(fā)
- abort:在用戶下載過程中古胆,如果內(nèi)容沒下載完,在object元素上觸發(fā)
- error:JavaScript出錯時在window上觸發(fā)筛璧,無法加載圖片時在omg上觸發(fā)逸绎,有一個或多個框架無法加載時在框架集上觸發(fā)
- select:用戶選擇文本(input,texture)中的一個或多個字符時觸發(fā)
- resize:當(dāng)窗口或框架大小改變時在window或框架觸發(fā)
- scroll:當(dāng)用戶滾動帶滾動條的元素時在該元素上觸發(fā)夭谤,body元素有頁面的滾動條
要確定瀏覽器是否支持:
var isSupported = document.implementation.hasFeature("HTMLEvents", "2.0");
var isSupported = document.implementation.hasFeature("UIEvent", "3.0");
load事件
DOM2級事件規(guī)范是在document上觸發(fā)load事件棺牧,不過為了兼容所有瀏覽器都在window上實現(xiàn)了load
EventUtil.addHandler(window, "load", function(){
var image = document.createElement("img");
EventUtil.addHandler(image, "load", function(event){
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src);
});
//就算不吧img添加到文檔,只要設(shè)置了SRC就會開始下載
//document.body.appendChild(image);
image.src = "http://www.feng.com/images/icon_01.png";
});
有的瀏覽器在script和link上也會有l(wèi)oad事件
unload事件
這個事件在文檔在完全被卸載后觸發(fā),只要用戶從一個頁面切換到另一個頁面就回觸發(fā)這個事件朗儒。利用這個事件可以清除引用
EventUtil.addHandler(window, "unload", function(event){
alert("Unloaded");
});
resize事件
EventUtil.addHandler(window, "resize", function(event){
alert("Resized");
});
瀏覽器可能會在窗口大小改變1px的時候就觸發(fā)這個事件颊乘,要小心不要在這里放開銷大的方法参淹。
scroll事件
這個事件可以添加到任何有滾動條的元素上。也是會被重復(fù)觸發(fā)的乏悄。頁面的
EventUtil.addHandler(document.getElementById("scrollTest"), "scroll", function(event){
alert("div Scrolled");
});
EventUtil.addHandler(window, "scroll", function(event){
alert("window Scrolled");
});
焦點事件
與document.hasFocus()和document.activeElement配合可以知曉用戶在頁面上的行蹤浙值。
- blur:在元素失去焦點時觸發(fā),不會冒泡
- DOMFocusIn:元素獲得焦點時觸發(fā)檩小,冒泡开呐,DOM3廢棄
- DOMFocusOut:元素失去焦點,DOM3廢棄
- focus:元素獲得焦點時觸發(fā)识啦,不冒泡
- focusin:與focus等價负蚊,但冒泡,不是所有瀏覽器都支持颓哮,較新的都支持
- focusout:失去焦點家妆,冒泡,較新的支持
當(dāng)焦點從一個元素移到另一個冕茅,依次觸發(fā)下面的事件:
- focusout
- focusin
- blur
- DOMFocusOut
- focus
- DOMFocusIn
focusin和focus還是有一些區(qū)別的伤极,試試這兩個你就知道啦:
<input type="text" id="textField">
var btn = document.getElementById("textField");
btn.addEventListener("focus",function () {
alert("button On Focus");
},false);
btn.addEventListener("focusin",function () {
alert("button On Focus");
},false);
focus事件會在alert被關(guān)掉之后,焦點回到input時再次觸發(fā)姨伤,alert會不停的出現(xiàn)哨坪。
focusing就只會alert一次。
鼠標(biāo)與滾輪事件
DOM3級事件中定義了9個鼠標(biāo)事件:
- click:單擊主鼠標(biāo)按鈕或按下回車鍵時觸發(fā)
- dblclick:雙擊主鼠標(biāo)按鈕
- mousedown:用戶按下任意鼠標(biāo)按鈕
- mouseup:釋放鼠標(biāo)按鈕時觸發(fā)
- mouseenter:光標(biāo)從元素外首次移到元素內(nèi)觸發(fā)乍楚。不冒泡当编。而且在光標(biāo)移動到后代元素上時不會觸發(fā)。
- mouseleave:移出元素時觸發(fā)徒溪,不冒泡忿偷,移出后代元素時不會觸發(fā)。
- mousemove:在元素內(nèi)部移動時重復(fù)觸發(fā)
- mouseout:指針位于一個元素上方臊泌,移入另一個元素時觸發(fā)鲤桥,移入的元素是當(dāng)前元素的子元素時也會觸發(fā)
- mouseover:移入本元素時觸發(fā),移入本元素的某個子元素時也會觸發(fā)
- mousewheel:跟蹤鼠標(biāo)滾輪或觸控板滾動
其中click事件的觸發(fā)依賴在同一個元素上相繼觸發(fā)mousedown渠概,mouse茶凳。dblclick則要在同一個元素上觸發(fā)兩次click。
客戶區(qū)坐標(biāo)位置
位置信息保存在clientX播揪,clientY贮喧。表示鼠標(biāo)事件發(fā)生時鼠標(biāo)指針在視口中的位置。要注意的是猪狈,這個是指針相對于視口的位置箱沦,如果你的頁面發(fā)生滾動而鼠標(biāo)沒動,這個坐標(biāo)不會有變化罪裹。
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert(event.clientX + "," + event.clientY);
});
頁面坐標(biāo)位置
這個就真的是在頁面中的位置了pageX饱普,pageY
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Page coordinates: " + event.pageX + "," + event.pageY);
});
屏幕坐標(biāo)位置
鼠標(biāo)相對屏幕的坐標(biāo)信息screenX,screenY
修改鍵
在鼠標(biāo)按下的時候可以檢查Shift状共、Ctrl套耕、Alt、Meta哪個鍵被按下了峡继。由此做一些特定的操作冯袍。由event的4個屬性來檢查:shiftKey、ctrlKey碾牌、altKey康愤、metaKey。
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
var keys = new Array();
if (event.shiftKey){
keys.push("shift");
}
if (event.ctrlKey){
keys.push("ctrl");
}
if (event.altKey){
keys.push("alt");
}
if (event.metaKey){
keys.push("meta");
}
alert("Keys: " + keys.join(","));
});
相關(guān)元素
mouseover舶吗、mouserout這兩個事件是有相關(guān)元素的征冷。比如mouseover時你移出的那個元素就是相關(guān)元素∈那恚可以通過event的relatedTarget屬性來獲得检激。IE8及以下通過fromElement和toElement來獲得。由于又有兼容問題腹侣,再次拓展我們的工具包咯:
getRelatedTarget: function(event){
if (event.relatedTarget){
return event.relatedTarget;
} else if (event.toElement){
return event.toElement;
} else if (event.fromElement){
return event.fromElement;
} else {
return null;
}
}
鼠標(biāo)按鈕
click只在鼠標(biāo)主鍵被按下時觸發(fā)叔收,所以并不存在檢測按鈕的問題,不過對于mousedown和mouseup來說就不一樣了傲隶,在他們的event中有一個button屬性饺律。DOM的button屬性有如下3個值:0主鍵,1滾輪鍵跺株,2次鍵复濒。
IE8之前也有button,不過差別比較大帖鸦,有8個值:
- 0:沒有按鈕
- 1:主
- 2:次
- 3:主次同時
- 4:滾輪
- 5:主芝薇,滾輪同時
- 6:次,滾輪同時
- 7:3個同時
是時候拓展工具包了:
getButton: function(event){
if (document.implementation.hasFeature("MouseEvents", "2.0")){
return event.button;
} else {
switch(event.button){
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
case 6:
return 2;
case 4:
return 1;
}
}
}
mousewheel事件
在滾輪滾動時觸發(fā)作儿,event有一個特殊的屬性wheelDelta向上滾是負(fù)值洛二,向下滾是正值。Opera早期版本相反攻锰。
EventUtil.addHandler(document, "mousewheel", function(event){
event = EventUtil.getEvent(event);
var delta = (client.engine.opera && client.engine.opera < 9.5 ?
-event.wheelDelta : event.wheelDelta);
alert(delta);
});
除firefox外都支持這個事件晾嘶,firefox支持的是DOMMouseScroll。
EventUtil.addHandler(window, "DOMMouseScroll", function(event){
event = EventUtil.getEvent(event);
alert(event.detail);
});
觸摸設(shè)備
觸摸設(shè)備不支持dblclick事件娶吞,雙擊會放大頁面
輕擊可單擊的元素會觸發(fā)mousemove事件垒迂。如果此操作會導(dǎo)致內(nèi)容變化,將不再有其他事件發(fā)生妒蛇;如果屏幕沒有因此發(fā)生變化机断,那么會依次發(fā)生mousedown楷拳、mouseup、click事件
輕擊不可單擊的元素不會觸發(fā)任何事件吏奸。
可單擊元素是指那些單擊有默認(rèn)操作的元素欢揖,或者你指定了onclick事件處理函數(shù)的元素。
mousemove事件也會觸發(fā)mouseover和mouseout事件奋蔚。
兩個手指放在屏幕上且頁面隨手指移動而滾動時會觸發(fā)mousewheel和scroll事件她混。
無障礙性問題
無障礙主要就是針對盲人的設(shè)計,盲人會使用屏幕閱讀器泊碑,而屏幕閱讀器使用鍵盤來觸發(fā)事件坤按。
所以盡量使用click事件,因為回車可以直接觸發(fā)馒过。
如果一定要使用那些鍵盤默認(rèn)觸發(fā)不了的操作臭脓,比如onmouseover、dblclick沉桌,應(yīng)添加鍵盤快捷方式谢鹊。
鍵盤與文本事件
鍵盤事件:
- keydown:當(dāng)用戶按下任意鍵觸發(fā),按住不放重復(fù)觸發(fā)
- keypress:當(dāng)用戶按下鍵盤上字符鍵時觸發(fā)留凭,按住不放時重復(fù)觸發(fā)
- keyup:當(dāng)用戶釋放鍵盤上的鍵時觸發(fā)
文本事件:
- textInput:文本插入文本框前會觸發(fā)
在用戶按下字符鍵時會觸發(fā)keydown佃扼,緊接著keypress,如果是在文本框里輸入文字這時會觸發(fā)textInput蔼夜,如果用戶抬起來了按鍵就會觸發(fā)keyup兼耀,不抬起來會重復(fù)觸發(fā)keydown,keypress求冷,textInput瘤运。
鍵盤事件也支持shiftKey、ctrlKey匠题、altKey拯坟、metaKey。
鍵碼
在發(fā)生keydown和keyup事件時韭山,event對象的keyCode屬性中會包含一個代碼郁季,數(shù)字字母鍵就是ASCII碼。
字符編碼
發(fā)生keypress意味著按下的鍵會影響到屏幕中文本的顯示钱磅,按下能插入或刪除字符的鍵都會觸發(fā)keypress事件梦裂。
屬性charCode只有在keypress事件時才包含值,這個值是按下的那個鍵所帶代表字符的ASCII碼盖淡,而此時的keyCode可能等于0年柠,也可能等于鍵碼,所以跨瀏覽器要小心:
getCharCode: function(event){
if (typeof event.charCode == "number"){
return event.charCode;
} else {
return event.keyCode;
}
}
EventUtil.addHandler(textbox, "keypress", function(event) {
event = EventUtil.getEvent(event);
alert(String.fromCharCode(EventUtil.getCharCode(event)));
});
DOM3級變化
DOM3中不再包含charCode褪迟,改為key和char冗恨。key就是鍵名字符串:“K”答憔、“g”、“Shift”等掀抹。char在字符鍵情況下與key相同攀唯,非字符鍵時為null。
textInput事件
只有可編輯區(qū)域才會觸發(fā)textInput渴丸。且只有有效的輸入會觸發(fā)梢杭。這個事件的事件對象里有個data效扫,這個屬性里保存的就是實實在在的輸入數(shù)據(jù),你輸入a或A或粘貼進來的asdfasdf在這里都會得到體現(xiàn)浙炼。
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "textInput", function(event){
event = EventUtil.getEvent(event);
alert(event.data);
});
還有一個屬性叫inputMethod吠谢,表示把文本輸入到文本框的方式土童,粘貼,拖放工坊,手寫之類的献汗,只有IE實現(xiàn)了。
復(fù)合事件
只有IE9+支持
DOM3級中新添加的事件用來處理IME的輸入序列王污,IME是輸入法編輯器罢吃,可以讓用戶輸入在物理鍵盤上找不到的字符,IME通常需要按住多個鍵最終只輸入一個字符昭齐。有3個事件:
- compositionstart:IME被打開尿招,這是event里的data屬性是正在編輯的文本(比如已經(jīng)被選中馬上要被替換的文本,正常輸入情況下一般是空)
- compositionupdate:在向輸入字段插入新字符時觸發(fā)阱驾,data包含正插入的新字符
- compositionend:IME關(guān)閉就谜,返回正常鍵盤輸入狀態(tài)時,data包含此次插入的所有字符里覆。
EventUtil.addHandler(textbox, "compositionstart", function(event){
event = EventUtil.getEvent(event);
alert(event.data);
});
變動事件
DOM2級的變動事件在DOM中某一部分發(fā)生變化時給出提示丧荐,跟少用到
- DOMSubtreeModified
- DOMNodeInserted
- DOMNodeRemoved
- DOMNodeInsertedIntoDocument
- DOMNodeInserted
- DOMNodeRemovedFromDocument
- DOMNodeRemoved
- DOMAttrModified
- DOMCharacterDataModified
HTML5事件
contextmenu事件
這個事件在右鍵調(diào)出上下文菜單時被觸發(fā),可以通過取消默認(rèn)事件來彈出自己的右鍵菜單喧枷,這個事件冒泡虹统。
EventUtil.addHandler(document, "contextmenu", function(event){
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
var menu = document.getElementById("myMenu");
menu.style.left = event.pageX + "px";
menu.style.top = event.pageY + "px";
menu.style.visibility = "visible";
});
beforeunload事件
這是為了讓開發(fā)人員在頁面被卸載前有可能提醒用戶
EventUtil.addHandler(window, "beforeunload", function(event){
event = EventUtil.getEvent(event);
var message = "I'm really going to miss you if you go.";
event.returnValue = message;
return message;
});
DOMContentLoaded事件
這個事件和window的load事件不同,這個不理會各種圖片割去,JS等文件是否加載完成窟却,只要完整的DOM結(jié)構(gòu)OK了就觸發(fā)。
這允許我們盡早的添加事件處理程序和DOM操作等呻逆。
這個事件的目標(biāo)實際上是document夸赫,雖然會冒泡到windows
EventUtil.addHandler(document, "DOMContentLoaded", function(event){
alert("Content loaded");
alert(event.target);//[object HTMLDocument]
});
readystatechange事件
IE、Firfox 4+咖城、Opera茬腿。
為某些元素提供的事件呼奢,目的是提供與文檔或元素的加載狀態(tài)有關(guān)的信息,支持這個事件的每個對象都有一個readyState屬性切平,有5個可能值:uninitialized握础、loading、loaded悴品、interactive禀综、complete
interactive,complete不一定哪個先出現(xiàn)苔严,所以要快的話兩個一起檢測定枷,為避免執(zhí)行兩次,檢測到了就注銷事件
EventUtil.addHandler(document, "readystatechange", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
if (target.readyState == "loaded" || target.readyState == "complete"){
EventUtil.removeHandler(target, "readystatechange", arguments. callee);
alert("Content Loaded");
}
});
pageshow和pagehide
有的瀏覽器有一種特性叫往返緩存届氢,使用戶在使用前進后退按鈕時更快欠窒,這個緩存完全保存了整個頁面,包括JS的執(zhí)行狀態(tài)退子,這就意味著不會再觸發(fā)load事件岖妄。
pageshow無論這個頁面是新打開的還是在往返緩存中的,都會在這個頁面顯示的時候觸發(fā)寂祥。新打開的會在load后觸發(fā)荐虐。
其event對象中有一個persisted屬性,是true時代表是從往返緩存中恢復(fù)的丸凭。
(function(){
var showCount = 0;
EventUtil.addHandler(window, "load", function(){
alert("Load fired");
});
EventUtil.addHandler(window, "pageshow", function(){
showCount++;
alert("Show has been fired " + showCount +
" times. Persisted? " + event.persisted);
});
})();
pagehide是在unload之前被觸發(fā)的缚俏。
指定了onunload事件的頁面不會被存在往返緩存中,因為onunload事件一般是為了撤銷在load事件中做的事贮乳。
hashchange事件
這個事件在URL參數(shù)列表發(fā)生改變時觸發(fā)忧换,這個事件要添加到window對象
EventUtil.addHandler(window, "hashchange", function(event){
alert("Current hash: " + location.hash);
});
設(shè)備事件
這些事件是針對移動設(shè)備的
orientationchange事件
這是Apple在移動版本的Safari中加入的事件,其window.orientation中可能包含3個值:0向拆、90亚茬、-90。只要用戶改變了設(shè)備的查看模式就會觸發(fā)該事件浓恳。iOS設(shè)備都支持這個事件刹缝。
EventUtil.addHandler(window, "orientationchange", function(event){
alert(window.orientation);
});
MozOrientation事件
這是火狐引入的檢測設(shè)備旋轉(zhuǎn)的事件,其event中有x颈将、y梢夯、z三個值,有加速計的設(shè)備就可以用
EventUtil.addHandler(window, "MozOrientation", function(event){
var output = document.getElementById("output");
output.innerHTML = "X=" + event.x + ", Y=" + event.y + ", Z=" + event.z +"<br>";
});
deviceorientation事件
這個事件也是檢測加速計來獲得設(shè)備方向的變化晴圾,變化時在window上觸發(fā)颂砸。設(shè)備在平躺時z軸向上。
事件的event對象中有如下5個屬性:
- alpha:圍繞z軸旋轉(zhuǎn)時,y軸的度數(shù)差人乓,0~360的浮點數(shù)
- beta:圍繞x軸旋轉(zhuǎn)時勤篮,z軸的度數(shù)差-180~180的浮點數(shù)
- gamma:圍繞y軸旋轉(zhuǎn)時,z軸的度數(shù)差色罚,-90~90的浮點數(shù)
- absolute:布爾值碰缔,設(shè)備是否返回一個絕對值
- compassCalibrated:布爾值,指南針是否校準(zhǔn)
EventUtil.addHandler(window, "deviceorientation", function(event){
alert("Alpha=" + event.alpha + ", Beta=" + event.beta + ", Gamma=" + event.gamma);
});
devicemotion事件
這個事件告訴開發(fā)人員設(shè)備什么時候移動戳护,其事件對象包含以下屬性:
- acceleration:一個包含xyz的對象金抡,排除重力每個方向的加速度
- accelerationIncludingGravity:考慮重力,每個方向的加速度
- interval:以毫秒表示的時間值腌且,在每次事件中是常量竟终。
- rotationRate:包含表示方向的alpha、beta切蟋、gamma屬性的對象
以上這些值讀不到就是null,用前先檢測
EventUtil.addHandler(window, "devicemotion", function(event){
var output = document.getElementById("output");
if (event.rotationRate !== null){
output.innerHTML += "Alpha=" + event.rotationRate.alpha + ", Beta=" +
event.rotationRate.beta + ", Gamma=" +
event.rotationRate.gamma;
}
});
觸摸與手勢事件
觸摸事件
在iOS和Android上實現(xiàn)了
- touchstart:每根手指觸摸屏幕時觸發(fā)
- touchmove:手指在屏幕上滑動時連續(xù)觸發(fā)榆芦,調(diào)用preventDefault()可以阻止頁面滾動
- touchend:手指移開
- touchcancel:系統(tǒng)停止跟蹤觸摸時觸發(fā)
上面幾個事件都會冒泡柄粹,也都可以取消。
event對象中常見的鼠標(biāo)事件的屬性都有:bubbles匆绣、cancelable驻右、view、clientX崎淳、clientY堪夭、screenX、screenY拣凹、detail森爽、altKey、shiftKey嚣镜、ctrlKey爬迟、metaKey。
還包含三個用于跟蹤觸摸事件的屬性: - touches:表示當(dāng)前跟蹤的觸摸操作的Touch對象的數(shù)組
- targetTouchs:特定于事件目標(biāo)的Touch對象的數(shù)組
- changeTouches:表示自上次觸摸以來發(fā)生什么改變的Touch對象的數(shù)組
每個Touch對象有下列屬性:
- clientX
- clientY
- identifier:表示觸摸的唯一ID
- pageX
- pageY
- screenX
- screenY
- target
function handleTouchEvent(event){
if (event.touches.length == 1){
var output = document.getElementById("output");
switch(event.type){
case "touchstart":
output.innerHTML = "Touch started (" +
event.touches[0].clientX +
"," + event.touches[0].clientY + ")";
break;
case "touchend":
output.innerHTML += "<br>Touch ended (" +
event.changedTouches[0].clientX + "," +
event.changedTouches[0].clientY + ")";
break;
case "touchmove":
event.preventDefault(); //
output.innerHTML += "<br>Touch moved (" +
event.changedTouches[0].clientX + "," +
event.changedTouches[0].clientY + ")";
break;
}
}
}
EventUtil.addHandler(document, "touchstart", handleTouchEvent);
EventUtil.addHandler(document, "touchend", handleTouchEvent);
EventUtil.addHandler(document, "touchmove", handleTouchEvent);
觸摸屏幕上的元素時菊匿,事件發(fā)生的順序如下:
- touchstart
- mouseover
- mousemove (單次)
- mousedown
- mouseup
- click
- touchend
手勢事件
當(dāng)兩個手指觸摸屏幕時會產(chǎn)生手勢付呕,iOS中的Safari定義了3個手勢事件:
gesturestart
- gesturestart:一個手指已在屏幕上另一個手指又觸摸屏幕
- gesturechange:當(dāng)觸摸屏幕的任何一個手指發(fā)生變化的時候
- gestureend:任何一個手指移開
事件都冒泡
鼠標(biāo)事件的標(biāo)準(zhǔn)屬性都有
兩個特殊事件:rotation、scale
rotation表示手指變化引起的旋轉(zhuǎn)角度跌捆,負(fù)值表示逆時針
scale表示兩個手指間距離的變化徽职,從1開始變
function handleGestureEvent(event) {
var output = document.getElementById("output");
switch (event.type) {
case "gesturestart":
output.innerHTML = "Gesture started (rotation=" + event.rotation +
",scale=" + event.scale + ")";
break;
case "gestureend":
output.innerHTML += "<br>Gesture ended (rotation=" + event.rotation +
",scale=" + event.scale + ")";
break;
case "gesturechange":
output.innerHTML += "<br>Gesture changed (rotation=" + event.rotation +
",scale=" + event.scale + ")";
break;
}
}
document.addEventListener("gesturestart", handleGestureEvent, false);
document.addEventListener("gestureend", handleGestureEvent, false);
document.addEventListener("gesturechange", handleGestureEvent, false);
內(nèi)存和性能
在JS中添加到頁面上的事件處理程序數(shù)量將直接關(guān)系到頁面的整體運行性能。
事件委托
利用事件的冒泡特性佩厚,在DOM樹種盡量高的層次上添加一個事件處理程序:
EventUtil.addHandler(document, "click", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch(target.id){
case "myButton":
document.title = "I changed the document's title";
break;
case "highDiv":
location.;
break;
case "myDiv":
alert("hi");
break;
}
});
這樣做優(yōu)點很多
- 只需要取得一個DOM元素或直接加在document上姆钉,快
- 只添加了一個事件處理函數(shù),內(nèi)存占用小
- 如果直接添加在document上,document不需要等待load事件育韩,也就是說按鈕只要出現(xiàn)立即可用
移除事件處理程序
事件與元素的連接越多克蚂,頁面就越慢。限制事件數(shù)量剛才我們已經(jīng)做了筋讨。另外就是在不需要的時候移除事件處理程序埃叭。
當(dāng)我們移除或替換節(jié)點時,原有節(jié)點的事件處理程序卻還在悉罕,這時最好手工將其事件解綁赤屋。如果一開始你的事件處理就像剛才那樣寫在了高層次的元素中,這個問題就不存在啦壁袄。
還有就是在我們卸載頁面時类早,有的瀏覽器處理的并不好,頁面被卸載了但是處理程序還在嗜逻,來回來回切換打開的過程中內(nèi)存里就多了很多沒用或重復(fù)的事件涩僻。我們可以在onunload事件中移除所有事件處理程序。這就體現(xiàn)了將事件處理集中起來的優(yōu)點——移除時很輕松栈顷。
模擬事件
通過JS來觸發(fā)本該由瀏覽器觸發(fā)的事件
DOM中的事件模擬
鼠標(biāo)事件
var div = document.getElementById("myDiv");
//先創(chuàng)建一個事件,會返回一個特定的事件對象
var event = document.createEvent("MouseEvents");
//用各種參數(shù)初始化事件對象
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,
false, false, false, false, 0, null);
//在目標(biāo)元素上觸發(fā)
div.dispatchEvent(event);
可以模擬下面這些事件UIEvents逆日、MouseEvents、MutationEvents萄凤、HTMLEvents室抽。具體的就不寫了大體一致的思路。
IE中的事件模擬
一樣的思路靡努,方法不太一樣
var btn = document.getElementById("myBtn");
var event = document.createEventObject();
event.screenX = 100;
event.screenY = 0;
event.clientX = 0;
event.clientY = 0;
event.ctrlKey = false;
event.altKey = false;
event.shiftKey = false;
event.button = 0;
btn.fireEvent("onclick", event);