>>>>> 事件

事件冒泡

事件冒泡 : 當(dāng)一個(gè)元素接收到事件的時(shí)候,會(huì)把他接收到的所有傳播給他的父級(jí),一直到頂層window.事件冒泡機(jī)制

<style>
div {padding: 40px;}
#div1 {background:red}
#div2 {background:green}
#div3 {background:blue}
</style>

<div id="div1">
    <div id="div2">
        <div id="div3"></div>
    </div>
</div>

<script>
var oDiv1 = document.getElementById('div1');
var oDiv2 = document.getElementById('div2');
var oDiv3 = document.getElementById('div3');
function fn1() {
    alert( this.id );
}
oDiv1.onclick = fn1;
oDiv2.onclick = fn1;
oDiv3.onclick = fn1;
</script>

點(diǎn)擊div3, div3 div2 div1上的點(diǎn)擊事件都會(huì)被觸發(fā)

事件冒泡與樣式無(wú)關(guān),與html結(jié)構(gòu)相關(guān)

事件對(duì)象

在觸發(fā)DOM上的某個(gè)事件的時(shí)候會(huì)產(chǎn)生一個(gè)事件對(duì)象event,這個(gè)對(duì)象包含著所有與事件有關(guān)的信息,包括產(chǎn)生事件的元素、事件類型等相關(guān)信息。所有瀏覽器都支持event對(duì)象,但支持方式不同。

事件對(duì)象必須在一個(gè)事件調(diào)用的函數(shù)里面使用才有內(nèi)容
事件函數(shù):事件調(diào)用的函數(shù),一個(gè)函數(shù)是不是事件函數(shù),不在定義的決定,而是取決于這個(gè)調(diào)用的時(shí)候

兼容

ie/chrome : event是一個(gè)內(nèi)置全局對(duì)象
標(biāo)準(zhǔn)下 : 事件對(duì)象是通過(guò)事件函數(shù)的第一個(gè)參數(shù)傳入

如果一個(gè)函數(shù)是被事件調(diào)用的那么,這個(gè)函數(shù)定義的第一個(gè)參數(shù)就是事件對(duì)象

ie/chrome下

function fn(){
    alert(event);
}

document.onclick = fn;

標(biāo)準(zhǔn)下:

function fn(ev){
    alert(ev);
}
document.onclick = fn;

兼容性寫(xiě)法:

function fn(ev){
    var ev = ev || window.enent;
    alert(ev);
}
document.onclick = fn;

clientX clientY

clientX 事件屬性返回當(dāng)事件被觸發(fā)時(shí)鼠標(biāo)指針向?qū)τ跒g覽器頁(yè)面(或客戶區(qū))的水平坐標(biāo)。
clientY 事件屬性返回當(dāng)事件被觸發(fā)時(shí)鼠標(biāo)指針向?qū)τ跒g覽器頁(yè)面(或客戶區(qū))的垂直坐標(biāo)。

例如,當(dāng)你點(diǎn)擊客戶端區(qū)域的左上角時(shí),鼠標(biāo)事件的 clientX 值為 0 ,這一值與頁(yè)面是否有水平滾動(dòng)無(wú)關(guān)。

document.onclick = function(e){
    var e = e||window.event;
    alert(e.clientX +' '+e.clientY);
}

示例: 方塊跟著鼠標(biāo)移動(dòng)

取消冒泡

標(biāo)準(zhǔn)下:

event.stopPropagation()

ie下:

e.cancelBubble = true;

兼容性寫(xiě)法:

function stopPropagation(e) {
    if (e.stopPropagation)
        e.stopPropagation();
    else
        e.cancelBubble = true;
}

阻止默認(rèn)行為

標(biāo)準(zhǔn)下:
event.preventDefault();

ie下:
event.returnValue = false;

兼容性寫(xiě)法:

function preventDefault(e) {
    if (e.preventDefault)
        e.preventDefault();
    else
        e.returnValue = false;
}

target

Element 只讀 觸發(fā)事件的目標(biāo)元素

function getTarget(e) {
    return e.target || e.srcElement;//ie下為srcElement;
}

dom對(duì)象 事件處理函數(shù)

方法一

綁定事件處理函數(shù)

