首頁 >web前端 >js教程 >JavaScript中事件模型的詳解(程式碼範例)

JavaScript中事件模型的詳解(程式碼範例)

不言
不言轉載
2018-11-21 11:47:411615瀏覽
這篇文章帶給大家的內容是關於JavaScript中事件模型的詳解(程式碼範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

事件

#

使用者與網頁互動是透過事件實現的,事件剛開始是作為分擔伺服器負載的一個手段,起初沒有統一的規範,直到 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 物件。

JavaScript中事件模型的詳解(程式碼範例)

JavaScript中事件模型的詳解(程式碼範例)

#所有現代瀏覽器都支援事件冒泡。

二、事件捕獲

由網景公司主導的事件捕獲則剛好和事件冒泡相反,事件流開始從不具體的元素觸發,然後傳播到具體的元素上。簡而言之就是從父級元素傳播到目標元素。

JavaScript中事件模型的詳解(程式碼範例)

由於事件擷取是從 IE 9開始支持,不相容舊版瀏覽器,所以使用的人比較少。

三、事件流

DOM 規定事件包含三個階段,事件捕獲,處於目標階段、事件冒泡。

從IE 9 開始的瀏覽器規定,事件流的順序先是事件捕獲,會截獲到事件,然後是處於目標階段,實際的目標接收到事件,最後是事件冒泡,可以在這個階段對事件進行回應。

以先前的 child 元素為例,直到 child 元素接收到事件前(從 window 到 parent),都是事件擷取階段。到了 child 元素,此時對事件進行處理,隨後冒泡到 window 物件上,冒泡階段也是可以處理事件的。基於事件冒泡能處理事件的特點,接著將講到與其相關的事件委託機制。

JavaScript中事件模型的詳解(程式碼範例)

四、事件綁定

#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-1
  •     
  • menu-2
  •     
  • menu-3
  •     
  • menu-4
<script> window.onload = function() { var menu = document.getElementById("menu"); var item = menu.getElementsByClassName(&#39;menu-item&#39;); for (var i = 0; i < item.length; i++) { item[i].onclick = (function(i) { return function() { console.log(i); } }(i)) } var addBtnEl = document.getElementById("addBtn"); addBtnEl.onclick = function() { var newEl = document.createElement(&#39;li&#39;); newEl.innerHTML = "menu-new" menu.appendChild(newEl); } } </script>

新增加的menu-new,點擊發現沒有反應,說明事件沒有綁定進去,但是我們也不想,每增加一個新元素,就為這個新元素綁定事件,重複低效率的工作應避免去做。

我们通过事件委托的思路来想,事件流的传播,目标元素本身依然会有事件,但同时,冒泡出去后,更高层次的 dom 也能处理事件程序。那么,我们只需要给高层次节点绑定事件,通过判断具体是触发的哪个子节点,再做相应的事件处理。


        
  • menu-1
  •     
  • menu-2
  •     
  • menu-3
  •     
  • menu-4
<script> window.onload = function() { var menu = document.getElementById("menu"); menu.onclick = function(event) { var e = event || window.event; var target = e.target || e.srcElement; console.log(e); switch (target.textContent) { case "menu-1": console.log("menu-1 被点击了"); break; case "menu-2": console.log("menu-2 被点击了"); break; case "menu-3": console.log("menu-3 被点击了"); break; case "menu-4": console.log("menu-4 被点击了"); break; case "menu-new": console.log("menu-new 被点击了"); break; } } var addBtnEl = document.getElementById("addBtn"); addBtnEl.onclick = function() { var newEl = document.createElement(&#39;li&#39;); newEl.innerHTML = "menu-new" menu.appendChild(newEl); } } </script>

menu 列表的每个子菜单元素的事件都能正确响应,新增的 menu-new 同样也能正确响应事件。

事件委托的好处在于,我们不用给每个元素都一一地手动添加绑定事件,避免重复低效的工作。

其次,事件委托更少得获取 dom, 初始化元素对象和事件函数,能有效减少内存占用。

每当将事件程序指定给元素时,html 代码和 js 代码之间就建立了一个连接,这种连接越多,网页就执行起来越慢,所以事件委托能有效减少连接树,提高网页性能。

总结

用户与网页的交互是通过事件进行的,事件模型分为事件冒泡和事件捕获,事件冒泡的兼容性更好,应用更广,同时通过事件冒泡,可以建立事件委托,提升网页性能。

以上是JavaScript中事件模型的詳解(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除