1. 程式人生 > >JavaScript 瀏覽器事件解析

JavaScript 瀏覽器事件解析

JavaScript、瀏覽器、事件之間的關係

JavaScript 程式採用了非同步事件驅動程式設計(Event-driven programming)模型,維基百科對它的解釋是:

事件驅動程式設計(英語:Event-driven programming)是一種電腦程式設計模型。這種模型的程式執行流程是由使用者的動作(如滑鼠的按鍵,鍵盤的按鍵動作)或者是由其他程式的訊息來決定的。相對於批處理程式設計(batch programming)而言,程式執行的流程是由程式設計師來決定。批量的程式設計在初級程式設計教學課程上是一種方式。然而,事件驅動程式設計這種設計模型是在互動程式(Interactive program)的情況下孕育而生的

簡頁言之,在 web 前端程式設計裡面 JavaScript 通過瀏覽器提供的事件模型 API 和使用者互動,接收使用者的輸入

由於使用者的行為是不確定的,也就是說不知道使用者什麼時候發生點選、滾動這些動作。這種場景是傳統的同步程式設計模型沒法解決的,因為你不可能等使用者操作完了才執行後面的程式碼

比如我們在 Python 裡面呼叫接收使用者輸入的方法 raw_input() 後終端就會一直等待使用者的輸入,直到輸入完成才會執行後面的程式碼邏輯。但是在下面這段 NodeJS 程式碼中,接收使用者輸入的方法 process.stdin.read 是在一個事件中呼叫的。後面的程式碼不會被阻塞(blocked)

JavaScript
1234567891011121314 'use strict';process.stdin.on('readable',()=>{varchunk=process.stdin.read();if(chunk!==null){process.stdout.write(`Async output data:${chunk}`);}});process.stdin.on('end',()=>{process.stdout.write('end');});console.log('Will not be blocked');

事件驅動程式模型基本的實現原理基本上都是使用 事件迴圈(Event Loop),這部分內容涉及瀏覽器事件模型、回撥原理,有興趣的去看連結裡面的視訊學習下

需要說明的是在客戶端 JavaScript 中像 setTimeout, XMLHTTPRequest 這類 API 並不是 JavaScript 語言本身就有的。而是 JavaScript 的宿主環境(在客戶端 JavaScript 中就是瀏覽器),同樣像 DOM、BOM、Event API 都是瀏覽器提供的

事件繫結的方法

DOM 元素行內繫結

直接在 DOM 元素上通過設定 on + eventType 來繫結事件處理程式

XHTML
1 <a href="#none"onclick="alert('clicked.')">點選我</a>

這種繫結方法是最原始的,有兩個缺點:

1 事件處理程式和 HTML 結構混雜在一起

早期在結構、樣式、表現分離的時代很忌諱這一點。現在看來在很多 MVX 框架中將事件繫結和 DOM 結構放在一起處理,這樣似乎更方便維護(不用來回切換 HTML,JavaScript 檔案),而且也符合可預見(predictable)性的規則

2 名稱空間衝突

因為 onclick 中的 JavaScript 程式碼片段執行環境是全域性作用域。然而在 JavaScript 語言中並沒有相關的名稱空間特性。所以就很容易造成名稱空間的衝突,非要用這種方法繫結事件的話只能用物件來做一些封裝

古老的繫結方法

使用 DOM Element 上面的 on + eventType 屬性 API

XHTML
123456 <a href="#none"id="button">click me</a><script>varel=getElementById('button');el.onclick=function(){alert('button clicked.')};el.onclick=function(){alert('button clicked (Rewrite event handler before).')};</script>

這種方法也有一個缺點,因為屬性賦值會覆蓋原值的。所以無法繫結 多個 事件處理函式,如果我們要註冊多個 onload 事件處理程式的話就得自己封裝一個方法來防止這種事情發生,下面這個例子可以解決這個問題

JavaScript
12345678910111213141516 <script>functionaddLoadEvent(fn){varoldonLoad=window.onload;if(typeofoldonLoad!=='function'){window.onload=fn;}else{window.onload=function(){oldonLoad();fn();}}}addLoadEvent(function(){alert('onload 1')});addLoadEvent(function(){alert('onload 2')});</script>

注意這只是個示例,生產環境很少會用到。一般用 DOM Ready 就可以了,因為 JavaScript 的執行通常不用等到頁面資源全部載入完,DOM 載入完就可以了

現代/標準的繫結方法

標準的繫結方法有兩種,addEventListenerattachEvent 前者是標準瀏覽器支援的 API,後者是 IE 8 以下瀏覽器支援的 API。通常需要我們做個相容封裝

JavaScript
123456789101112 <script>functionaddEvent(target,type,handler){if(target.addEventListener){target.addEventListener(type,handler,false);}else{target.attachEvent('on'+type,handler)}}addEvent(document,'click',function(){alert(this===document)});addEvent(document,'click',function(){alert(this===document)});</script>

