js事件穿透实现
很多时候我们可能会遇到事件穿透这样的问题,就是说在一个元素a上面遮了另外一个元素b,b完全遮住a,然后我们在点击b的时候,如果该点击位置在a的区域内,那么同时应该触发a的相应事件。但是默认情况下,再点击b的时候就只会触发b的事件,而不会再触发a的事件。
对于这个问题css3有一个很有意思的东西pointer-events:none,其精湛的表现真的让人两眼发光。
pointer-events:none顾名思意,就是和鼠标事件说拜拜的意思。元素应用了该CSS属性,链接啊,点击啊什么的都变成了“浮云”。
而这个东西还有一个很奇特的特性,就是我们这里说的事件穿透
看起来一切似乎都很好,但是渐渐地我们发现pointer-events这个东西兼容性不是很好,对于ie10及以下的,浏览器是完全不兼容的。而且他屏蔽了当前元素的事件,如果我们想执行当前点击的元素的事件和其后面盖住元素的事件就没办法办到了。
这个时候就不得不提另外一个有趣的东西了,elementFromPoint,很陌生吧,我也是第一次见到。虽然陌生,这个东西却可以兼容到ie6,所以用它作事件穿透的兼容是再好不过了。
经过一番尝试,发现elementFromPoint每次只能取到最顶层的元素,看起来还是没办法满足我们的需求,但是对于隐藏的元素他会跳过寻找当前位置后面的一个元素,利用这个特性我们就可以实现我们的事件穿透了。
实现代码:
var Through = (function(){ var elems = [], eName, parent; function init(eventName,parentNode){ eName = eventName; parent = parentNode; bindEvents(eName,callback); } function bindEvents(eventName,callback){ var node = parent || document.body; if(document.addEventListener){ node.addEventListener(eventName,callback,false); }else if(document.attachEvent){ node.attachEvent("on"+eventName,callback); } } function recurFind(x,y){ //check current element var ele = document.elementFromPoint(x,y), nodeName = ele.tagName.toLowerCase(); if(nodeName==="body" || nodeName==="html"){ return; } elems.push(ele); ele.style.display = "none"; //check back element if(document.elementFromPoint(x,y).tagName.toLowerCase()!=="body" && ele.tagName.toLowerCase()!=="html"){ recurFind(x,y); } return; } function callback(){ var x =event.clientX, y = event.clientY; //clear old elemnts; elems = []; //loop over element in current position recurFind(x,y); elems.map(function(node){ node.style.display = "block"; }); elems.map(function(node,i){ if(i===0) return; //skip current element to prevent event repeat; node[eName](); }); } return { init : init }; })();
- 支付宝
- 微信