JS學(xué)習(xí)12(事件)

事件流

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ā)下面的事件:

  1. focusout
  2. focusin
  3. blur
  4. DOMFocusOut
  5. focus
  6. 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ā)生的順序如下:

  1. touchstart
  2. mouseover
  3. mousemove (單次)
  4. mousedown
  5. mouseup
  6. click
  7. 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);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坪圾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惑朦,更是在濱河造成了極大的恐慌兽泄,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漾月,死亡現(xiàn)場離奇詭異已日,居然都是意外死亡,警方通過查閱死者的電腦和手機栅屏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門飘千,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人栈雳,你說我怎么就攤上這事护奈。” “怎么了哥纫?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵霉旗,是天一觀的道長。 經(jīng)常有香客問我,道長厌秒,這世上最難降的妖魔是什么读拆? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮鸵闪,結(jié)果婚禮上檐晕,老公的妹妹穿的比我還像新娘。我一直安慰自己蚌讼,他們只是感情好辟灰,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著篡石,像睡著了一般芥喇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上凰萨,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天继控,我揣著相機與錄音,去河邊找鬼胖眷。 笑死武通,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瘦材。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼仿畸,長吁一口氣:“原來是場噩夢啊……” “哼食棕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起错沽,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤簿晓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后千埃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體憔儿,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年放可,在試婚紗的時候發(fā)現(xiàn)自己被綠了谒臼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡耀里,死狀恐怖蜈缤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冯挎,我是刑警寧澤底哥,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響趾徽,放射性物質(zhì)發(fā)生泄漏续滋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一孵奶、第九天 我趴在偏房一處隱蔽的房頂上張望疲酌。 院中可真熱鬧,春花似錦拒课、人聲如沸徐勃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽僻肖。三九已至,卻和暖如春卢鹦,著一層夾襖步出監(jiān)牢的瞬間臀脏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工冀自, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留揉稚,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓熬粗,卻偏偏與公主長得像搀玖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子驻呐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 總結(jié): 鼠標(biāo)事件 1.click與dbclick事件$ele.click()$ele.click(handler(...
    阿r阿r閱讀 1,605評論 2 10
  • JavaScript 程序采用了異步事件驅(qū)動編程模型灌诅。在這種程序設(shè)計風(fēng)格下,當(dāng)文檔含末、瀏覽器猜拾、元素或與之相關(guān)的對象發(fā)...
    劼哥stone閱讀 1,256評論 3 11
  • JavaScript 與 HTML 間通過事件實現(xiàn)交互。事件——文檔或瀏覽器窗口中發(fā)生的一些特定的交互瞬間佣盒,即用戶...
    sylvia_yue閱讀 466評論 0 0
  • (續(xù)jQuery基礎(chǔ)(1)) 第5章 DOM節(jié)點的復(fù)制與替換 (1)DOM拷貝clone() 克隆節(jié)點是DOM的常...
    凜0_0閱讀 1,336評論 0 8
  • 時間?﹏?2016年(離小學(xué)畢業(yè)僅剩一個月) 地點?﹏?小學(xué)校園 小說類別?﹏?言情小說挎袜,青春文學(xué),校園故事 主人...
    灰太狼不壞閱讀 208評論 0 0