function fn(){
    alert(1);
}
div.onclick = fn;

缺點(diǎn): 只能綁定一個(gè)處理函數(shù)

function fn1(){
    alert(1);
}

function fn2(){
    alert(1);
}

div.onclick = fn1;
div.onclick = fn2;

div.onclick 屬性中的值會(huì)被覆蓋

移除事件綁定函數(shù)

div.onclick = null;

方法二

DOM2級(jí)事件定義了兩個(gè)方法用于處理指定和刪除事件處理程序的操作:

  1. 綁定事件處理函數(shù): addEventListener
  2. 移除事件綁定函數(shù): removeEventListener

所有的DOM節(jié)點(diǎn)都包含這兩個(gè)方法,并且它們都接受三個(gè)參數(shù):

  1. 事件類型
  2. 事件處理方法
  3. 布爾參數(shù),如果是true表示在捕獲階段調(diào)用事件處理程序,如果是false,則是在事件冒泡階段處理

綁定事件處理函數(shù)

function fn1(){
    alert(1);
}

function fn2(){
    alert(2);
}

oDiv.addEventListener('click', fn1, false);
oDiv.addEventListener('click', fn2, false);

移除事件綁定函數(shù)

function fn1() {
    alert(1);
}
function fn2() {
    alert(2);
}

document.addEventListener('click', fn1, false);
document.addEventListener('click', fn2, false);

document.removeEventListener('click', fn1, false);

IE兼容性

IE并不支持addEventListener和removeEventListener方法,而是實(shí)現(xiàn)了兩個(gè)類似的方法

  1. attachEvent
  2. detachEvent

這兩個(gè)方法都接收兩個(gè)相同的參數(shù)

  1. 事件處理程序名稱
  2. 事件處理程序方法

由于IE只支持事件冒泡,所以添加的程序會(huì)被添加到冒泡階段,使用attachEvent添加事件處理程序可以如下

<input id="btnClick" type="button" value="Click Here" />

<script type="text/javascript">
    var btnClick = document.getElementById('btnClick');
    var handler=function() {
        alert(this.id);
    }
    btnClick.attachEvent('onclick', handler);
</script>

結(jié)果是undefined,很奇怪,一會(huì)兒我們會(huì)介紹到

使用attachEvent添加的事件處理程序可以通過(guò)detachEvent移除,條件也是相同的參數(shù),匿名函數(shù)不能被移除。

<input id="btnClick" type="button" value="Click Here" />

<script type="text/javascript">
    var btnClick = document.getElementById('btnClick');

    var handler=function() {
        alert(this.id);
    }

    btnClick.attachEvent('onclick', handler);
    btnClick.detachEvent('onclick', handler);
</script>

跨瀏覽器的事件處理程序

前面內(nèi)容我們可以看到,在不同的瀏覽器下,添加和移除事件處理程序方式不相同,要想寫(xiě)出跨瀏覽器的事件處理程序,首先我們要了解不同的瀏覽器下處理事件處理程序的區(qū)別

在添加事件處理程序事addEventListener和attachEvent主要有幾個(gè)區(qū)別

  1. 參數(shù)個(gè)數(shù)不相同

這個(gè)最直觀,addEventListener有三個(gè)參數(shù),attachEvent只有兩個(gè),attachEvent添加的事件處理程序只能發(fā)生在冒泡階段,addEventListener第三個(gè)參數(shù)可以決定添加的事件處理程序是在捕獲階段還是冒泡階段處理(我們一般為了瀏覽器兼容性都設(shè)置為冒泡階段)

  1. 事件名稱不相同

addEventListener下事件名稱沒(méi)有on,比如說(shuō)click,mouseover, attachEvent下有on,比如說(shuō)onclick
onmousevoer

  1. 事件函數(shù)觸發(fā)時(shí), this的指向不相同

addEventListener的作用域是元素本身,this是指的觸發(fā)元素,而attachEvent事件處理程序會(huì)在全局變量?jī)?nèi)運(yùn)行,this是window,所以剛才例子才會(huì)返回undefined,而不是元素id

  1. 為一個(gè)事件添加多個(gè)事件處理程序時(shí),執(zhí)行順序不同,

