溫故js系列(10)-事件event

前端學習:教程&開發模塊化/規範化/工程化/優化&工具/調試&值得關注的博客/Git&面試-前端資源彙總javascript

歡迎提issues斧正:Event前端

JavaScript-事件event

JavaScript中,事件通常是指瀏覽器和用戶操做進行交互。咱們能夠經過偵聽器(或者處理程序)來預約事件,以便事件發生的時候執行相應的代碼。java

事件模型

JavaScript的事件模型有DOM0,腳本模型,DOM2&DOM3三個模型。git

DOM0模型

DOM0模型即內聯模型,這種模型是最傳統接單的一種處理事件的方法。在內聯模型中,事件處理函數是HTML標籤的一個屬性,用於處理指定事件。雖然內聯在早期使用較多,但它是和HTML 混寫的,並無與HTML 分離。github

<input type="button" value="click me " onclick="console.log('xzavier win');" />
//點擊在打印臺輸出 xzavier win 

<input type="button" value="click me " onclick="func();" />
<script type="text/javascript">
function func(){
  console.log('xzavier win win');
}
//點擊在打印臺輸出 xzavier win win

其實世上原本沒有DOM0,叫的人多了,也就有了DOM0。1998 年 10 月 DOM1級規範成爲 W3C 的推薦標準,在此以前的實現咱們就習慣稱爲DOM0級,後來就都叫DOM0了。面試

腳本模型

內聯模型違反了HTML 與JavaScript 代碼層次分離的原則。腳本模型讓咱們能夠在JavaScript 中處理事件。編程

<input type="button" id="myBotton" value="click me " />
var oBotton = document.getElementById('myBotton');
oBotton.onclick = function () {
  console.log('xzavier win win');
};  //點擊在打印臺輸出 xzavier win win

DOM2&DOM3模型

DOM2和DOM3級別則在這個結構的基礎上引入了更多的交互能力,也支持了更高級的XML特性。爲此DOM2和DOM3級分爲許多模塊(模塊之間具備某種關聯),分別描述了DOM的某個很是具體的子集。瀏覽器

一、DOM2級核心(DOM Level 2 Core):在1級核心的基礎上構建,爲節點添加了更多方法和屬性;
二、DOM2級視圖(DOM Level 2 Views):爲文檔定義了基於樣式信息的不一樣視圖;
三、DOM2級事件(DOM Level 2 Style):定義瞭如何以編程方式來訪問和改變CSS樣式信息;
四、DOM2級遍歷和範圍(DOM Level 2 Traversal and Range):引入了遍歷DOM文檔和選擇其特定部分的新接口。
五、DOM2級HTML(DOM Level 2 HTML):在1級HTML基礎上構建,添加了更多屬性、方法和新接口。
六、DOM3級又增長了XPath模塊和加載與保存(Load and Save)模塊。框架

<input type="button" id="myBotton" value="click me " />
var oBotton = document.getElementById('myBotton'); 

oBotton1.addEventListener('click', function () {
    console.log('xzavier win win');
});  //點擊在打印臺輸出 xzavier win win

DOM2 級事件」定義了兩個方法,用於添加事件和刪除事件處理程序的操做:
addEventListener()和removeEventListener()。全部DOM 節點中都包含這兩個方法,而且它們都接受3 個參數;事件名、函數、冒泡或捕獲的布爾值(true 表示捕獲,false 表示冒泡)。模塊化

window.addEventListener('load', function () {
    console.log('xzavier');
}, false);

IE 實現了與DOM2 中相似的兩個方法:attachEvent()和detachEvent()。這兩個方法接受相同的參數:事件名稱和函數。

window.attachEvent('onload', function () {
    console.log('xzavier');
});

寫一個ready()方法,DOM結構繪製完畢後就執行,沒必要等到加載完畢,也實踐下兼容

