>>>>> 事件

事件冒泡

事件冒泡 : 當一個元素接收到事件的時候,會把他接收到的所有傳播給他的父級,一直到頂層window.事件冒泡機制

<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>

點擊div3, div3 div2 div1上的點擊事件都會被觸發

事件冒泡與樣式無關,與html結構相關

事件對象

在觸發DOM上的某個事件的時候會產生一個事件對象event,這個對象包含著所有與事件有關的信息,包括產生事件的元素、事件類型等相關信息。所有瀏覽器都支持event對象,但支持方式不同。

事件對象必須在一個事件調用的函數里面使用才有內容
事件函數:事件調用的函數,一個函數是不是事件函數,不在定義的決定,而是取決于這個調用的時候

兼容

ie/chrome : event是一個內置全局對象
標準下 : 事件對象是通過事件函數的第一個參數傳入

如果一個函數是被事件調用的那么,這個函數定義的第一個參數就是事件對象

ie/chrome下

function fn(){
    alert(event);
}

document.onclick = fn;

標準下:

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

兼容性寫法:

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

clientX clientY

clientX 事件屬性返回當事件被觸發時鼠標指針向對于瀏覽器頁面(或客戶區)的水平坐標。
clientY 事件屬性返回當事件被觸發時鼠標指針向對于瀏覽器頁面(或客戶區)的垂直坐標。

例如,當你點擊客戶端區域的左上角時,鼠標事件的 clientX 值為 0 ,這一值與頁面是否有水平滾動無關。

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

示例: 方塊跟著鼠標移動

取消冒泡

標準下:

event.stopPropagation()

ie下:

e.cancelBubble = true;

兼容性寫法:

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

阻止默認行為

標準下:
event.preventDefault();

ie下:
event.returnValue = false;

兼容性寫法:

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

target

Element 只讀 觸發事件的目標元素

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

dom對象 事件處理函數

方法一

綁定事件處理函數

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

缺點: 只能綁定一個處理函數

function fn1(){
    alert(1);
}

function fn2(){
    alert(1);
}

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

div.onclick 屬性中的值會被覆蓋

移除事件綁定函數

div.onclick = null;

方法二

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

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

所有的DOM節點都包含這兩個方法,并且它們都接受三個參數:

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

綁定事件處理函數

function fn1(){
    alert(1);
}

function fn2(){
    alert(2);
}

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

移除事件綁定函數

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方法,而是實現了兩個類似的方法

  1. attachEvent
  2. detachEvent

這兩個方法都接收兩個相同的參數

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

由于IE只支持事件冒泡,所以添加的程序會被添加到冒泡階段,使用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>

結果是undefined,很奇怪,一會兒我們會介紹到

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

<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>

跨瀏覽器的事件處理程序

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

在添加事件處理程序事addEventListener和attachEvent主要有幾個區別

  1. 參數個數不相同

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

  1. 事件名稱不相同

addEventListener下事件名稱沒有on,比如說click,mouseover, attachEvent下有on,比如說onclick
onmousevoer

  1. 事件函數觸發時, this的指向不相同

addEventListener的作用域是元素本身,this是指的觸發元素,而attachEvent事件處理程序會在全局變量內運行,this是window,所以剛才例子才會返回undefined,而不是元素id

  1. 為一個事件添加多個事件處理程序時,執行順序不同,

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

了解了這四點區別后我們可以嘗試寫一個瀏覽器兼容性比較好的添加事件處理程序方法

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;
}

這樣,首先我們解決了第一個問題參數個數不同,現在三個參數,采用事件冒泡階段觸發

第二個問題也得以解決,如果是IE,我們給type添加上on

第四個問題目前還沒有解決方案,需要用戶自己注意,一般情況下,大家也不會添加很多事件處理程序

試試這個方法感覺很不錯,但是我們沒有解決第三個問題,由于處理程序作用域不同,如果handler內有this之類操作,那么就會出錯。在IE下,實際上大多數函數都會有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的問題了,但是新的問題又來了,我們這樣等于添加了一個匿名的事件處理程序,無法用detachEvent取消事件處理程序,有很多解決方案,我們可以借鑒大師的處理方式,jQuery創始人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;
}

在取消事件處理程序的時候

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;
}

事件的捕獲

事件流包括三個階段,事件捕獲階段,處于目標階段,事件冒泡階段,首先發生的是事件捕獲,為截取事件提供機會,然后是實際目標接收事件,最后是冒泡階段

<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>

鍵盤事件

onkeydown : 當鍵盤按鍵按下的時候觸發
onkeyup : 當鍵盤按鍵抬起的時候觸發

document.onkeydown = function(ev) {

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

與鍵盤事件相關的事件對象的屬性值

  • event.keyCode : 數字類型 鍵盤按鍵的值 鍵值
  • event.ctrlKey, event.shiftKey, event.altKey

這三個鍵 我們通常稱為功能鍵

當一個事件發生的時候,如果ctrl || shift || alt 是按下的狀態,相應的屬性值返回true,否則返回false

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

當我們點擊時,如果是按住ctrl鍵則彈出true;

示例: 留言板

當輸入完成, 并且按住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 != '' ) {
        
        //不能寫成ev.keyCode == 13 && ev.keyCode == 17;
        //應為ev.keyCode不可能同時為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 );
            }
            
        }
        
    }
    
}

不是所有元素都能夠接收鍵盤事件,能夠響應用戶輸入的元素,能夠接收焦點的元素就能夠接收鍵盤事件

onkeydown : 如果按下不抬起,那么會連續觸發

示例: 移動div

oncontextmenu

右鍵菜單事件,當右鍵菜單(環境菜單)顯示出來的時候觸發

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

例子 彈出自定義右鍵菜單

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';
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • JavaScript 程序采用了異步事件驅動編程模型。在這種程序設計風格下,當文檔、瀏覽器、元素或與之相關的對象發...
    劼哥stone閱讀 1,272評論 3 11
  • 以下文章為轉載,對理解JavaScript中的事件處理機制很有幫助,淺顯易懂,特分享于此。 什么是事件? 事件(E...
    jxyjxy閱讀 3,057評論 1 10
  • 聲明:本文來源于http://www.webzsky.com/?p=731我只是在這里作為自己的學習筆記整理一下(...
    angryyan閱讀 7,071評論 1 6
  • 如何批量操作 css 如何獲取 DOM 計算后的樣式 使用getComputedStyle獲取元素計算后的樣式 實...
    _Dot912閱讀 575評論 1 3
  • 事件 JavaScript和HTML的交互是通過事件實現的。JavaScript采用異步事件驅動編程模型,當文檔、...
    徐國軍_plus閱讀 595評論 0 2