新的一天又開始了,咱們對今天對將來抱有很大期待,因此開始咱們今天的學習吧,在此以前來點題外話,仍是愛好問題。javascript
週三的面試雖然失敗,可是也是頗有啓迪的,好比以前我就歷來沒有想過愛好問題,我發現個人愛好以下:css
① 霹靂布袋戲html
完了就米有什麼愛好了,其實我徹底能夠說本身愛好旅遊什麼的,我也確實愛好旅遊,只不過比較窮,走的地方很少罷了,這裏又扯出一個話題:java
學習工做與生活jquery
咱們爲了理想須要學習須要工做,工做完了須要生活,如今是前者份量掩蓋了後者,因此之後的世界要注意了。面試
好了進入今天的學習吧,咱們今天來看看javascript裏面的事件吧。瀏覽器
javascript與html之間的交互是經過事件實現的,咱們使用偵聽器註冊事件,
在事件發生時候便執行相關的代碼,這就是傳說中的觀察者模式
事件捕獲與冒泡的出現十分有意思,當瀏覽器發展到第四代時(IE4),出現了一個小意思的問題:框架
頁面的哪一部分有什麼事件?瀏覽器開發團隊也不知道了,想象咱們頁面的元素:dom
1 <div> 2 <a>刀狂劍癡<span>葉小釵</span> </a> 3 </div>
咱們點擊span時候是否是也點擊了a呢?點擊a是否是也點擊了div呢,依次上升到body與html函數
事件流描述的是從頁面中接收事件的順序
IE採用事件冒泡流
標準採用事件捕獲流
最後addEventLister給出了第三個參數同時支持冒泡與捕獲
事件冒泡
由span開始一直傳播至document
事件捕獲
由document向下傳播至span
事件就是用戶或者瀏覽器自身執行某種動做,好比click、load、mouseover。
而響應某個事件的函數就叫作事件處理程序(事件監聽器),事件處理程序的名字以on開頭,click=>onclick、load=>onload
1 el.addEventListener(eventType, function () { 2 3 }, false); 4 5 該方法應用至dom節點 6 第一個參數爲事件名 7 第二個爲事件處理程序 8 第三個爲布爾值,true即是事件捕獲,false爲事件冒泡
既然都說到了addEventLister,咱們來看一看這段代碼吧:
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 </head> 5 <body> 6 <div> 7 <a>刀狂劍癡<span id="el">葉小釵</span> </a> 8 </div> 9 <script type="text/javascript"> 10 var el = document.getElementById('el'); 11 el.addEventListener('click', function () { 12 alert('冒泡'); 13 }, false); 14 el.addEventListener('click', function () { 15 alert('捕獲'); 16 }, true); 17 </script> 18 </body> 19 </html>
咱們同時給一個dom綁定了click事件,而且一個是冒泡,一個是捕獲,咱們的執行順序是怎麼樣的呢?
答案一:先冒泡再捕獲
可是答案真的是這樣的嗎?咱們將代碼改下:
1 var el = document.getElementById('el'); 2 el.addEventListener('click', function () { 3 alert('捕獲'); 4 }, true); 5 el.addEventListener('click', function () { 6 alert('冒泡'); 7 }, false);
如此一來即是先捕獲再冒泡了,我想說這道題真的好耍賴啊。。。。
那麼如今咱們是離真相近了仍是遠了呢?其實真相依舊撲所迷離:
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 </head> 5 <body> 6 <div> 7 <a id="p">刀狂劍癡<span id="el">葉小釵</span> </a> 8 </div> 9 <script type="text/javascript"> 10 var el = document.getElementById('el'); 11 var p = document.getElementById('p'); 12 //el.addEventListener('click', function () { 13 // alert('捕獲'); 14 //}, true); 15 //el.addEventListener('click', function () { 16 // alert('冒泡'); 17 //}, false); 18 p.addEventListener('click', function () { 19 alert('父級 冒泡'); 20 }, false); 21 p.addEventListener('click', function () { 22 alert('父級 捕獲'); 23 }, true); 24 </script> 25 </body> 26 </html>
此處會出現兩種狀況:
① 直接點擊a標籤,便與以前邏輯一致,哪一個定義到前面哪一個先執行
② 點擊span標籤狀況會有所不一樣!!!
咱們來理一理:
由於咱們span標籤沒有註冊事件,咱們點擊時候他雖然沒有反應,可是他也會向上傳遞的:
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 </head> 5 <body> 6 <div> 7 <a id="p">刀狂劍癡<span id="el" onclick="alert('點擊');">葉小釵</span> </a> 8 </div> 9 <script type="text/javascript"> 10 var el = document.getElementById('el'); 11 var p = document.getElementById('p'); 12 13 p.addEventListener('click', function () { 14 alert('父級 冒泡'); 15 }, false); 16 p.addEventListener('click', function () { 17 alert('父級 捕獲'); 18 }, true); 19 20 //el.addEventListener('click', function () { 21 // alert('捕獲'); 22 //}, true); 23 //el.addEventListener('click', function () { 24 // alert('冒泡'); 25 //}, false); 26 </script> 27 </body> 28 </html>
咱們這個代碼執行的順序是:父級捕獲=>點擊=>父級冒泡
說明,點擊span引起的事件便與事件註冊程序的前後無關了,我這裏斗膽的猜想一下整個邏輯:
標準瀏覽器默認採用捕獲方式,因此:
咱們點擊span時候,事實上市先點擊document而後到span,中間通過了a標籤便先執行其邏輯(將事件寫到標籤中不合適)
1 var el = document.getElementById('el'); 2 var p = document.getElementById('p'); 3 4 p.addEventListener('click', function () { 5 alert('父級 冒泡'); 6 }, false); 7 p.addEventListener('click', function () { 8 alert('父級 捕獲'); 9 }, true); 10 el.addEventListener('click', function () { 11 alert('冒泡'); 12 }, false); 13 el.addEventListener('click', function () { 14 alert('捕獲'); 15 }, true);
這段javascript的執行順序是(點擊span):父級捕獲=>冒泡=>捕獲=>父級冒泡
各位看看這段東西有問題沒有,上次要答好寒冬老師這個問題是不可能的。。。
這個問題暫時到這裏,如果後面討論的朋友多咱們再研究吧。
【初窺javascript奧祕之事件冒泡】那些年咱們一塊兒冒的泡
請使用高版本瀏覽器
咱們知道這塊的兼容性有一點問題,因此咱們通常都會封裝下的,可是裏面的event對象已經target的獲取各位就本身想辦法處理下吧:
1 var EventUtil = { 2 addHandler: function (el, type, handler) { 3 if (el.addEventListener) { 4 el.addEventListener(type, handler, false); 5 } else { 6 el.attachEvent('on' + type, handler); 7 } 8 }, 9 removeHandler: function (el, type, handler) { 10 if (el.removeEventListener) { 11 el.removeEventListerner(type, handler, false); 12 } else { 13 el.detachEvent('on' + type, handler); 14 } 15 } 16 };
按道理說,咱們原本可使用call方法將this指向以及event傳進去,完全解決這塊兼容問題,可是又涉及到刪除時候刪不掉而致使性能問題,咱們仍是老老實實用jquery吧。
真的能寫本身框架的話,這塊到能夠好好研究一番!
咱們前面常常提到事件對象event,那麼他是什麼呢?
觸發dom上某個事件時,會產生一個事件對象event,這個對象包含着與事件有關的信息
① 致使事件的元素
② 事件類型
③ 特定信息(鼠標信息,鍵盤信息)
......
這個對象包含太多信息,我這裏也記不住,因而挑幾個重要的來講吧:
① currentTarget dom 事件處理程序當前正在處理事件的那個元素(始終等於this)
② preventDefault function 取消事件默認行爲
③ stopPropagation function 取消事件冒泡
④ target dom 事件的目標(這個與currentTarget不是很好區分哦,currentTarget可能發生變化target卻不會)
這裏關於currentTarget與target可能有些朋友沒有分清楚,咱們上個代碼吧:
1 EventUtil.addHandler(document, 'click', function (e) { 2 e = window.event || e; 3 var target = e.target || e.srcElement; 4 //操做 5 //此處currentTarget便等於this 6 //target即是咱們點擊的元素 7 alert(e.currentTarget); //HTMLDocument 8 alert(target); //HTMLSpanElement 9 });
來吧搞點兼容的代碼,反正不吃虧:
1 var EventUtil = { 2 addHandler: function (el, type, handler) { 3 if (el.addEventListener) { 4 el.addEventListener(type, handler, false); 5 } else if (el.attachEvent) { 6 el.attachEvent('on' + type, handler); 7 } else { 8 el['on' + type] = handler; 9 } 10 }, 11 removeHandler: function (el, type, handler) { 12 if (el.removeEventListener) { 13 el.removeEventListerner(type, handler, false); 14 } else if (el.detachEvent) { 15 el.detachEvent('on' + type, handler); 16 } else { 17 el['on' + type] = null; 18 } 19 }, 20 getEvent: function (e) { 21 return e ? e : window.event; 22 }, 23 getTarget: function (e) { 24 return e.target ? e.target : e.srcElement; 25 }, 26 preventDefault: function (e) { 27 if (e.preventDefault) { 28 e.preventDefault(); 29 } else { 30 e.returnValue = false; 31 } 32 }, 33 stopPropagation: function (e) { 34 if (e.stopPropagation) { 35 e.stopPropagation(); 36 } else { 37 e.cancelBubble = true; 38 } 39 } 40 };
咱們通常有這幾類事件:
① UI用戶界面事件
當用戶與頁面上元素髮生交互時觸發
② 焦點事件
當元素獲取/失去焦點時觸發
③ 鼠標事件
鼠標操做引起的事件
④ 滾輪事件
鼠標滾輪引發的事件,相似的也算
⑤ 文本事件
text類型的操做
⑥ 鍵盤事件
......
咱們下面來看看咱們的各個事件吧。
load事件
當頁面所有加載後在window上觸發,當全部框架都加載完畢時在框架集上觸發,當img加載結束後在img上觸發。
javascript中這個傢伙很是常見,頁面徹底加載後(圖片、js、css)就會觸發,來一個圖片加載結束後的提示吧:
1 EventUtil.addHandler(img, 'load', function (e) { 2 e = EventUtil.getEvent(e); 3 alert(EventUtil.getTarget(e).src + ' 加載結束'); 4 });
PS:此處的加載與咱們jquery的document.ready有所不一樣,一個是圖片所有加載結束執行,一個是dom與css造成render樹便開始執行,後者是咱們但願的。
unload
這個事件與load對應,咱們卻用到很少,在文檔徹底卸載後觸發(頁面切換也會觸發)。
這個傢伙通常用於釋放資源的,咱們通常不須要關注。
resize
這個事件咱們也用得不少,當瀏覽器高度或者寬度變化時就會觸發(這個時候也會引發頁面迴流reflow哦),事件在window上觸發。
這個事件中的代碼可能會被頻繁執行,因此定義時候必定要注意。
scroll
滾動條滾動時候觸發
焦點事件
① blur: 事情焦點時候觸發,不會冒泡
② focus: 獲取焦點時候觸發,不會冒泡
其它的略去
鼠標事件
事件不少......
後面還有不少新增的事件,我這裏先無論啦。。。等接觸到移動開發再研究吧,今天暫時這樣。
今天咱們一塊兒學習了javascript的事件流,各位有所得麼?