上面的例子在 IE 8 以下和標準瀏覽器的效果是不一樣的,問題就在於 addEventListener 中的事件回撥函式中的 this 指向元素(target)本身,而 attachEvent 則指向 window 為了修復這個問題上面的 attachEvent 可以做一點小調整讓其保持和 addEventListener 的效果一樣,不過這樣的話註冊的 handler 就是個匿名函式,無法移除

JavaScript
12345678910111213 <script>functionaddEvent(target,type,handler){if(target.addEventListener){target.addEventListener(type,handler,false);}else{target.attachEvent('on'+type,function(){returnhandler.call(target)});}}addEvent(document,'click',function(){alert(this===document)});</script>

當上面這幾種情況同時出現的時候就比較有意思了,可以試試下面這段程式碼的你輸出

XHTML
12345678 <a href="javascript:alert(1)"onclick="alert(2)"id="link">click me</a><script>varlink=document.getElementById('link');link.onclick=function(){alert(3);}$('#link').bind('click',function(){alert(4);});$('#link').bind('click',function(){alert(5);});</script>

正確的結果應該是 3,4,5,1,根據結果我們可以得出以下結論:

  • 連結上的 href 偽 javascript 協議相當於在瀏覽器位址列執行了一段 JavaScript 程式碼,連結如果是這種格式,點選的時候相當於執行了這段 JavaScript 指令碼
  • 行內的事件繫結和元素呼叫 onclick 繫結事件會覆蓋
  • 使用 jQuery(內部使用標準事件註冊 API)可以繫結多個事件處理程式

事件冒泡

大部分事件會沿著事件觸發的目標元素往上傳播。比如:body>div>p>span 如果他們都註冊了點選事件,那麼在 span 元素上觸發點選事件後 p,div,body 各自的點選事件也會按順序觸發

事件冒泡是可以被停止的,下面這個函式封閉了停止事件冒泡的方法:

