在Web中, 事件在瀏覽器窗口中被觸發,執行事先綁定的事件處理器(也就是事件觸發時會運行的代碼塊),對事件作出響應。
用戶在瀏覽器的任何一個操做都會去觸發一個事件,JavaScript採用異步事件驅動編程模型,當文檔、瀏覽器、元素或與之相關對象發生特定事情時,瀏覽器會產生事件。css
事件是某個行爲或者觸發,好比點擊、鼠標移動、提交表單,滾動菜單等等html
事件流描述的是從頁面中接收事件的順序,好比有兩個嵌套的div,點擊了內層的div,這時候是內層的div先觸發click事件仍是外層先觸發?node
若是事件不傳播,咱們沒法肯定咱們點擊的對象是什麼?編程
事件開始時由最具體的元素接收,而後逐級向上傳播到較爲不具體的元素。好比點擊div時,首先是div先監聽到了點擊事件,而後向上傳播到body/html/documentsegmentfault
和事件冒泡相反,事件最開始由最外層不太具體的節點先監聽到,而後向下傳遞到最具體的元素。
好比點擊div事件,先是document監聽到,而後分發到html/body/div數組
DOM2級事件規定事件流包括三個階段,首先發生的是事件捕獲,爲截取事件提供機會,而後是實際目標接收事件,最後是冒泡階段瀏覽器
demoapp
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JS Bin</title> <style> .box1{ border:1px solid black; padding:10px; } </style> </head> <body> <div class="container box1"> container <div class="box box1"> box <div class="target box1">target</div> </div> </div> </body> <script> var container= document.querySelector('.container') var box= document.querySelector('.box') var target=document.querySelector('.target') target.addEventListener('click',function(){ console.log('target in 捕獲') },true) box.addEventListener('click',function(){ console.log('box in 捕獲') },true) container.addEventListener('click',function(){ console.log('container in 捕獲') },true) target.addEventListener('click',function(){ console.log('target in 冒泡') },false) box.addEventListener('click',function(){ console.log('box in 冒泡') },false) container.addEventListener('click',function(){ console.log('container in 冒泡') },false) </script> </html>
執行結果:dom
![圖片上傳中...]異步
事件處理程序:事件觸發後,執行響應對應事件的程序。
事件處理程序是預先設定的,咱們須要提早定義好某些事件發生了該怎麼處理,這個過程叫作綁定事件處理程序
2.1原理:
JavaScript指定事件處理程序就是把一個函數賦值給一個元素的事件處理程序屬性(如onclick)
2.2綁定的過程:
選中元素,選中事件處理程序屬性如onclick,給屬性賦值一個處理函數。
<input id="btnClick" type="button" value="Click Here" /> <script > var btnClick = document.getElementById('btnClick'); btnClick.onclick = function showMessage() { alert(this.id); }; </script>
2.3不足:
不能給同一個元素的同一個事件處理程序屬性綁定多個事件處理函數,會產生覆蓋的。
3.1簡介
DOM2事件處理程序能夠解決不能綁定多個事件處理函數的問題
DOM2級事件定義了兩個方法用於處理指定和刪除事件處理程序的操做:
3.2 addEventListener使用
addEventListener有三個參數
3.3舉個栗子
<input id="btnClick" type="button" value="Click Here" /> <script > var btnClick = document.getElementById('btnClick'); btnClick.addEventListener('click', function() { alert(this.id); }, false); </script>
總結:addEventListener 和制定事件處理程序的不一樣,一個是對屬性賦值,另一個addEventListener是執行一個函數,能夠屢次執行
3.4 removeEventListener解綁事件
經過addEventListener添加的事件處理程序只能經過removeEventListener移除,移除時參數與添加的時候相同
添加的匿名函數沒法移除
<input id="btnClick" type="button" value="Click Here" /> <script > var btnClick = document.getElementById('btnClick') var handler=function() { console.log("hhhhhhhhh") } btnClick.addEventListener('click', handler, false) btnClick.removeEventListener('click', handler, false) </script>
在觸發DOM上的某個事件的時候會產生一個事件對象event,這個對象包含着全部與事件有關的信息,包括產生事件的元素、事件類型等相關信息。
event對象包含與建立它的特定事件有關的屬性和方法,觸發事件的類型不一樣,可用的屬性和方法也不一樣,可是全部事件都會包含
2.1bubbles:
默認爲false,表示事件對象是否冒泡。
若是該屬性爲false,div.addEventListener方法在冒泡階段監聽不會觸發。只能寫成div.addEventListener('click', callback, true)在「捕獲階段」監聽這個事件。
2.2cancelable:
默認爲false,表示事件是否能夠被取消.只有爲true的時候,才能用Event.preventDefault()取消這個事件。
2.3preventDefault
阻止默認事件
<a href="http://baid.com">baidu</a> <script> document.querySelector('a').onclick= function(e){ e.preventDefault() console.log(this.href) if(/baidu.com/.test(this.href)){ location.href = this.href } } </script>
<form action="/login"> <input type="text" name="username"> <input type="submit"> </form> <script> document.querySelector('form').addEventListener('submit',function(e){ e.preventDefault() if(document.querySelector('input[name=username]').value==='sjz'){ this.submit() } }) </script>
2.4target和currenttarget
在事件處理程序內部,this始終等同於currentTarget,currentTarget爲綁定事件的元素,而target是爲觸發事件的實際目標。
當存在嵌套的時候,二者不同,具體詳情能夠見這篇文章連接描述,或者中文版event.target 和 event.currentTarget。我這裏不作贅述
2.5stopPropagation()
阻止事件在 DOM 中繼續傳播,防止再觸發定義在別的節點上的監聽函數,可是不包括在當前節點上其餘的事件監聽函數。
舉個栗子
<style> .container, .box, .target{ border: 1px solid; padding: 10px; } </style> <button id="btn">click</button> <div class="container"> container <div class="box"> box <div class="target">target</div> </div> </div> <script> function $(selector){ return document.querySelector(selector) } var btn = $('#btn') btn.onclick = function (e){ console.log(e) } btn.addEventListener('click', function(evt){ console.log(this) console.log(btn) console.log(evt.target) }) $('.container').addEventListener('click', function(e){ console.log('contianer click.. in 捕獲階段') }, true) $('.box').addEventListener('click', function(e){ //e.stopPropagation() console.log('box click.. in 捕獲階段') }, true) $('.target').addEventListener('click', function(e){ console.log('target click.. in 捕獲階段') }, true) $('.container').addEventListener('click', function(e){ console.log('contianer click.. in 冒泡階段') }, false) $('.box').addEventListener('click', function(e){ //e.stopPropagation() console.log('box click.. in 冒泡階段') }, false) $('.target').addEventListener('click', function(e){ console.log('target click.. in 冒泡階段') }, false) </script>
結果
沒有給捕獲階段的box加e.stopPropagation()的結果
給捕獲階段的box加e.stopPropagation()以後的結果
哈哈哈寫事件代理前,找到了這篇事件代理的文章用例子解釋事件模型和事件代理,這裏寫事件模型的歷史也寫得至關棒,因此先就轉載過來了。
利用事件模型的傳播性質,將子元素的監聽函數綁定到父元素上,經過事件傳播去執行監聽函數。
需求:給container裏面全部box都綁定點擊事件,點擊時輸出box的值
2.1方式一:foreach
原理:選中.box全部元素,獲得一個類數組對象,遍歷這個類數組對象,給.box元素一一綁click事件。
代碼:
<div class="container"> <div class="box">box1</div> <div class="box">box2</div> <div class="box">box3</div> </div> <script> function $(selector){ return document.querySelector(selector) } function $$(selector){ return document.querySelectorAll(selector) } // $$('.box').forEach(function(node){ // node.onclick = function(){ // console.log(this.innerText) // } // })
結果
缺點:執行foreach選中的box時固定的,若是咱們後續再加上幾個box,後加的box就沒有綁定上點擊事件。
代碼連接
2.2方式二事件代理
原理:給container綁定點擊事件,經過e.target獲取點擊事件目標
代碼:
<div class="container"> <div class="box">box1</div> <div class="box">box2</div> <div class="box">box3</div> </div> <button id="add">add</button> <script> function $(selector){ return document.querySelector(selector) } function $$(selector){ return document.querySelectorAll(selector) } $('.container').onclick = function(e){ console.log(this) console.log(e.target) if(e.target.classList.contains('box')){//contain少寫s console.log(e.target.innerText) } } var i = 4 $('#add').onclick = function(){ var box = document.createElement('div') box.classList.add('box') box.innerText = 'box' + (i++) $('.container').appendChild(box)//box加'' }
遇坑:
一、contain少寫s
常見事件類型 | 解析 |
---|---|
click | 單擊 |
dblclick | 雙擊 |
focus | 焦點,好比表單input把光標放上去開始輸入的時刻 |
blur | 失去焦點,好比輸入完成切換到下一個輸入框時,就失去了焦點 |
keyup | 按鍵按下鬆開的時候觸發, |
change | 好比input失去焦點而且值發生了改變 |
submit | 表單提交的時候觸發 |
scroll | 頁面滾動的時候觸發,注意使用函數節流 |
resize | 頁面面積變化觸發,注意使用函數節流 |
DOMContentLoaded | DOM 結構解析完成,不用等圖片解析 |
load | 頁面全部資源(圖片css 等)加載完成觸發,觸發時間比較晚 |
mouseover | 鼠標放上去觸發,注意進入元素的子元素會重複觸發 |
mouseout | 鼠標拿出去觸發,注意離開元素的子元素會重複觸發 |
mouseenter | 鼠標進入觸發,進入子元素不會觸發,比較經常使用 |
mouseleave | 鼠標離開觸發,離開子元素不會觸發,比較經常使用 |
演示代碼:直接複製代碼到編輯器,在瀏覽器去測試這些事件
或者點擊這個連接測試
<button id="btn">點我</button> <button id="btn1">點我1</button> <div class="ct" style="font-size: 20px"> <div class="box">hello</div> </div> <div class="ct1"> <div class="box1"></div> </div> <input id="input-name" type="text"> <form id="form" action="/upload"> <input id="username" name="username" type="text"> <p class="msg"></p> <input id="btn-submit" type="submit" value="註冊"> </form> <img src="https://jirengu.com/data/upload/2017/0118/17/587f39fba695a.png" alt=""> <script> function $(selector){ return document.querySelector(selector); } $('#btn').addEventListener('click', function(){ console.log('click') console.log(this) }) $('#btn1').addEventListener('dblclick', function(){ console.log('dblclick') console.log(this) }) $('.ct').addEventListener('mouseover', function(){ console.log('mouseover') console.log(this) // this.style.borderColor = 'blue' this.classList.add('hover') }) $('.ct').addEventListener('mouseout', function(){ console.log('mouseout...') // this.style.borderColor = 'red' this.classList.remove('hover') }) $('.ct1').addEventListener('mouseenter', function(){ console.log('mouseenter...') //this.style.borderColor = 'blue' this.classList.add('hover') }) $('.ct1').addEventListener('mouseleave', function(){ console.log('mouseleave...') //this.style.borderColor = 'blue' this.classList.remove('hover') }) $('#input-name').addEventListener('focus', function(){ console.log('focus...') console.log(this.value) }) $('#input-name').addEventListener('blur', function(){ console.log('blur...') console.log(this.value) }) $('#input-name').addEventListener('keyup', function(e){ console.log('keyup...') console.log(this.value) console.log(e) this.value = this.value.toUpperCase() }) $('#input-name').addEventListener('change', function(e){ console.log('change...') console.log(this.value) console.log(e) this.value = this.value.toUpperCase() }) $('#form').addEventListener('submit', function(e){ e.preventDefault(); if(/^\w{6,12}$/.test($('#username').value)){ $('#form').submit(); }else{ $('#form .msg').innerText = '出錯了' $('#form .msg').style.display = 'block' console.log(' no submit...'); } }) window.addEventListener('scroll', function(e){ console.log('scroll..') }) window.addEventListener('resize', function(e){ console.log('resize..') }) //頁面全部資源加載完成 window.onload = function(){ console.log('window loaded') } //DOM 結構解析完成 document.addEventListener('DOMContentLoaded', function(){ console.log('DOMContentLoaded ') }) console.log($('img').width) //0 $('img').onload = function(){ console.log(this.width) //此時才能獲得圖片的真實大小 } </script> <style> body{ color: blue; } .ct,.ct1{ width: 100px; height: 100px; border: 1px solid red; background-color: yellow; margin: 20px; } .box,.box1{ width: 50px; height: 50px; background-color: blue; } .ct.hover, .ct1.hover{ border-color: blue; background-color: pink; } .box3{ list-style: none; background: yellow; margin: 0; padding: 0; } .box3>li{ background: pink; margin: 5px; padding: 10px; } .box3>li.hover{ background-color: blue; } .msg{ display: none; } </style>
var EventCenter = { on: function(type, handler){ document.addEventListener(type, handler) }, fire: function(type, data){ return document.dispatchEvent(new CustomEvent(type, { detail: data })) } } EventCenter.on('hello', function(e){ console.log(e.detail) }) EventCenter.fire('hello', '你好')