事件
使用者與網頁互動是透過事件實現的,事件剛開始是作為分擔伺服器負載的一個手段,起初沒有統一的規範,直到 DOM2 級,網景和 IE 才開始有各自的 API 規範。
對於事件的觸發機制,兩家公司都認為頁面的觸發機制不只是點擊了某個元素,就只觸發當前目標元素的事件。
比方說:頁面有多個同心圓,當點擊最裡面的圓時,你其實也點擊了包含這個圓外面的那些圓。 兩家公司對這點的認同是一致的,但是事件流的傳播順序上採用了不同的兩種方案來實現,即事件冒泡和事件捕獲。
IE 瀏覽器從舊版開始就一直支援事件冒泡機制,所謂事件冒泡,指事件流開始是從較為具體的元素接收,一直傳播上不具體的元素上。
就是從目標元素傳播到父級元素。
<div> <div></div> </div> <script> function childEventHandler(event) { console.log(this); console.log("child 被点击了"); } function parentEventHandler(event) { console.log(this); console.log("parent 被点击了"); } function bodyEventHandler(event) { console.log(this); console.log("body 被点击了"); } function htmlEventHandler(event) { console.log(this); console.log("html 被点击了"); } function documentEventHandler(event) { console.log(this); console.log("document 被点击了"); } function windowEventHandler(event) { console.log(this); console.log("window 被点击了"); } var bodyEl = document.getElementsByTagName("body")[0]; var htmlEl = document.getElementsByTagName("html")[0]; var win = window; var parentEl = document.getElementById("parent"); var childEl = document.getElementById("child"); childEl.onclick = childEventHandler; parentEl.onclick = parentEventHandler; bodyEl.onclick = bodyEventHandler; htmlEl.onclick = htmlEventHandler; document.onclick = documentEventHandler; win.onclick = windowEventHandler; </script>
如下圖所示,如果點擊了 id 為 child 的元素後,事件流會從 child 一直傳播到 window 物件。
#所有現代瀏覽器都支援事件冒泡。
由網景公司主導的事件捕獲則剛好和事件冒泡相反,事件流開始從不具體的元素觸發,然後傳播到具體的元素上。簡而言之就是從父級元素傳播到目標元素。
由於事件擷取是從 IE 9開始支持,不相容舊版瀏覽器,所以使用的人比較少。
DOM 規定事件包含三個階段,事件捕獲,處於目標階段、事件冒泡。
從IE 9 開始的瀏覽器規定,事件流的順序先是事件捕獲,會截獲到事件,然後是處於目標階段,實際的目標接收到事件,最後是事件冒泡,可以在這個階段對事件進行回應。
以先前的 child 元素為例,直到 child 元素接收到事件前(從 window 到 parent),都是事件擷取階段。到了 child 元素,此時對事件進行處理,隨後冒泡到 window 物件上,冒泡階段也是可以處理事件的。基於事件冒泡能處理事件的特點,接著將講到與其相關的事件委託機制。
#HTML 與事件的綁定有三種形式:
1. <div></div> 2. var childEl = document.getElementById("child"); childEl.onclick = function() { console.log('hello'); } 3. var childEl = document.getElementById("child"); childEl.addEventListener('click', function() { console.log('hello'); }, false);
JavaScript是單線程的語言,當遇到元素有事件觸發時,會在事件隊列中尋找有沒有與這個事件綁定的函數,如果沒有則什麼都不做,如果有,則將該函數放到事件隊列的前面,等待主執行緒事件執行完畢後執行。
上述程式碼第一種綁定,將事件寫在 html 中,表現和行為沒有解耦,是不建議這樣寫程式碼的。
第二種綁定,將事件綁定在元素物件上,這種寫法主要是容易發生事件的覆蓋。
第三種綁定,首先,第三個參數為布林值,預設為false, 表示在事件冒泡階段調用事件處理程序,如果為true, 則表示在事件捕獲階段調用事件處理函數。
當我們想處理完一次事件後,將不想在處理該元素的事件綁定時,應該將元素的事件綁定置為空,如果容易發生記憶體洩漏。
第一种写法: childEl.onclick = null; 第三种写法: function eventHandler() { console.log('hello'); } childEl.addEventListener('click', eventHandler, false); childEl.removeEventListener('click', eventHandler, false);
事件委託是利用事件冒泡的性質,事件流開始是從較為具體的元素接收,一直傳播上不具體的元素上。
首先,假如有一個列表 ul,每個列表元素 li 點擊會觸發事件處理程序,顯然,如果一個一個地給元素綁定事件, 效率肯定不好。
同時,當新增一個元素時,事件不見得會綁定成功。一起來看:
新增加的menu-new,點擊發現沒有反應,說明事件沒有綁定進去,但是我們也不想,每增加一個新元素,就為這個新元素綁定事件,重複低效率的工作應避免去做。
我们通过事件委托的思路来想,事件流的传播,目标元素本身依然会有事件,但同时,冒泡出去后,更高层次的 dom 也能处理事件程序。那么,我们只需要给高层次节点绑定事件,通过判断具体是触发的哪个子节点,再做相应的事件处理。
menu 列表的每个子菜单元素的事件都能正确响应,新增的 menu-new 同样也能正确响应事件。
事件委托的好处在于,我们不用给每个元素都一一地手动添加绑定事件,避免重复低效的工作。
其次,事件委托更少得获取 dom, 初始化元素对象和事件函数,能有效减少内存占用。
每当将事件程序指定给元素时,html 代码和 js 代码之间就建立了一个连接,这种连接越多,网页就执行起来越慢,所以事件委托能有效减少连接树,提高网页性能。
用户与网页的交互是通过事件进行的,事件模型分为事件冒泡和事件捕获,事件冒泡的兼容性更好,应用更广,同时通过事件冒泡,可以建立事件委托,提升网页性能。
以上是JavaScript中事件模型的詳解(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!