成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript 事件詳解

Object / 2837人閱讀

摘要:事件監(jiān)聽函數(shù)標(biāo)準(zhǔn)的事件監(jiān)聽函數(shù)如下上面的示例表示先獲得表示節(jié)點(diǎn)的對(duì)象,然后在這個(gè)對(duì)象上面添加了一個(gè)事件監(jiān)聽器,當(dāng)監(jiān)聽到事件發(fā)生時(shí),則調(diào)用回調(diào)函數(shù),即在控制臺(tái)輸出。

JavaScript 事件解讀 1. 事件基本概念

事件是指在文檔或者瀏覽器中發(fā)生的一些特定交互瞬間,比如打開某一個(gè)網(wǎng)頁(yè),瀏覽器加載完成后會(huì)觸發(fā) load 事件,當(dāng)鼠標(biāo)懸浮于某一個(gè)元素上時(shí)會(huì)觸發(fā) hover 事件,當(dāng)鼠標(biāo)點(diǎn)擊某一個(gè)元素時(shí)會(huì)觸發(fā) click 事件等等。

事件處理就是當(dāng)事件被觸發(fā)后,瀏覽器響應(yīng)這個(gè)事件的行為,而這個(gè)行為所對(duì)應(yīng)的代碼即為事件處理程序。

2. 事件操作:監(jiān)聽與移除監(jiān)聽 2.1 監(jiān)聽事件

瀏覽器會(huì)根據(jù)一些事件作出相對(duì)應(yīng)的事件處理,事件處理的前提是需要監(jiān)聽事件,監(jiān)聽事件的方法主要有以下三種:

2.1.1 HTML 內(nèi)聯(lián)屬性

即在 HTML 元素里直接填寫與事件相關(guān)的屬性,屬性值為事件處理程序。示例如下:


onclick 對(duì)應(yīng)著 click 事件,所以當(dāng)按鈕被點(diǎn)擊后,便會(huì)執(zhí)行事件處理程序,即控制臺(tái)輸出 You clicked me!。

不過(guò)我們需要指出的是,這種方式將 HTML 代碼與 JavaScript 代碼耦合在一起,不利于代碼的維護(hù),所以應(yīng)該盡量避免使用這樣的方式。

2.1.2 DOM 屬性綁定

通過(guò)直接設(shè)置某個(gè) DOM 節(jié)點(diǎn)的屬性來(lái)指定事件和事件處理程序,上代碼:

const btn = document.getElementById("btn");
btn.onclick = function(e) {
    console.log("You clicked me!");
};

上面示例中,首先獲得 btn 這個(gè)對(duì)象,通過(guò)給這個(gè)對(duì)象添加 onclick 屬性的方式來(lái)監(jiān)聽 click 事件,這個(gè)屬性值對(duì)應(yīng)的就是事件處理程序。這段程序也被稱作 DOM 0 級(jí)事件處理程序。

2.1.3 事件監(jiān)聽函數(shù)

標(biāo)準(zhǔn)的事件監(jiān)聽函數(shù)如下:

const btn = document.getElementById("btn");
btn.addEventListener("click", () => {
    console.log("You clicked me!");
}, false);

上面的示例表示先獲得表示節(jié)點(diǎn)的 btn 對(duì)象,然后在這個(gè)對(duì)象上面添加了一個(gè)事件監(jiān)聽器,當(dāng)監(jiān)聽到 click 事件發(fā)生時(shí),則調(diào)用回調(diào)函數(shù),即在控制臺(tái)輸出 You clicked me!。addEventListener 函數(shù)包含了三個(gè)參數(shù) false,第三個(gè)參數(shù)的含義在后面的事件觸發(fā)三個(gè)階段之后再講解。這段程序也被稱作 DOM 2 級(jí)事件處理程序。IE9+、FireFox、Safari、Chrome 和 Opera 都是支持 DOM 2 級(jí)事件處理程序的,對(duì)于 IE8 及以下版本,則用 attacEvent() 函數(shù)綁定事件。

所以我們可以寫一段具有兼容性的代碼:

function addEventHandler(obj, eventName, handler) {
    if (document.addEventListener) {
        obj.addEventListener(eventName, handler, false);
    }
    else if (document.attachEvent) {
        obj.attachEvent("on" + eventName, handler);
    }    
    else {
        obj["on" + eventName] = handler;
    }
}
2.2 移除事件監(jiān)聽

