html
該方法接收三個參數:瀏覽器
type: 事件類型字符串,好比click、mouseover ,注意這裏不要帶ondom
listener: 事件處理函數,事件發生時,會調用該監聽函數函數
useCapture: 可選參數,是-個布爾值,默認是false。學完DOM事件流後,咱們再進一步學習性能
eventTarget.attachEvent()方法將指定的監聽器註冊到 eventTarget(目標對象) 上,當該對象觸發指定的事件時,指定的回調函數就會被執行。學習
該方法接收兩個參數:this
eventNameWithOn: 事件類型字符串,好比onclick、 onmouseover,這裏要帶onatom
callback: 事件處理函數,當目標觸發事件時回調函數被調用spa
注意: IE8 及早期版本支持3d
<button>傳統註冊事件</button>
<button>方法監聽註冊事件</button>
<button>ie9 attachEvent</button>
<script>
var btns = document.querySelectorAll('button');
// 1. 傳統方式註冊事件
btns[0].onclick = function() {
alert('hi');
}
btns[0].onclick = function() {
alert('hao a u');
}
// 2. 事件偵聽註冊事件 addEventListener
// (1) 裏面的事件類型是字符串 一定加引號 並且不帶on
// (2) 同一個元素 同一個事件能夠添加多個偵聽器(事件處理程序)
btns[1].addEventListener('click', function() {
alert(22);
})
btns[1].addEventListener('click', function() {
alert(33);
})
// 3. attachEvent ie9之前的版本支持
btns[2].attachEvent('onclick', function() {
alert(11);
})
</script>
封裝一個函數,函數中判斷瀏覽器的類型:
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
// 1. 傳統方式刪除事件
divs[0].onclick = null;
}
// 2. removeEventListener 刪除事件
divs[1].addEventListener('click', fn) // 裏面的fn 不須要加小括號調用
function fn() {
alert(22);
divs[1].removeEventListener('click', fn);
}
// 3. detachEvent
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
</script>
刪除事件兼容性解決方案
html中的標籤都是相互嵌套的,咱們能夠將元素想象成一個盒子裝一個盒子,document是最外面的大盒子。
當你單擊一個div時,同時你也單擊了div的父元素,甚至整個頁面。
那麼是先執行父元素的單擊事件,仍是先執行div的單擊事件 ???
事件流描述的是從頁面中接收事件的順序。
事件發生時會在元素節點之間按照特定的順序傳播,這個傳播過程即DOM事件流
好比:咱們給頁面中的一個div註冊了單擊事件,當你單擊了div時,也就單擊了body,單擊了html,單擊了document。
當時的2大瀏覽器霸主誰也不服誰!
IE 提出從目標元素開始,而後一層一層向外接收事件並響應,也就是冒泡型事件流。
Netscape(網景公司)提出從最外層開始,而後一層一層向內接收事件並響應,也就是捕獲型事件流。
江湖紛爭,武林盟主也腦袋疼!!!
最終,w3c 採用折中的方式,平息了戰火,制定了統一的標準 —--— 先捕獲再冒泡。
現代瀏覽器都遵循了此標準,因此當事件發生時,會經歷3個階段。
DOM 事件流會經歷3個階段:
捕獲階段
當前目標階段
冒泡階段
咱們向水裏面扔一塊石頭,首先它會有一個降低的過程,這個過程就能夠理解爲從最頂層向事件發生的最具體元素(目標點)的捕獲過程;以後會產生泡泡,會在最低點( 最具體元素)以後漂浮到水面上,這個過程至關於事件冒泡。
事件冒泡
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// onclick 和 attachEvent(ie) 只在冒泡階段觸發
// 冒泡階段 若是addEventListener 第三個參數是 false 或者 省略
// son -> father ->body -> html -> document
var son = document.querySelector('.son');
// 給son註冊單擊事件
son.addEventListener('click', function() {
alert('son');
}, false);
// 給father註冊單擊事件
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
// 給document註冊單擊事件,省略第3個參數
document.addEventListener('click', function() {
alert('document');
})
</script>
事件捕獲
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// 若是addEventListener() 第三個參數是 true 那麼在捕獲階段觸發
// document -> html -> body -> father -> son
var son = document.querySelector('.son');
// 給son註冊單擊事件,第3個參數爲true
son.addEventListener('click', function() {
alert('son');
}, true);
var father = document.querySelector('.father');
// 給father註冊單擊事件,第3個參數爲true
father.addEventListener('click', function() {
alert('father');
}, true);
// 給document註冊單擊事件,第3個參數爲true
document.addEventListener('click', function() {
alert('document');
}, true)
</script>
官方解釋: event對象表明事件的狀態,好比鍵盤按鍵的狀態鼠標的位置、鼠標按鈕的狀態。
簡單理解:事件發生後,跟事件相關的一系列信息數據的集合都放到這個對象裏面,這個對象就是事件對象。
好比:
誰綁定了這個事件。
鼠標觸發事件的話,會獲得鼠標的相關信息,如鼠標位置。
鍵盤觸發事件的話,會獲得鍵盤的相關信息,如按了哪一個鍵。
事件觸發發生時就會產生事件對象,而且系統會以實參的形式傳給事件處理函數。
因此,在事件處理函數中聲明1個形參用來接收事件對象。
這個event是個形參,系統幫咱們設定爲事件對象,不須要傳遞實參過去。 當咱們註冊事件時,event 對象就會被系統自動建立,並依次傳遞給事件監聽器(事件處理函數) .
事件對象自己的獲取存在兼容問題:
標準瀏覽器中是瀏覽器給方法傳遞的參數,只須要定義形參 e 就能夠獲取到。
在 IE6~8 中,瀏覽器不會給方法傳遞參數,若是須要的話,須要到 window.event 中獲取查找。
只要「||」前面爲false, 無論「||」後面是true 仍是 false,都返回 「||」 後面的值。
只要「||」前面爲true, 無論「||」後面是true 仍是 false,都返回 「||」 前面的值。
<div>123</div>
<script>
var div = document.querySelector('div');
div.onclick = function(e) {
// 事件對象
e = e || window.event;
console.log(e);
}
</script>
this 是事件綁定的元素(綁定這個事件處理函數的元素) 。
e.target 是事件觸發的元素。
常狀況下terget 和 this是一致的,
但有一種狀況不一樣,那就是在事件冒泡時(父子元素有相同事件,單擊子元素,父元素的事件處理函數也會被觸發執行),
這時候this指向的是父元素,由於它是綁定事件的元素對象,
而target指向的是子元素,由於他是觸發事件的那個具體元素對象。
<div>123</div>
<script>
// 常見事件對象的屬性和方法
// 1. e.target 返回的是觸發事件的對象(元素) this 返回的是綁定事件的對象(元素)
// 區別 : e.target 點擊了那個元素,就返回那個元素 this 那個元素綁定了這個點擊事件,那麼就返回誰
var div = document.querySelector('div');
div.addEventListener('click', function(e) {
// e.target 和 this指向的都是div
console.log(e.target);
console.log(this);
});
</script>
事件冒泡下的e.target和this
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// 咱們給ul 綁定了事件 那麼this 就指向ul
console.log(this);
console.log(e.currentTarget);
// e.target 指向咱們點擊的那個對象 誰觸發了這個事件 咱們點擊的是li e.target 指向的就是li
console.log(e.target);
})
// 瞭解兼容性
// div.onclick = function(e) {
// e = e || window.event;
// var target = e.target || e.srcElement;
// console.log(target);
// }
// 2. 瞭解 跟 this 有個很是類似的屬性 currentTarget ie678不認識
</script>
html中一些標籤有默認行爲,例如a標籤被單擊後,默認會進行頁面跳轉。
<a href="http://www.baidu.com">百度</a>
<script>
// 常見事件對象的屬性和方法
// 1. 返回事件類型
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
function fn(e) {
console.log(e.type);
}
// 2. 阻止默認行爲 讓連接不跳轉
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom 標準寫法
});
// 3. 傳統的註冊方式
a.onclick = function(e) {
// 普通瀏覽器 e.preventDefault(); 方法
e.preventDefault();
// 低版本瀏覽器 ie678 returnValue 屬性
e.returnValue = false;
// 咱們能夠利用return false 也能阻止默認行爲 沒有兼容性問題
return false;
}
</script>
事件冒泡:開始時由最具體的元素接收,而後逐級向上傳播到到DOM最頂層節點。
事件冒泡自己的特性,會帶來的壞處,也會帶來的好處。
<div class="father">
<div class="son">son兒子</div>
</div>
<script>
var son = document.querySelector('.son');
// 給son註冊單擊事件
son.addEventListener('click', function(e) {
alert('son');
e.stopPropagation(); // stop 中止 Propagation 傳播
window.event.cancelBubble = true; // 非標準 cancel 取消 bubble 泡泡 兼容性作法
}, false);
var father = document.querySelector('.father');
// 給father註冊單擊事件
father.addEventListener('click', function() {
alert('father');
}, false);
// 給document註冊單擊事件
document.addEventListener('click', function() {
alert('document');
})
</script>
阻止事件冒泡的兼容性處理
事件冒泡自己的特性,會帶來的壞處,也會帶來的好處。
把事情委託給別人,代爲處理。
事件委託也稱爲事件代理,在 jQuery 裏面稱爲事件委派。
說白了就是,不給子元素註冊事件,給父元素註冊事件,把處理代碼在父元素的事件中執行。
生活中的代理:
js事件中的代理:
不是每一個子節點單獨設置事件監聽器,而是事件監聽器設置在其父節點上,而後利用冒泡原理影響設置每一個子節點。(給父元素註冊事件,利用事件冒泡,當子元素的事件觸發,會冒泡到父元素,而後去控制相應的子元素。)
以上案例:給ul註冊點擊事件,而後利用事件對象的target來找到當前點擊的li ,由於點擊li,事件會冒泡到ul上,
ul有註冊事件,就會觸發事件監聽器。
咱們只操做了一次 DOM ,提升了程序的性能。
動態新建立的子元素,也擁有事件。
<ul>
<li>知否知否,點我應有彈框在手!</li>
<li>知否知否,點我應有彈框在手!</li>
<li>知否知否,點我應有彈框在手!</li>
<li>知否知否,點我應有彈框在手!</li>
<li>知否知否,點我應有彈框在手!</li>
</ul>
<script>
// 事件委託的核心原理:給父節點添加偵聽器, 利用事件冒泡影響每個子節點
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// e.target 這個能夠獲得咱們點擊的對象
e.target.style.backgroundColor = 'pink';
})
</script>