JavaScript
123456789101112131415 <script>functionstopPropagation(event){event=event||window.event;if(event.stopPropagation){event.stopPropagation()}else{// IEevent.cancelBubble=true}}addEvent('ele','click',function(e){// click handlerstopPropagation(e);});</script>

事件物件

標準瀏覽器中在事件處理程式被呼叫時 事件物件 會通過引數傳遞給處理程式,IE 8 及以下瀏覽器中事件物件可以通過全域性的 window.event 來訪問。比如我們要獲取當前點選的 DOM Element

JavaScript
123456789101112131415 <script>addEvent(document,'click',function(event){// IE 8 以下 => undefinedconsole.log(event);});addEvent(document,'click',function(event){event=event||window.event;// 標準瀏覽器 => [object HTMLHtmlElement]// IE 8 以下 => undefinedconsole.log(event.target);vartarget=event.target||event.srcElement;console.log(target.tagName);});</script>

事件代理

有時候我們需要給 不存在的(可能將來會有)的一段 DOM 元素繫結事件,比如給一段 Ajax 請求完成後渲染的 DOM 節點繫結事件。一般繫結的邏輯會在渲染前執行,繫結的時候找不到元素所以並不能成功,當然你也可以把繫結事件的程式碼放在 Ajax 請求之後。這樣做在一些事件邏輯簡單的應用裡面沒問題,但是會加重資料渲染邏輯和事件處理的邏輯耦合。一但事件處理程式特別多的時候,我們通常建議把事件的邏輯和其它程式碼邏輯分離,這樣方便維護。

為了解決這個問題,我們通常使用事件代理/委託(Event Delegation )。而且通常來說使用 事件代理的效能會比單獨繫結事件高 很多,我們來看個例子

XHTML
1234567 <ul id="list"><li id="item-1">item1</li><li id="item-2">item2</li><li id="item-3">item3</li><li id="item-4">item4</li><li id="item-5">item5</li></ul>

假如 ul 中的 HTML 是 Ajax 非同步插入的,通常我們的做法是 插入完成後遍歷每個 li 繫結事件處理程式

XHTML
12345

相關推薦

JavaScript 瀏覽器事件解析

JavaScript、瀏覽器、事件之間的關係 JavaScript 程式採用了非同步事件驅動程式設計(Event-driven programming)模型,維基百科對它的解釋是: 事件驅動程式設計(英語:Event-driven programming)是一種電腦程式設計模型

javascript阻止事件冒泡和瀏覽器的默認行為

pre stop key else can put 事件冒泡 prop top 1.阻止事件冒泡,使成為捕獲型事件觸發機制. 1 function stopBubble(e) { 2 //如果提供了事件對象,則這是一個非IE瀏覽器 3 if ( e &&

JavaScript瀏覽器解析原理

首先,JavaScript的特點是:   1. 跨平臺     可以再不同的作業系統上執行。   2. 弱型別     與之相對的是強型別     強型別:在定義變數的時候,需要將變數的資料型別表明。例如:Java     弱型別:定義變數的時候不需要定義資料型別,資料型別根據變數值來確定。例如:

移動裝置、手機瀏覽器Javascript滑動事件程式碼

以下經過本人測試成功。 測試平臺:三星S5830I 作業系統:Android 2.3.6 瀏覽器:UC瀏覽器 HTML標準:HTML5 測試了三個事件:touchstart、touchmove 和 touchend,並獲取了觸控時觸點在頁面上的座標,根據座標進行了左右滑動

瀏覽器常用事件解析

之前寫過一篇瀏覽器事件的相關操作和事件執行的原理——JavaScript瀏覽器事件解析。這一篇主要寫一些常用的事件及一些可能的坑。 表單事件 鍵盤事件 當 <input>, <textarea> 的值發生變化時觸發。此外,開

javascript打造跨瀏覽器事件處理機制:詳解

由於瀏覽器相容的複雜性.打造一個較優的跨瀏覽器事件處理函式.不是件容易的事情.各大類庫也都通過了種種方案去抽象一個龐大的事件機制. 使用類庫可以比較容易的解決相容性問題.但這背後的機理又是如何呢? 下面我們就一點點鋪開來講. element.add

[瀏覽器事件循環] javaScript事件循環 EventLoop

發現 按順序 總結 維數 完成後 js調用 observer 特殊 基本上 前言 Event Loop即事件循環,是指瀏覽器或Node的一種解決javaScript單線程運行時不會阻塞的一種機制,也就是我們經常使用異步的原理。 先熟悉基本概念 【堆Heap】 堆是一種數據

js window事件解析(轉載)

slow disable forward 建立 多選 1.0 參數 小程序 距離 js-window對象的方法和屬性資料 hxpd 發表於 2007-05-08 21:58:18 熟練window對象的open、close、alert、confirm、prompt、setT

JavaScript筆記——事件

跟著 bsp ava eset 窗口 輸入框 put cli 交互 事件一般是用於瀏覽器和用戶操作進行交互。最早是 IE 和 Netscape Navigator 中出現, 作為分擔服務器端運算負載的一種手段。直到幾乎所有的瀏覽器都支持事件處理。而 DOM2 級規範開始嘗試

瀏覽器解析和執行過程

們的 由於 繼續 動畫 table 就會 內嵌 cnblogs 內嵌腳本 當瀏覽器獲得一個html文件時,會“自上而下”加載,並在加載過程中進行解析渲染。 解析: 1. 瀏覽器會將HTML解析成一個DOM樹(display:none,visibility:hidden)。

JavaScript-onerror事件:圖片加載失敗後不顯示

mage function title 存在 fault splay pan hive javascrip HTML: <img src="http://www.mazey.net/images/upload/image/20170518/14951221981806

javascript-瀏覽器消息提醒

練手 index 詳細 nts tts miss 了解 .com asc 如何讓用戶在瀏覽器最小化的狀態下也能及時的收到消息提醒呢? 這個問題作為webRd是要正面面對的. 大約可分兩種場景:一種是類似桌面通知的形式還有一種是類似QQ提醒(在系統任務欄閃爍隨後高亮);接下來

JavaScript響應事件

onchange 表單 例如 單擊事件 處理器 什麽事 英文 lur 按鍵 事件:發生了某一件事情。 例如: onClick鼠標單擊,當你單擊的時候發生什麽事情。 1.onBlur焦點離開事件 2.onChange用戶修改了值正要離開事件 3.onClick鼠標單擊事件 4

Javascript - ExtJs - 事件

events gif gety src button 簡單 顯示 mouseover java 事件(ExtJs Event) Ext.Util.observable類 Ext.Util.observable是一個接口,為Ext組件的事件提供了支持,組件的事件不同於傳

JavaScript事件的target屬性

button name 點擊事件 .html hasclass alert -c color min target 事件屬性可返回事件的目標節點(哪個 DOM 元素觸發了該事件),如生成事件的元素、文檔或窗口。 語法:event.target <html> &

Javascript----input事件實現動態監聽textarea內容變化

span oninput idt ava ntb ima property onchange pre 1、代碼 <!DOCTYPE html> <html> <head> <title>textarea輸入文字監聽

JavaScript事件概念和監聽事件

scrip isp doctype utf itl 技術分享 創建 img ret 1、事件的概念: JavaScript使我們有能力創建動態頁面,網頁中的每一個元素都可以產生某些觸發JavaScript函數的事件。我們可以認為事件是可以被JavaScript偵測到的一種行

javascript 瀏覽器定位

his fail 1.5 doc int jquery margin point hidden <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="

C#事件事件解析

intern 處理機 信息 nta 語句 args handler poi pri 事件(event)是基於windows消息處理機制的類,封裝的更好,讓開發者無須知道底層的消息處理機制,就可以開發出強大的基於事件的應用程序來。委托(delegate)委托可以理解成為函數指

javascript-詞法分析解析

utf -c head 詞法分析 img style utf-8 doc rip <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8">