在為某個(gè)元素綁定了一個(gè)事件后,如果想接觸綁定,則需要用到 removeEventListener 方法??慈缦吕樱?/p>

const handler = function() {
    // handler logic
}
const btn = document.getElementById("btn");

btn.addEventListener("click", handler);
btn.removeEventListener("click", handler);

需要注意的是,綁定事件的回調(diào)函數(shù)不能是匿名函數(shù),必須是一個(gè)已經(jīng)被聲明的函數(shù),因?yàn)榻獬录壎〞r(shí)需要傳遞這個(gè)回調(diào)函數(shù)的引用。

同樣,IE8 及以下版本也不支持上面的方法,而是用 detachEvent 代替。

const handler = function() {
    // handler logic
}
const btn = document.getElementById("btn");

btn.attachEvent("onclick", handler);
btn.detachEvent("onclick", handler);

同樣,可以寫一段具有兼容性的刪除事件函數(shù):

function removeEventHandler(obj, eventName, handler) {
    if (document.removeEventListener) {
        obj.removeEventListener(eventName, handler, false);
    }
    else if (document.detachEvent) {
        obj,detachEvent("on" + eventName, handler);
    }
    else {
        obj["on" + eventName] = null;
    }
}

3. 事件觸發(fā)過(guò)程

事件流描述了頁(yè)面接收事件的順序?,F(xiàn)代瀏覽器(指 IE6-IE8 除外的瀏覽器,包括 IE9+、FireFox、Safari、Chrome 和 Opera 等)事件流包含三個(gè)過(guò)程,分別是捕獲階段、目標(biāo)階段和冒泡階段,下圖形象地說(shuō)明這個(gè)過(guò)程:

下面就詳細(xì)地講解這三個(gè)過(guò)程。

3.1 捕獲階段

當(dāng)我們對(duì) DOM 元素進(jìn)行操作時(shí),比如鼠標(biāo)點(diǎn)擊、懸浮等,就會(huì)有一個(gè)事件傳輸?shù)竭@個(gè) DOM 元素,這個(gè)事件從 Window 開始,依次經(jīng)過(guò) docuemnt、html、body,再不斷經(jīng)過(guò)子節(jié)點(diǎn)直到到達(dá)目標(biāo)元素,從 Window 到達(dá)目標(biāo)元素父節(jié)點(diǎn)的過(guò)程稱為捕獲階段,注意此時(shí)還未到達(dá)目標(biāo)節(jié)點(diǎn)。

3.2 目標(biāo)階段

捕獲階段結(jié)束時(shí),事件到達(dá)了目標(biāo)節(jié)點(diǎn)的父節(jié)點(diǎn),最終到達(dá)目標(biāo)節(jié)點(diǎn),并在目標(biāo)節(jié)點(diǎn)上觸發(fā)了這個(gè)事件,這就是目標(biāo)階段。

需要注意的是,事件觸發(fā)的目標(biāo)節(jié)點(diǎn)為最底層的節(jié)點(diǎn)。比如下面的例子:

你猜,目標(biāo)在這里還是那里。

當(dāng)我們點(diǎn)擊“那里”的時(shí)候,目標(biāo)節(jié)點(diǎn)是,點(diǎn)擊“這里”的時(shí)候,目標(biāo)節(jié)點(diǎn)是

,而當(dāng)我們點(diǎn)擊

區(qū)域之外,
區(qū)域之內(nèi)時(shí),目標(biāo)節(jié)點(diǎn)就是

3.3 冒泡階段

當(dāng)事件到達(dá)目標(biāo)節(jié)點(diǎn)之后,就會(huì)沿著原路返回,這個(gè)過(guò)程有點(diǎn)類似水泡從水底浮出水面的過(guò)程,所以稱這個(gè)過(guò)程為冒泡階段。

針對(duì)這個(gè)過(guò)程,wilsonpage 做了一個(gè) DEMO,可以非常直觀地查看這個(gè)過(guò)程。

現(xiàn)在再看 addEventListener(eventName, handler, useCapture) 函數(shù)。第三個(gè)參數(shù)是 useCapture,代表是否在捕獲階段進(jìn)行事件處理, 如果是 false, 則在冒泡階段進(jìn)行事件處理,如果是 true,在捕獲階段進(jìn)行事件處理,默認(rèn)是 false。這么設(shè)計(jì)的主要原因是當(dāng)年微軟和 netscape 之間的瀏覽器戰(zhàn)爭(zhēng)打得火熱,netscape 主張捕獲方式,微軟主張冒泡方式,W3C 采用了折中的方式,即先捕獲再冒泡。

