Js以事件驅動來實現介面互動。事件驅動的核心:以訊息為基礎,以事件來驅動。通俗地說,事件就是文件或瀏覽器視窗中發生的一些特定
互動行為,如載入、單擊、輸入、選擇等。
1.1事件基礎
Js與HTML之間互動就是通過事件實現的,事件就是文件或瀏覽器視窗中發生的一些特定的互動瞬間。事件在瀏覽器中是以物件的形式存在的,即event,觸發一個事件,就會產生一個事件物件event,該物件包含著所有與事件有關的資訊,包括導致事件的元素、事件的型別以及其他與特定事件相關的資訊。
1.1.1事件模型
在瀏覽器的發展歷史中。先後出現了以下4種事件處理模型:
- 基本事件模型:也稱為DOM0級事件模型,是瀏覽器發展初期出現的一種比較簡單的事件模型,主要通過事件屬性;為指定標籤繫結事件處理函式。
優點:
由於這種模型應用比較廣泛,獲得了所有瀏覽器的支援,目前依然比較流行。
缺點:
但是這種模型對HTML文件標籤的依賴較為嚴重,不利於Js獨立開發。
2. DOM事件模型:有W3C制定,是目前標準的事件處理模型。所有符合標準的瀏覽器都支援該事件模型。DOM事件模型包括DOM2事件模型和DOM3事件模型,
DOM3事件模型為DOM2事件模型的升級版,略有完善,主要是新增了一些事情型別,以適應移動裝置的開發需要,但大部分規範和用法保持一致。
3. IE事件模型:IE4.0及其以上版本瀏覽器支援,與DOM事件模型相似,但用法不同。
4. Netscape事件模型:由Netscape4瀏覽器實現,在Netscape6中停止支援。
1.1.2事件流
事件流就是多個節點物件對同一種事件進行響應的先後順序。主要包括3種型別。
1.冒泡型
從最特定的目標向最不特定的目標依次觸發事件,也就是事件從下向上進行響應,這個傳遞過程被形象地稱為冒泡。
下面用法:
function bubble() { var div = document.getElementsByTagName('div'); var show = document.getElementById('show'); for (var i = 0; i < div.length; i++) { div[i].onclick = (function (i) { return function () { div[i].style.border = '1px dashed orange'; show.innerHTML += div[i].className + '>'; } })(i); } } window.onload = bubble;
2.捕獲型
事件從最不特定的目標開始被觸發,最後到最特定的目標,也就是事件從上向下進行響應。
下面用法:
for (var i = 0; i < div.length; i++) { div[i]. /*onclick*/ addEventListener('click', (function (i) { return function () { div[i].style.border = '1px dashed orange'; show.innerHTML += div[i].className + '>'; } })(i), true); }
3.混合型
W3C的DOM事件模型支援捕獲型和冒泡型兩種事件流,但是捕獲型事件流先發生,然後才發生冒泡型事件流。兩種事件流會觸及DOM中的所
有層級物件,從document物件開始,最後返回document物件結束。
根據事件流型別。
以下可以把事件傳播的整個過程分為3個階段:
捕獲階段 |
事件從document物件沿文件樹向下傳播到目標節點。 |
目標階段 |
註冊在目標節點上的事件被執行。 |
冒泡階段 |
事件從目標節點向上觸發。 |
1.1.3事件型別
根據觸發物件不同,可以將瀏覽器中發生的事件分成不同的型別。
DOM0級事件定義了以下事件型別:
① 滑鼠事件:與滑鼠操作相關的各種行為。可以細分為兩類:
如(mouseover、mouseout) |
跟蹤滑鼠當前定位的事件 |
如(mouseup、mousedown、click) |
跟蹤滑鼠單擊的事件 |
② 鍵盤事件:與鍵盤操作相關的各種行為,包括追蹤鍵盤敲擊及其上下文。
追蹤鍵盤包括3種型別:
-
keyup
-
keydown
-
keypress
③ 頁面事件:關於頁面本身的行為。例如,當首次載入頁面時觸發load事件和離開頁面時觸發unload和beforeunload事件。
④ UI事件:追蹤使用者在頁面中的各種行為。例如,監聽使用者在表單中的輸入,可以通過focus和blur兩個事件來實現。
DOM2事件模型中,事件模型包含4個子模組,每個子模組提供對某類事件的支援。
‘預設動作’列定義了事件型別是否支援preventDefault()方法,取消事件的預設動作。
DOM3事件模型新增了一些新事件。
DOM3事件型別簡單說明如下:
UI(User Interface,使用者介面)事件 |
當使用者與頁面上的元素互動時觸發。 |
焦點事件 |
當元素獲得或失去焦點時觸發。 |
滑鼠事件 |
當使用者通過滑鼠在頁面上執行操作時觸發。 |
滾輪事件 |
當使用滑鼠滾輪或類似裝置時觸發。 |
文字事件 |
在文件中輸入文字時觸發。 |
鍵盤事件 |
當使用者通過鍵盤在頁面上執行操作時觸發。 |
合成事件 |
當為IME輸入字元時觸發。 |
變動事件 |
當底層DOM結構發生變化時觸發。 |
1.1.4繫結事件
在基本事件模型中,Js支援兩種繫結方式。
1. 靜態繫結
把Js指令碼作為屬性值,直接賦予事件屬性。
下面用法:
<button onclick="document.write('我是程式設計師!');">按鈕</button>
2. 動態繫結
使用DOM物件的事件屬性進行賦值。
下面用法:
var button = document.getElementById('btn'); button.onclick = function () { document.write('我是程式設計師!'); }
這種方法可以在指令碼中直接為頁面元素附加事件,不用破壞HTML結構,比上一種靈活。
1.1.5事件處理函式
事件處理函式是一類特殊的函式,其結構與函式直接量相同,主要任務是實現事件處理。使用方法是非同步呼叫,由事件觸發進行響應。
事件處理函式一般沒有明確的返回值。不過在特定事件中,使用者可以利用事件處理函式的返回值影響程式的執行。
下面用法:
function btn1(event) { event = event || window.event; var btn11 = event.srcElement ? event.srcElement : Event.target; btn11.style.background = 'green'; }
function btn2(event) { event = event || window.event; var src = event.srcElement ? event.srcElement : Event.target; src.style.background = 'skyblue'; }
1.1.6註冊事件
在DOM事件模型中,通過呼叫物件的addEventListener()方法註冊事件。
語法:
element.addEventListener(type, listener, useCapture);
引數:
-
type(表示監聽事件型別的字串。)
-
listener(當所監聽的事件型別觸發時,會接收到一個事件通知(實現了 Event 介面的物件)物件。
-
listener 必須是一個實現了 EventListener 介面的物件,或者是一個函式。)
-
useCapture(Boolean,在DOM樹中,註冊了listener的元素,是否要先於它下面的EventTarget,呼叫該listener。
-
當useCapture(設為true) 時,沿著DOM樹向上冒泡的事件,不會觸發listener。
-
當一個元素巢狀了另一個元素,並且兩個元素都對同一事件註冊了一個處理函式時,所發生的事件冒泡和事件捕獲是兩種不同的事件傳播方式。
-
事件傳播模式決定了元素以哪個順序接收事件。如果沒有指定,useCapture預設為 false 。)
下面用法:
var p1 = document.getElementById('p1'); p1.addEventListener('mouseover', function () { p1.style.background = 'green'; }, true); p1.addEventListener('mouseout', function () { p1.style.background = 'red'; }, true);
1.1.7銷燬事件
在DOM事件模型中,使用removeEventListener()方法可以從指定物件中刪除已經註冊的事件處理函式。
用法:
element.removeEventListener(event, function, useCapture)
引數:
event | 必須。要移除的事件名稱。 |
function | 必須。指定要移除的函式。 |
useCapture | 可選。布林值,指定移除事件控制程式碼的階段。 |
可能值:
true - 在捕獲階段移除事件控制程式碼。
false- 預設。在冒泡階段移除事件控制程式碼。
注意: 如果新增兩次事件控制程式碼,一次在捕獲階段,一次在冒泡階段,你必須單獨移除該事件。
下面用法:
var span1 = document.getElementById('span1'); var f1 = function () { span1.style.background = 'pink'; }; var f2 = function () { span1.style.background = 'skyblue'; span1.removeEventListener('mouseover', f1); span1.removeEventListener('mouseout', f2); }; span1.addEventListener('mouseover', f1); span1.addEventListener('mouseout', f2);
1.1.8事件委託
Js事件委託就是利用冒泡的原理,把本應該新增到某個元素上的事件委託給他的父級,從而減少DOM互動達到網頁優化。
這樣做的好處:
優化程式碼 |
提升執行效能 |
真正把HTML和Js分離,也能防止在動態新增或刪除節點的過程中註冊的事件丟失。
下面用法:
var ul = document.getElementById('list'); ul.addEventListener('click', function (e) { var e = e || window.event; var target = e.target || e.srcElement; if (e.target && e.target.nodeName.toUpperCase() == 'LI') { document.write(e.target.innerHTML); } }, true);
var i = 4; var btn = document.getElementById('btn'); btn.addEventListener('click', function () { var li = document.createElement('li'); li.innerHTML = '我是程式設計師' + i++; ul.appendChild(li); });
1.2使用滑鼠事件
滑鼠事件是Web開發中最常用的事件型別。
1.2.1滑鼠點選
滑鼠點選事件包括4個:
click |
單擊 |
dbclick |
雙擊 |
mousedown |
按下 |
mouseup |
鬆開 |
其中click事件型別最為常用,而mousedown和mouseup事件型別多用於在滑鼠拖放、拉伸操作中。當這些事件處理函式的返回值為false時,
則會禁止繫結物件的預設行為。
下面用法:
var a = document.getElementsByTagName('a'); for (var i = 0; i < a.length; i++) { if ((new RegExp(window.location.href)).test(a[i].href)) { a[i].onclick = function () { return false; } } }
1.2.2滑鼠移動
mousemove事件型別是一個實時響應的事件,當滑鼠指標的位置發生變化時(至少移動一個畫素),就會觸發mousemove事件。
該事件響應的靈敏度主要參考滑鼠的指標的移動速度的快慢,以及瀏覽器跟新的速度。
下面用法:
var box = document.getElementById('box'); box.style.position = 'absolute'; box.style.width = '200px'; box.style.height = '200px'; box.style.background = 'green'; var mx, my, ox, oy; function e(event) { if (!event) { event = window.event; event.target = event.srcElement; event.layerX = event.offsetX; event.layerY = event.offsetY; } event.mx = event.pageX || event.clientX + document.body.scrollLeft; event.my = event.pageY || event.clientY + document.body.scrollTop; return event; } document.onmousedown = function (event) { event = e(event); o = event.target; ox = parseInt(o.offsetLeft); oy = parseInt(o.offsetTop); mx = event.mx; my = event.my; document.onmousemove = move; document.onmouseup = stop; } function move(event) { event = e(event); o.style.left = ox + event.mx - mx + 'px'; o.style.Top = oy + event.my - my + 'px'; } function stop(event) { event = e(event); ox = parseInt(o.offsetLeft); oy = parseInt(o.offsetTop); mx = event.mx; my = event.my; o = document.onmousemove = document.onmouseup = null; }
1.2.3滑鼠經過
滑鼠經過包括下面兩種事件型別:
移過 |
當移動滑鼠指標到某個元素上時,將觸發mouseover事件。 |
移出 |
當把滑鼠指標移出某個元素時,將觸發mouseout事件。 |
如果從父元素中移到子元素中時,也會觸發父元素的mouseover事件型別。
下面用法:
var div = document.getElementsByTagName('div'); for (var i = 0; i < div.length; i++) { div[i].onmousemove = function (e) { this.style.color = 'orange'; this.style.fontSize = '24px'; this.style.fontWeight = '600'; } div[i].onmouseout = function () { this.style.color = 'red'; } }
1.3使用鍵盤事件
當使用者操作鍵盤時會觸發鍵盤事件。
鍵盤事件主要包括下面3種型別:
keydown |
在鍵盤上按下某個鍵時觸發。 |
keypress |
按下某個鍵盤鍵並釋放時觸發。 |
Keyup |
釋放某個鍵盤鍵時觸發。 |
1.3.1鍵盤事件屬性
鍵盤事件定義了很多屬性,利用這些屬性可以精確控制鍵盤操作。鍵盤事件屬性一般只在鍵盤相關事件發生時才會存在於事件物件中。
下面用法:
var box = document.getElementById('box'); box.style.position = 'absolute'; box.style.width = '100px'; box.style.height = '100px'; box.style.background = 'green'; document.keyDown = keyDown; function keyDown(event) { var event = event || window.event; switch (event.keyCode) { case 37: box.style.left = box.offsetLeft - 5 + 'px'; break; case 38: box.style.left = box.offsetLeft + 5 + 'px'; break; case 39: box.style.top = box.offsetTop - 5 + 'px'; break; case 40: box.style.top = box.offsetTop + 5 + 'px'; break; } return false; }
1.4使用頁面事件
所有頁面事件都明確地處理整個頁面的函式和狀態。
1.4.1視窗重置
resize事件型別是在瀏覽器視窗被重置時觸發的,當使用者調整視窗大小,或者最大化,最小化、恢復視窗大小顯示時均可觸發resize事件。
利用該時間可以根據視窗大小的變化以便動態調整頁面元素的顯示大小。
下面用法:
var box = document.getElementById("box"); box.style.position = "absolute"; box.style.backgroundColor = "red"; box.style.width = w() * 0.8 + "px"; box.style.height = h() * 0.8 + "px"; window.onresize = function () { box.style.width = w() * 0.8 + "px"; box.style.height = h() * 0.8 + "px"; }
function w() { if (window.innerWidth) { //相容DOM return window.innerWidth; } else if (document.body) { return document.body.clientWidth; //相容IE } }
function h() { if (window.innerHeight) { return window.innerHeight; } else if (document.body) { return document.body.clientHeight; } }
1.4.2頁面滾動
scroll事件型別是在元素滾動條在滾動時觸發。
下面用法:
var box = document.getElementById("box"); box.style.position = 'absolute'; box.style.width = '100px'; box.style.height = '100px'; box.style.background = 'green'; window.onload = f; window.onscroll = f; function f() { box.style.left = 100 + parseInt(document.body.scrollLeft) + 'px'; box.style.top = 100 + parseInt(document.body.scrollTop) + 'px'; }
1.5使用UI事件
UI事件負責響應使用者與頁面元素的互動。
1.5.1焦點處理
焦點處理主要包括以下兩種事件型別:
focus |
獲得焦點 |
blur |
失去焦點 |
所謂獲得焦點;就是啟用表單欄位,使其可以響應鍵盤事件。
所謂失去焦點:就是指定元素當失去焦點就會觸發此事件。(通常應用於表單元素。)
下面用法:
var form = document.getElementById('myform'); var field = form.elements['name']; window.onload = function () { field.focus(); field.blur(); }
1.5.2選擇文字
當在文字框或文字區域內選擇文字時,將觸發select事件。
下面用法:
var a = document.getElementsByTagName('input')[0]; var b = document.getElementsByTagName('input')[1]; a.onselect = function () { if (document.selection) { o = document.selection.createRange(); if (o.text.length > 0) b.value = o.text; } else { p1 = a.selectionStart; p2 = a.selectionEnd; b.value = a.value.substring(p1, p2); } }
1.5.3字串變化檢測
change事件型別是在表單元素的值發生變化時觸發,它主要用於input、select、和textarea元素。
下面用法:
var a = document.getElementsByTagName('select')[0]; a.onchange = function () { window.open(this.value, ''); }
1.5.4提交表單
使用<input>或<button>標籤都可以定義提交按鈕。
下面用法:
var t = document.getElementsByTagName('input')[0]; var f = document.getElementsByTagName('form')[0]; f.onsubmit = function (e) { document.write(t.value); }
1.5.5重置表單
當單擊重置按鈕時,表單被重置,所有表單欄位恢復初始值。這時會觸發resct事件。
下面用法:
var t = document.getElementsByTagName('input')[0]; var f = document.getElementsByTagName('form')[0]; f.onreset = function (e) { document.write(t.value); }
1.5.6剪貼簿資料
HTML5規範了剪貼簿資料操作。
主要包括6個剪貼簿事件:
beforecopy |
在發生複製操作前觸發。 |
copy |
在發生複製操作時觸發。 |
beforecut |
在發生剪下操作前觸發。 |
cut |
在發生剪下操作時觸發。 |
beforepaste |
在發生貼上操作前觸發。 |
paste |
在發生貼上操作時觸發。 |
至於copy、cut和paste事件,只要是在上下文選單中選擇了相應選項等,所有瀏覽器都會觸發它們。
下面用法:
var form = document.getElementById('myform'); var field1 = form.elements[0]; var getClipboardText = function (event) { var clipboardData = (event.clipboardData || window.clipboardData); return clipboardData.getData('text'); };
var setClipboardText = function (event, value) { if (event.clipboardData) { event.clipboardData.setData('text/plain', value); } else if (window.clipboardData) { window.clipboardData.setData('text', value); } };
var addHandler = function (element, type, handler) { if (document.addEventListener) { document.addEventListener(type, handler, false); } else if (element.attachEvent) { element.attachEvent('on' + type, handler); } else { element['on' + type] = handler; } };
addHandler(field1, 'paste', function (event) { event = event || window.event; var text = getClipboardText(event); if (!/^\d*$/.text(text)) { if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } } })
1.6 實戰案例
1.6.1 設計彈出對話方塊
無論從事Web前端開發,還是從事Vue前端開發,事件都是經常用到的。
下面用法:
function Dialog(id) { this.id = id; var that = this; document.getElementById(id).children[0].onclick = function () { that.close(); } }
Dialog.prototype.show = function () { var dlg = document.getElementById(this.id); dlg.style.display = 'block'; dlg = null; }
Dialog.prototype.close = function () { var dlg = document.getElementById(this.id); dlg.style.display = 'none'; dlg = null; }
function openDialog() { var dlg = new Dialog('dlgText'); dlg.show(); }