function ready(fn){
    if(document.addEventListener) {        //標準瀏覽器
        document.addEventListener('DOMContentLoaded', function() {
            //註銷事件, 避免反覆觸發
            document.removeEventListener('DOMContentLoaded',arguments.callee, false);
            fn();            //執行函數
        }, false);
    }else if(document.attachEvent) {        //IE
        document.attachEvent('onreadystatechange', function() {
            if(document.readyState == 'complete') {
                document.detachEvent('onreadystatechange', arguments.callee);
                fn();        //函數執行
            }
        });
    }
};

事件類型

JavaScript 能夠處理的事件類型爲:鼠標事件、鍵盤事件、HTML 事件。

鼠標事件

<input type="button" id="myBotton" value="click me " />
var oBotton = document.getElementById('myBotton'); 
click:當用戶單擊鼠標按鈕或按下回車鍵時觸發
oBotton.onclick = function () {
    console.log('xzavier is so ...');
};
dblclick:當用戶雙擊主鼠標按鈕時觸發
oBotton.ondblclick = function () {
    console.log('xzavier is so ...');
};
mousedown:當用戶按下了鼠標還未彈起時觸發
oBotton.onmousedown = function () {
    console.log('xzavier is so ...');
};
mouseup:當用戶釋放鼠標按鈕時觸發
oBotton.onmouseup = function () {
    console.log('xzavier is so ...');
};
mouseover:當鼠標移到某個元素上方時觸發
oBotton.onmouseover = function () {
    console.log('xzavier is so ...');
};
mouseenter:同mouseover,但子元素不會觸發
oBotton.onmouseenter = function () {
    console.log('xzavier is so ...');
};
mouseout:當鼠標移出某個元素上方時觸發
oBotton.onmouseout = function () {
    console.log('xzavier is so ...');
};
mouseleave: 同onmouseout,但子元素不會觸發
oBotton.onmouseleave = function () {
    console.log('xzavier is so ...');
};
mousemove:當鼠標指針在元素上移動時觸發
oBotton.onmousemove = function () {
    console.log('xzavier is so ...');
};
drag: 事件在元素或者選取的文本被拖動時觸發,但必須設有draggable="true"
oBotton.ondrag = function () {
    console.log('xzavier is so ...');
};
在拖動元素時,每隔 350 毫秒會觸發 ondrag 事件

mouseover與mouseenter
不論鼠標指針穿過被選元素或其子元素,都會觸發 mouseover 事件。只有在鼠標指針穿過被選元素時,纔會觸發 mouseenter 事件。

mouseout與mouseleave
不論鼠標指針離開被選元素仍是任何子元素,都會觸發 mouseout 事件。只有在鼠標指針離開被選元素時,纔會觸發 mouseleave 事件。

關於拖拽
在拖動目標上觸發事件 (源元素):

ondragstart - 用戶開始拖動元素時觸發
ondrag - 元素正在拖動時觸發
ondragend - 用戶完成元素拖動後觸發

釋放目標時觸發的事件:

ondragenter - 當被鼠標拖動的對象進入其容器範圍內時觸發此事件
ondragover - 當某被拖動的對象在另外一對象容器範圍內拖動時觸發此事件
ondragleave - 當被鼠標拖動的對象離開其容器範圍內時觸發此事件
ondrop - 在一個拖動過程當中,釋放鼠標鍵時觸發此事件

鍵盤事件

keydown:當用戶按下鍵盤上任意鍵觸發,若是按住不放,會重複觸發。
onkeydown = function () {
    console.log('xzavier is so ...');
};
keypress:當用戶按下鍵盤上的字符鍵觸發,若是按住不放,會重複觸發。
onkeypress = function () {
    console.log('xzavier is so ...');
};
keyup:當用戶釋放鍵盤上的鍵觸發。
onkeyup = function () {
    console.log('xzavier is so ...');
};

keydown返回的是鍵盤的代碼, keypress返回的是ASCII字符。若是隻想讀取字符, 用keypress, 若是想讀各鍵的狀態, 用keydown.