4、事件委托

上面我們講了事件的冒泡機(jī)制,我們可以利用這一特性來(lái)提高頁(yè)面性能,事件委托便事件冒泡是最典型的應(yīng)用之一。

何謂“委托”?在現(xiàn)實(shí)中,當(dāng)我們不想做某件事時(shí),便“委托”給他人,讓他人代為完成。JavaScript 中,事件的委托表示給元素的父級(jí)或者祖級(jí),甚至頁(yè)面,由他們來(lái)綁定事件,然后利用事件冒泡的基本原理,通過(guò)事件目標(biāo)對(duì)象進(jìn)行檢測(cè),然后執(zhí)行相關(guān)操作??聪旅胬樱?/p>

// HTML
  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5
// JavaScript var list = document.getElementById("list"); list.addEventListener("click", function(e) { console.log(e.target); });

上面的例子中,5 個(gè)列表項(xiàng)的點(diǎn)擊事件均委托給了父元素

    。

    先看看事件委托的可行性。有人會(huì)問(wèn),當(dāng)事件不是加在某個(gè)元素上的,如何在這個(gè)元素上觸發(fā)事件呢?我們就是利用事件冒泡的機(jī)制,事件流到達(dá)目標(biāo)元素后會(huì)向上冒泡,此時(shí)父元素接收到事件流便會(huì)執(zhí)行事件執(zhí)行程序。有人又會(huì)問(wèn),被委托的父元素下面如果有很多子元素,怎么知道事件流來(lái)自于哪個(gè)子元素呢?這個(gè)我們可以從事件對(duì)象中的 target 屬性獲得。事件對(duì)象下面會(huì)詳細(xì)講解。

    我們?cè)賮?lái)看看為什么需要事件委托。

    減少事件綁定。上面的例子中,也可以分別給每個(gè)列表項(xiàng)綁定事件,但利用事件委托的方式不僅省去了一一綁定的麻煩,也提升了網(wǎng)頁(yè)的性能,因?yàn)槊拷壎ㄒ粋€(gè)事件便會(huì)增加內(nèi)存使用。

    可以動(dòng)態(tài)監(jiān)聽綁定。上面的例子中,我們對(duì) 5 個(gè)列表項(xiàng)進(jìn)行了事件監(jiān)聽,當(dāng)刪除一個(gè)列表項(xiàng)時(shí)不需要多帶帶刪除這個(gè)列表項(xiàng)所綁定的事件,而增加一個(gè)列表項(xiàng)時(shí)也不需要多帶帶為新增項(xiàng)綁定事件。

    看了上面的例子和解釋,我們可以看出事件委托的核心就是監(jiān)聽一個(gè) DOM 中更高層、更不具體的元素,等到事件冒泡到這個(gè)不具體元素時(shí),通過(guò) event 對(duì)象的 target 屬性來(lái)獲取觸發(fā)事件的具體元素。

    5、阻止事件冒泡

    事件委托是事件冒泡的一個(gè)應(yīng)用,但有時(shí)候我們并不希望事件冒泡。比如下面的例子:

    const ele = document.getElementById("ele");
    ele.addEventListener("click", function() {
        console.log("ele-click");
    }, false);
    
    document.addEventListener("click", function() {
        console.log("document-click");
    }, false);
    

    我們本意是當(dāng)點(diǎn)擊 ele 元素區(qū)域時(shí)顯示 "ele-click",點(diǎn)擊其他區(qū)域時(shí)顯示 "document-click"。但是我們發(fā)現(xiàn)點(diǎn)擊 ele 元素區(qū)域時(shí)會(huì)依次顯示 "ele-click" "document-click"。那是因?yàn)榻壎ㄔ?ele 上的事件冒泡到了 document 上。想要解決這個(gè)問(wèn)題,只需要加一行代碼:

    const ele = document.getElementById("ele");
    ele.addEventListener("click", function(e) {
        console.log("ele-click");
        e.stopPropagation(); // 阻止事件冒泡
    }, false);
    
    document.addEventListener("click", function(e) {
        console.log("document-click");
    }, false);
    

    我們還能用 e.cancelBubble = true 來(lái)替代 e.stopPropagation()。網(wǎng)上的說(shuō)法是 cancelBubble 僅僅適用于 IE,而 stopPropagation 適用于其他瀏覽器。但根據(jù)我實(shí)驗(yàn)的結(jié)果,現(xiàn)代瀏覽器(IE9 及 以上、Chrome、FF 等)均同時(shí)支持這兩種寫法。為了保險(xiǎn)起見,我們可以采用以下代碼:

    function preventBubble(e) {
        if (!e) {
            const e = window.event;
        }
        e.cancelBubble = true;
        if (e.stopPropagation) {
            e.stopPropagation();
        }
    }
    
    6、event 對(duì)象

    Event 對(duì)象代表事件的狀態(tài),比如事件在其中發(fā)生的元素、鍵盤按鍵的狀態(tài)、鼠標(biāo)的位置、鼠標(biāo)按鈕的狀態(tài)。當(dāng)一個(gè)事件被觸發(fā)的時(shí)候,就會(huì)創(chuàng)建一個(gè)事件對(duì)象。

    我們用下面的代碼打印出事件對(duì)象:

  • Item 1
  • Item 2
  • chrome 49 的運(yùn)行結(jié)果如下:

    下面介紹一些比較常用的屬性和方法。

    target、 srcElement、 currentTarget 和 relatedTarget、fromElement、 toElement

    target 與 srcElement 完全相同;

    target 指觸發(fā)事件的元素, currentTarget 指事件所綁定的元素;

    relatedTarget: 與事件的目標(biāo)節(jié)點(diǎn)相關(guān)的節(jié)點(diǎn)。對(duì)于 mouseover 事件來(lái)說(shuō),該屬性是鼠標(biāo)指針移到目標(biāo)節(jié)點(diǎn)上時(shí)所離開的那個(gè)節(jié)點(diǎn)。對(duì)于 mouseout 事件來(lái)說(shuō),該屬性是離開目標(biāo)時(shí),鼠標(biāo)指針進(jìn)入的節(jié)點(diǎn)。
    對(duì)于其他類型的事件來(lái)說(shuō),這個(gè)屬性沒(méi)有用;

    fromElement 和 toElement 僅僅對(duì)于 mouseover 和 mouseout 事件有效。

    以上面的例子說(shuō)明,當(dāng)點(diǎn)擊

  • Item 1
  • 時(shí),target 就是
  • Item 1
  • 元素,而 currentTarget 是

    clientX/Y、 screenX/Y、 pageX/Y、 offsetX/Y

    上圖:

    offsetX/Y: 點(diǎn)擊位置相對(duì)于所處元素左上角的位置;

    clientX/Y: 點(diǎn)擊位置相對(duì)于瀏覽器內(nèi)容區(qū)域左上角的位置;

    screenX/Y: 點(diǎn)擊位置相對(duì)于屏幕左上角的位置;

    pageX/Y: 點(diǎn)擊位置相對(duì)整張頁(yè)面左上角的位置;

    pageX/Y 與 clientX/Y 一般情況下會(huì)相同,只有出現(xiàn)滾動(dòng)條時(shí)才不一樣。

    altKey、 ctrlKey、 shiftKey

    altKey: 返回當(dāng)事件被觸發(fā)時(shí),"ALT" 是否被按下;

    ctrlKey: 返回當(dāng)事件被觸發(fā)時(shí),"CTRL" 鍵是否被按下;

    shiftKey: 返回當(dāng)事件被觸發(fā)時(shí),"SHIFT" 鍵是否被按下;

    其他屬性

    type: 返回當(dāng)前 Event 對(duì)象表示的事件的名稱

    bubbles: 返回布爾值,指示事件是否是起泡事件類型;

    cancelable: 返回布爾值,指示事件是否可擁可取消的默認(rèn)動(dòng)作;

    eventPhase: 返回事件傳播的當(dāng)前階段,有三個(gè)值: Event.CAPTURING_PHASE、 Event.AT_TARGET、 Event.BUBBLING_PHASE,對(duì)應(yīng)的值為 1、2、3,分別表示捕獲階段、正常事件派發(fā)和起泡階段;

    path: 冒泡階段經(jīng)過(guò)的節(jié)點(diǎn);

    方法

    preventDefault(): 通知瀏覽器不要執(zhí)行與事件關(guān)聯(lián)的默認(rèn)動(dòng)作;

    stopPropagation(): 阻止冒泡;

    參考及拓展閱讀:

    HTML DOM Event 對(duì)象

    最詳細(xì)的JavaScript和事件解讀

    JavaScript Events

    [解惑]JavaScript事件機(jī)制

    文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/79308.html

    相關(guān)文章

    • 【連載】前端個(gè)人文章整理-從基礎(chǔ)到入門

      摘要:個(gè)人前端文章整理從最開始萌生寫文章的想法,到著手開始寫,再到現(xiàn)在已經(jīng)一年的時(shí)間了,由于工作比較忙,更新緩慢,后面還是會(huì)繼更新,現(xiàn)將已經(jīng)寫好的文章整理一個(gè)目錄,方便更多的小伙伴去學(xué)習(xí)。 showImg(https://segmentfault.com/img/remote/1460000017490740?w=1920&h=1080); 個(gè)人前端文章整理 從最開始萌生寫文章的想法,到著手...

      madthumb 評(píng)論0 收藏0
    • JavaScript Event Loop 機(jī)制詳解與 Vue.js 中實(shí)踐應(yīng)用

      摘要:機(jī)制詳解與中實(shí)踐應(yīng)用歸納于筆者的現(xiàn)代開發(fā)語(yǔ)法基礎(chǔ)與實(shí)踐技巧系列文章。事件循環(huán)機(jī)制詳解與實(shí)踐應(yīng)用是典型的單線程單并發(fā)語(yǔ)言,即表示在同一時(shí)間片內(nèi)其只能執(zhí)行單個(gè)任務(wù)或者部分代碼片。 JavaScript Event Loop 機(jī)制詳解與 Vue.js 中實(shí)踐應(yīng)用歸納于筆者的現(xiàn)代 JavaScript 開發(fā):語(yǔ)法基礎(chǔ)與實(shí)踐技巧系列文章。本文依次介紹了函數(shù)調(diào)用棧、MacroTask 與 Micr...

      livem 評(píng)論0 收藏0
    • JavaScript學(xué)習(xí)總結(jié)(九)事件詳解

      摘要:布爾值表示捕獲階段調(diào)用事件處理程序,表示冒泡階段通過(guò)對(duì)象的方法,也可以定義事件的回調(diào)函數(shù)。對(duì)象會(huì)被作為第一個(gè)參數(shù)傳遞給事件監(jiān)聽的回調(diào)函數(shù)。布爾默認(rèn)值是,當(dāng)設(shè)置成時(shí)用以取消事件的默認(rèn)行為與中的相同。 其實(shí)這篇文章挺早之前就寫了,但是由于sf保存方面的bug,所以當(dāng)時(shí)寫了一大堆,結(jié)果沒(méi)保存,覺得這個(gè)沒(méi)寫完是個(gè)不小的遺憾,今天正好有空,就給補(bǔ)充下了,也正好給我的javascript學(xué)習(xí)總結(jié)做...

      LiveVideoStack 評(píng)論0 收藏0
    • JavaScript系列之事件詳解

      摘要:響應(yīng)某個(gè)事件的函數(shù)就叫事件處理程序或事件偵聽器。為事件指定事件處理程序的方法主要有種。事件處理程序事件直接加在元素上。事件委托利用冒泡的原理,把事件加到父元素或祖先元素上,觸發(fā)執(zhí)行效果,解決事件處理程序過(guò)多問(wèn)題。事件委托優(yōu)點(diǎn)提高性能。 JavaScript簡(jiǎn)單入門可以看看我丑丑的Github博客JavaScript簡(jiǎn)單入門 事件 JavaScript與HTML之間的交互是通過(guò)事件實(shí)現(xiàn)的...

      pakolagij 評(píng)論0 收藏0
    • JavaScript 運(yùn)行機(jī)制詳解(理解同步、異步和事件循環(huán))

      摘要:從異步過(guò)程的角度看,函數(shù)就是異步過(guò)程的發(fā)起函數(shù),事件監(jiān)聽函數(shù)就是異步過(guò)程的回調(diào)函數(shù)。事件觸發(fā)時(shí),表示異步任務(wù)完成,會(huì)將事件監(jiān)聽器函數(shù)封裝成一條消息放到消息隊(duì)列中,等待主線程執(zhí)行。 1.為什么JavaScript是單線程? JavaScript語(yǔ)言的一大特點(diǎn)就是單線程,也就是說(shuō),同一個(gè)時(shí)間只能做一件事。那么,為什么JavaScript不能有多個(gè)線程呢?這樣能提高效率啊。JavaScrip...

      loonggg 評(píng)論0 收藏0

    發(fā)表評(píng)論

    0條評(píng)論

    Object

    |高級(jí)講師

    TA的文章

    閱讀更多
    最新活動(dòng)
    閱讀需要支付1元查看
    <