最近恰好在學js的事件機制,寫這個是看到這篇文章提到了一個騰訊的面試題。我先把文章的代碼稍做改動貼在這裏。node
<body> <div id="outer" style="width:100%; height:200px; background-color: cornflowerblue;"> <div style="width:200px; height: 150px; background-color: pink;" id='middle'> <div style="width:100px; height: 100px; background-color: yellowgreen;" id="inner"></div> </div> </div> <script> function delegateEvent(interfaceEle, selector, type, fn) { if(interfaceEle.addEventListener) { interfaceEle.addEventListener(type, eventfn, false); } else { interfaceEle.attachEvent("on" + type, eventfn); } function eventfn(e) { var e = e || window.event; var target = e.target || e.srcElement; if(matchSelector(target, selector)) { if(fn) { fn.call(target, e); } } } } function matchSelector(ele, selector) { // if use id if(selector.charAt(0) === "#") { return ele.id === selector.slice(1); } // if use class if(selector.charAt(0) === ".") { return(" " + ele.className + " ").indexOf(" " + selector.slice(1) + " ") != -1; } // if use tagName return ele.tagName.toLowerCase() === selector.toLowerCase(); } //調用 var outer = document.getElementById("outer"); var middle = document.getElementById("middle"); delegateEvent(outer, "#middle", "click", function() { console.log('test'); }) </script> </body> 做者:一隻dororo 連接:https://www.jianshu.com/p/7ea01a3beb7a 來源:簡書 簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。
顯示效果如圖:面試
可是這段代碼有一個小問題:用鼠標點擊綠色方塊,不會輸出‘test’,這彷彿違背了咱們但願事件冒泡的初衷。
這是因爲在綁定的時候,很關鍵的一個地方在eventfn函數,它限制了只有當target就是selector匹配的元素時,纔會調用handler。
而事實上咱們在調用這個函數的時候,target是selector匹配到的元素的子節點也能夠。
在這裏介紹一個新的api,parent.contains(node),他返回一個布爾值,判斷node是否是parent節點的後代或parent自己。
所以咱們修改代碼爲:api
function delegateEvent(interfaceEle, selector, type, fn) { if(interfaceEle.addEventListener) { interfaceEle.addEventListener(type, eventfn, false); } else { interfaceEle.attachEvent("on" + type, eventfn); } function eventfn(e) { var $selector = document.querySelector(selector); var e = e || window.event; var target = e.target || e.srcElement; if(contain($selector, target)) { if(fn) { fn.call(target, e); } } } } function contain(parent, node) { if (parent.contains) { return parent.contains(node) } else { //兼容不支持contains方法的瀏覽器 while (node) { if (node === parentNode) { return true; } else { node = node.parentNode; } } return false; } }
如今再點擊綠色方塊也能夠打印'test'啦。瀏覽器