HTML 事件

load:當頁面徹底加載後在window 上面觸發,或當框架集加載完畢後在框架集上觸發。
window.onload = function () {
    console.log('xzavier is so ...');
};
unload:當頁面徹底卸載後在window 上面觸發,或當框架集卸載後在框架集上觸發。
window.onunload = function () {
    console.log('xzavier is so ...');
};
select:當用戶選擇文本框(input 或textarea)中的一個或多個字符觸發。
input.onselect = function () {
    console.log('xzavier is so ...');
};
<input type="textarea" id="myBotton" value="click me " />
var oBotton = document.getElementById('myBotton'); 
change:當文本框(input 或textarea)內容改變且失去焦點後觸發。
oBotton.onchange = function () {
    console.log('xzavier is so ...');
};
focus:當頁面或者元素得到焦點時在window 及相關元素上面觸發。
oBotton.onfocus = function () {
    console.log('xzavier is so ...');
};
blur:當頁面或元素失去焦點時在window 及相關元素上觸發。
oBotton.onblur = function () {
    console.log('xzavier is so ...');
};
submit:當用戶點擊提交按鈕在<form>元素上觸發。
form.onsubmit = function () {
    console.log('xzavier is so ...');
};
reset:當用戶點擊重置按鈕在<form>元素上觸發。
form.onreset= function () {
    console.log('xzavier is so ...');
};
resize:當窗口或框架的大小變化時在window 或框架上觸發。
window.onresize = function () {
    console.log('xzavier is so ...');
};
scroll:當用戶滾動帶滾動條的元素時觸發。
window.onscroll = function () {
    console.log('xzavier is so ...');
};

事件對象

事件對象就是event 對象,經過處理函數傳遞。

//經過處理函數傳遞事件對象
<input type="textarea" id="myBotton" value="click me " />
var oBotton = document.getElementById('myBotton'); 
oBotton.addEventListener('click', function (e) { //接受事件對象參數
    console.log(e);
});

event 對象的屬性

屬性名                          描述
type                獲取這個事件的事件類型,例如:click
target              獲取綁定事件的DOM 元素
data                獲取事件調用時的額外數據
relatedTarget       獲取移入移出目標點離開或進入的那個DOM 元素
currentTarget       獲取冒泡前觸發的DOM 元素,等同與this
pageX/pageY         獲取相對於頁面原點的水平/垂直座標
screenX/screenY     獲取顯示器屏幕位置的水平/垂直座標(非jQuery 封裝)
clientX/clientY     獲取相對於頁面視口的水平/垂直座標(非jQuery 封裝)
result              獲取上一個相同事件的返回值
timeStamp           獲取事件觸發的時間戳
which               獲取鼠標的左中右鍵(1,2,3),或獲取鍵盤按鍵
altKey/shiftKey/ctrlKey/metaKey 獲取是否按下了alt、shift、ctrl或 meta 鍵

event.target 獲得的是觸發元素的DOM,event.currentTarget 獲得的是監聽元素的DOM。而this 也是獲得監聽元素的DOM。

冒泡和默認行爲

若是在頁面中重疊了多個元素,而且重疊的這些元素都綁定了同一個事件,那麼就會出現冒泡問題。

<div id="myDiv" style="width:200px;height:200px;background:#666;">
    input type="button" id="myBotton" value="click me " />
</div>
var oBotton = document.getElementById('myBotton');
var oDiv = document.getElementById('myDiv'); 
//三個不一樣元素觸發事件
oBotton.addEventListener('click', function () {
  console.log('input');
});
oDiv.addEventListener('click', function () {
  console.log('div');
});
document.addEventListener('click', function () {
  console.log('document');
});

當點擊文檔的時候,只觸發文檔事件;當點擊div 層時,觸發了div 和文檔兩個;當咱們點擊按鈕時,觸發了按鈕、div 和文檔。觸發的順序是從小範圍到大範圍。這就是所謂的冒泡現象,一層一層往上冒泡觸發。

