最近恰好在学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'啦。浏览器