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種類型:
在鍵盤上按下某個鍵時觸發。 | |
按下某個鍵盤鍵并釋放時觸發。 | |
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 設計彈出對話框
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();
}