網頁中的元素,在操做的時候會有本身的默認行爲。好比:右擊文本框輸入區域,會彈出系統菜單、點擊超連接會跳轉到指定頁面、點擊提交按鈕會提交數據。咱們能夠組織默認行爲的發生

//禁止連接跳轉
$('a').click(function (e) {
    e.preventDefault();
});
//禁止提交表單跳轉
$('form').submit(function (e) {
    e.preventDefault();
});

若是想讓上面的超連接同時阻止默認行爲且禁止冒泡行爲,能夠把兩個方法同時寫上:event.stopPropagation()和event.preventDefault()。這兩個方法若是須要同時啓用的時候,還有一種簡寫方案代替,就是直接return false

$('a').click(function (e) {
    return false;
});

冒泡和默認行爲的一些方法

方法名                                  描述
preventDefault()                取消某個元素的默認行爲
isDefaultPrevented()            判斷是否調用了preventDefault()方法
stopPropagation()               取消事件冒泡
isPropagationStopped()          判斷是否調用了stopPropagation()方法
stopImmediatePropagation()      取消事件冒泡,並取消該事件的後續事件處理函數
isImmediatePropagationStopped() 判斷是否調用了stopImmediatePropagation()方法

捕獲冒泡

1.事件冒泡:事件按照從最特定的事件目標到最不特定的事件目標(通常爲document對象)的順序觸發。
2.事件捕獲(event capturing):事件從最不精確的對象(通常爲document 對象)開始觸發,而後到最精確(也能夠在窗口級別捕獲事件,不過必須由開發人員特別指定)。
3.DOM事件流:同時支持兩種事件模型:捕獲型事件和冒泡型事件,可是,捕獲型事件先發生。兩種事件流會觸及DOM中的全部對象,從document對象開始,也在document對象結束。

事件捕獲階段:事件從最上一級標籤開始往下查找,直到捕獲到事件目標(target)。
事件冒泡階段:事件從事件目標(target)開始,往上冒泡直到頁面的最上一級標籤。
不是全部的事件都能冒泡,例如:blur、focus、load、unload等

W3C : addEventListener('click',doSomething,true); //true=捕獲 false=冒泡
諸如onclick,onchange 事件採用事件冒泡方式
IE : attachEvent("onclick", doSomething2); 不支持捕獲,只有冒泡.

阻止事件冒泡:
在W3c中,使用stopPropagation()方法
    在IE下設置cancelBubble = true;
    在捕獲的過程當中stopPropagation()後,後面的冒泡過程也不會發生了~
阻止事件的默認行爲,例如click <a>後的跳轉~
    在W3c中,使用preventDefault()方法;
    在IE下設置window.event.returnValue = false;

事件委託

事件委託的原理就是事件冒泡。使用事件委託技術可讓你對每一個節點添加事件監聽器,事件監聽器被添加到它們的父元素上。事件監聽器會分析從子元素冒泡上來的事件,找到是哪一個子元素的事件。
獲取點擊的元素的信息:

ul id="test">
    <li>first</li>
    <li>second</li>
    <li>third</li>
</ul>
// 方法一:
var lis = document.getElementById('test').getElementsByTagName('li');
for(var i = 0;i < 3;i++){
    lis[i].index = i;
    lis[i].onclick = function(){
        console.log(this.index);
    };
} 
// 方法二:
var lis = document.getElementById('test').getElementsByTagName('li');
for(var i = 0;i < 3;i++){
    lis[i].index = i;
    lis[i].onclick = (function(val){
        return function() {
            console.log(val);
        }
    })(i);
}
// 方法三 事件委託  委託給ul
var oUl = document.getElementById('test');
oUl.addEventListener('click',function(e){
    var lis = e.target;
    console.log(lis); 
});

學習參考:DOM3級與事件

相關文章
相關標籤/搜索