addEventListener添加會(huì)按照添加順序執(zhí)行,而attachEvent添加多個(gè)事件處理程序時(shí)順序無(wú)規(guī)律(添加的方法少的時(shí)候大多是按添加順序的反順序執(zhí)行的,但是添加的多了就無(wú)規(guī)律了),所以添加多個(gè)的時(shí)候,不依賴執(zhí)行順序的還好,若是依賴于函數(shù)執(zhí)行順序,最好自己處理,不要指望瀏覽器

了解了這四點(diǎn)區(qū)別后我們可以嘗試寫(xiě)一個(gè)瀏覽器兼容性比較好的添加事件處理程序方法

function addEvent(node, type, handler) {
    if (!node) return false;
    if (node.addEventListener) {
        node.addEventListener(type, handler, false);
        return true;
    }
    else if (node.attachEvent) {
        node.attachEvent('on' + type, handler, );
        return true;
    }
    return false;
}

這樣,首先我們解決了第一個(gè)問(wèn)題參數(shù)個(gè)數(shù)不同,現(xiàn)在三個(gè)參數(shù),采用事件冒泡階段觸發(fā)

第二個(gè)問(wèn)題也得以解決,如果是IE,我們給type添加上on

第四個(gè)問(wèn)題目前還沒(méi)有解決方案,需要用戶自己注意,一般情況下,大家也不會(huì)添加很多事件處理程序

試試這個(gè)方法感覺(jué)很不錯(cuò),但是我們沒(méi)有解決第三個(gè)問(wèn)題,由于處理程序作用域不同,如果handler內(nèi)有this之類操作,那么就會(huì)出錯(cuò)。在IE下,實(shí)際上大多數(shù)函數(shù)都會(huì)有this操作

function addEvent(node, type, handler) {
    if (!node) return false;
    if (node.addEventListener) {
        node.addEventListener(type, handler, false);
        return true;
    }
    else if (node.attachEvent) {
        node.attachEvent('on' + type, function() { handler.call(node); });
        return true;
    }
    return false;
}

這樣處理就可以解決this的問(wèn)題了,但是新的問(wèn)題又來(lái)了,我們這樣等于添加了一個(gè)匿名的事件處理程序,無(wú)法用detachEvent取消事件處理程序,有很多解決方案,我們可以借鑒大師的處理方式,jQuery創(chuàng)始人John Resig是這樣做的

function addEvent(node, type, handler) {
    if (!node) return false;
    if (node.addEventListener) {
        node.addEventListener(type, handler, false);
        return true;
    }
    else if (node.attachEvent) {
        node['e' + type + handler] = handler;
        node[type + handler] = function() {
            node['e' + type + handler](window.event);
        };
        node.attachEvent('on' + type, node[type + handler]);
        return true;
    }
    return false;
}

在取消事件處理程序的時(shí)候

function removeEvent(node, type, handler) {
    if (!node) return false;
    if (node.removeEventListener) {
        node.removeEventListener(type, handler, false);
        return true;
    }
    else if (node.detachEvent) {
        node.detachEvent('on' + type, node[type + handler]);
        node[type + handler] = null;
    }
    return false;
}

事件的捕獲

事件流包括三個(gè)階段,事件捕獲階段,處于目標(biāo)階段,事件冒泡階段,首先發(fā)生的是事件捕獲,為截取事件提供機(jī)會(huì),然后是實(shí)際目標(biāo)接收事件,最后是冒泡階段

<style>

div {padding: 50px;}
#div1 {background: red;}
#div2 {background: blue;}
#div3 {background: green;}

</style>

<div id="div1">
    <div id="div2">
        <div id="div3"></div>
    </div>
</div>

<script>
var oDiv1 = document.getElementById('div1');
var oDiv2 = document.getElementById('div2');
var oDiv3 = document.getElementById('div3');

function fn1() {
    alert( this.id );
}

oDiv1.addEventListener('click', fn1, true);
oDiv2.addEventListener('click', fn1, true);
oDiv3.addEventListener('click', fn1, true);
</script>

鍵盤(pán)事件

onkeydown : 當(dāng)鍵盤(pán)按鍵按下的時(shí)候觸發(fā)
onkeyup : 當(dāng)鍵盤(pán)按鍵抬起的時(shí)候觸發(fā)

