當用戶與瀏覽器發生的一些交互時, 若是但願去得到用戶行爲, 就須要藉助事件來完成. 事件部份內容在 JS中重要性不言而喻. html
羅列須要瞭解與事件相關的知識以下: 這也是面試中遇到的問題.面試
要想明白事件流,必須先懂的這幾個知識點後端
先來看一個有趣的問題, 這是 4
代瀏覽器(IE4)開發團隊遇到一個的問題:瀏覽器
What part of the Webpage owns a specific event?
頁面的哪一部分會擁有某個特定的事件?框架
要想明白這個問題能夠想象成在一個頁面上畫了一組同心圓, 當手指放在中間時,它不只在一個圓圈內,並且在全部的圓圈內。
以下圖所示:函數
這就是瀏覽器事件的工做原理, 當你點擊一個按鈕時, 不只單擊按鈕,還單擊包含的容器和整個頁面。工具
事件生命週期, 分爲三個階段: capturing
(捕獲), target
(目標), bubbling
(冒泡). 而這三個階段也是構成事件流基本部分. 開發工具
這種處理思想, 在如今流行 NodeJS
後端框架 Koa
對中間件的處理模式也是基於這種, 熟悉Koa
或許對這洋蔥圖
並不會陌生:this
先來熟悉事件的模型:spa
事件冒泡: 既事件開始由最具體的元素接收,而後逐級向上傳播最後到達 Document 對象 或 window 上.
先來看一個簡單的示例, 代碼以下:
<!DOCTYPE HTML> <html> <head> <title>......</title> </head> <body> <div id="demo"> Press here.</div> </body> </html>
var target = document.getElementById("demo"); window.addEventListener("click", function(){ console.log("window bubbling"); }); document.addEventListener("click", function(){ console.log("document bubbling"); }); document.documentElement.addEventListener("click", function(){ console.log("html bubbling"); }); document.body.addEventListener("click", function(){ console.log("body bubbling"); }); target.addEventListener("click", function(){ console.log("target bubbling"); });
控制檯打印輸出以下:
"target bubbling" "body bubbling" "html bubbling" "document bubbling" "window bubbling"
當一個div
被點擊, 這點擊事件發生的順序以下:
從執行順序來講, click事件
首先在 div
元素上觸發, 而後沿着DOM Tree 向上傳播, 在路徑上的每一個節點上觸發,直到它到達文檔對象(或Window對象)。
事件捕獲
是另一種事件流模型, 最早由 Netscape Browser 引入.
根據上面的的模型, 恰好與前面冒泡相反. 根據該模型,最不特定(最外層)的節點首先接收事件,而最特定(目標元素)的節點最後接收事件.
它設計的目標就是在事件到達目標以前,事先進行攔截.
參考前面的示例, 修改下監聽方式, 代碼修改以下:
var target = document.getElementById("demo"); window.addEventListener("click", function(){ console.log("window Capturing"); }, true); document.addEventListener("click", function(){ console.log("document Capturing"); }, true); document.documentElement.addEventListener("click", function(){ console.log("html Capturing"); }, true); document.body.addEventListener("click", function(){ console.log("body Capturing"); }, true); target.addEventListener("click", function(){ console.log("target Capturing"); }, true);
打印的結果:
"window bubbling" "document bubbling" "html bubbling" "body bubbling" "target bubbling"
當點擊 div
元素, 按照以下順序來進行廣播事件.
注意:
DOM0
級中默認就是使用冒泡的方式, 不支持捕獲的. 因此在DOM2
級中經過addEventListener
提供的第三個參數來控制使用哪一種事件流來處理.
根據上面兩種模型, 能夠總結完整事件流應該向以下:
DOM Level 2 Events 指定的事件流模型分爲三個階段:
從上面流程圖中, 首先發生的是 事件捕獲階段
爲截獲事件提供了機會, 再到目標階段
而後進入 事件冒泡階段
, 能夠在這個階段對事件進行響應.
引用
前面的例子, 點擊 DIV
元素時, 事件將按照上圖順序進行觸發.
這就是完整的事件流, 內容看起來挺多的, 實際上一句話就概述事件流.
用來描述事件發生順序(頁面接收事件順序).
經過前面的知識點, 事件
就是表示用戶或瀏覽器自身執行某種動做. 例如: click
, dbclick
, load
, unload
, mouseover
,mouseout
, mouseenter
,mouseleave
等等, 這些都是事件的名字
. 而響應並處理某個事件的函數稱爲 事件處理程序(或事件監聽器(觀察者模式))
.
常見事件處理方式包括以下幾種:
直接來看個簡單示例:
<input type="button" onclick="alert('<Clicked')"/>
這種模式, 能夠理解爲 CSS 行內樣式
,
<div style="color: #ccc;"></div>
直接在 HTML 元素上綁定相應事件名, 並指定對應的事件處理程序. 從前面語法來講, 事件處理程序是一個函數
, 上面傳遞是一個語句, 也就是說默認執行時, JS引擎會進行相應處理. 等價於這種方式:
<input type="button" onclick="(function(){alert('Clicked')})()"/>
若是把事件處理函數直接以這種內聯值
的方式提供, 應該注意不能值中指定未經轉義的HTML語法字符
例如: 和號(&) 、雙引號("") 等等, 不然會解析出錯.
如上面示例,若是想使用雙引號, 必須這麼處理.
<input type="button" onclick="alert("Clicked")"/>
這種對於簡單語句還行, 除了提供元素屬性值的方式, 那麼有木有其它方式咧? 答案:固然有 , HTML事件處理程序能夠調用在頁面其它地方定義的腳本.
示例以下:
<input type="button" onclick="handleClick()"/> <script> function handleClick(){ alert("Clicked"); } </script>
經過這種方式指定事件處理程序具備一些特別的地方.
event
, 也就是事件對象.<input type="button" onclick="alert(event)"/> // => 等價 <input type="button" onclick="(function(){var e = event; alert(e);})()"/>
this
指針表示是當前的目標對象<input type="button" onclick="alert(this)"/> // this === [object HTMLInputElement] === input元素
這樣能夠經過 this
來獲取目標元素相關的內容了. 好比取值
<input type="button" onclick="alert(this.value)"/> <!--或簡寫成這樣--> <input type="button" value="Click Me" onclick="alert(value)"/>
爲何能夠簡寫方式, input 對象是存在於當前函數的做用域鏈中(scope). 爲了調試方式, 把上面方式做以下改變
<input type="button" value="Click Me" onclick="(function aa(){debugger;console.log(value)})()"/>
其實理解上面那句話, 咱們能夠藉助開發這工具來協助理解:
input
對象會被添加在當前匿名函數執行的做用域鏈上.根據開發工具來看, 咱們是能夠模擬引擎幫作的事情, 僞代碼以下:
function () { with(document) { with(input){ // dosomething console.log(value); } } }
本質經過 with
來擴展做用域.
上面把基本內容說, 那麼這種經過HTML事件處理程序有什麼問題麼 ?
事件處理程序必須優先元素加載, 有可能DOM加載出來, 用戶就開始操做, 此時事件處理程序可能未加載致使報錯
引用前面的示例:
<input type="button" onclick="handleClick()"/> <script> function handleClick(){ alert("Clicked"); } </script>
若是用戶想把函數名爲: "onClick", 這時是否是須要同時去修改.
未完, 後續...