document.onkeydown = function(ev) {

    var ev = ev || event;
    alert(ev.keyCode);
    
}

與鍵盤(pán)事件相關(guān)的事件對(duì)象的屬性值

  • event.keyCode : 數(shù)字類型 鍵盤(pán)按鍵的值 鍵值
  • event.ctrlKey, event.shiftKey, event.altKey

這三個(gè)鍵 我們通常稱為功能鍵

當(dāng)一個(gè)事件發(fā)生的時(shí)候,如果ctrl || shift || alt 是按下的狀態(tài),相應(yīng)的屬性值返回true,否則返回false

document.onclick = function(ev) {
    var ev = ev || event;
    
    alert(ev.ctrlKey);
}

當(dāng)我們點(diǎn)擊時(shí),如果是按住ctrl鍵則彈出true;

示例: 留言板

當(dāng)輸入完成, 并且按住ctrl+enter(回車),添加留言

<input type="text" id="text1" />
<ul id="ul1"></ul>
var oText = document.getElementById('text1');
var oUl = document.getElementById('ul1');

oText.onkeyup = function(ev) {
    
    var ev = ev || event;
    
    //alert(this.value);
    if ( this.value != '' ) {
        
        //不能寫(xiě)成ev.keyCode == 13 && ev.keyCode == 17;
        //應(yīng)為ev.keyCode不可能同時(shí)為13 和17
        if (ev.keyCode == 13 && ev.ctrlKey) {
        
            var oLi = document.createElement('li');
            oLi.innerHTML = this.value;
            
            if ( oUl.children[0] ) {
                oUl.insertBefore( oLi, oUl.children[0] );
            } else {
                oUl.appendChild( oLi );
            }
            
        }
        
    }
    
}

不是所有元素都能夠接收鍵盤(pán)事件,能夠響應(yīng)用戶輸入的元素,能夠接收焦點(diǎn)的元素就能夠接收鍵盤(pán)事件

onkeydown : 如果按下不抬起,那么會(huì)連續(xù)觸發(fā)

示例: 移動(dòng)div

oncontextmenu

右鍵菜單事件,當(dāng)右鍵菜單(環(huán)境菜單)顯示出來(lái)的時(shí)候觸發(fā)

document.oncontextmenu = function(){
    alert(1);
    return false;//阻止默認(rèn)行為
}

例子 彈出自定義右鍵菜單

var oDiv = document.getElementById('div1');
    
document.oncontextmenu = function(ev) {
    var ev = ev || event;
    
    oDiv.style.display = 'block';
    
    oDiv.style.left = ev.clientX + 'px';
    oDiv.style.top = ev.clientY + 'px';
    
    return false;
    
}

document.onclick = function() {
    oDiv.style.display = 'none';
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • JavaScript 程序采用了異步事件驅(qū)動(dòng)編程模型。在這種程序設(shè)計(jì)風(fēng)格下,當(dāng)文檔、瀏覽器、元素或與之相關(guān)的對(duì)象發(fā)...
    劼哥stone閱讀 1,330評(píng)論 3 11
  • 以下文章為轉(zhuǎn)載,對(duì)理解JavaScript中的事件處理機(jī)制很有幫助,淺顯易懂,特分享于此。 什么是事件? 事件(E...
    jxyjxy閱讀 3,165評(píng)論 1 10
  • 聲明:本文來(lái)源于http://www.webzsky.com/?p=731我只是在這里作為自己的學(xué)習(xí)筆記整理一下(...
    angryyan閱讀 7,239評(píng)論 1 6
  • 如何批量操作 css 如何獲取 DOM 計(jì)算后的樣式 使用getComputedStyle獲取元素計(jì)算后的樣式 實(shí)...
    _Dot912閱讀 661評(píng)論 1 3
  • 事件 JavaScript和HTML的交互是通過(guò)事件實(shí)現(xiàn)的。JavaScript采用異步事件驅(qū)動(dòng)編程模型,當(dāng)文檔、...
    徐國(guó)軍_plus閱讀 669評(píng)論 0 2

友情鏈接更多精彩內(nèi)容