js事件穿透实现

原创 Dean 工作笔记 二维码阅读
2016-06-15 08:24

很多时候我们可能会遇到事件穿透这样的问题,就是说在一个元素a上面遮了另外一个元素b,b完全遮住a,然后我们在点击b的时候,如果该点击位置在a的区域内,那么同时应该触发a的相应事件。但是默认情况下,再点击b的时候就只会触发b的事件,而不会再触发a的事件。你可以狠狠地戳这里:正常点击Demo

对于这个问题css3有一个很有意思的东西pointer-events:none,其精湛的表现真的让人两眼发光。

pointer-events:none顾名思意,就是和鼠标事件说拜拜的意思。元素应用了该CSS属性,链接啊,点击啊什么的都变成了“浮云”。

你可以狠狠地戳这里:鼠标禁止Demo

而这个东西还有一个很奇特的特性,就是我们这里说的事件穿透

你可以狠狠地戳这里:pointerEvents事件穿透Demo

看起来一切似乎都很好,但是渐渐地我们发现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 };
})();

你可以狠狠地戳这里:elementFromPoint事件穿透Demo

遍历元素总归会引起效率问题,所以能用pointer-events的还是用它吧,elementFromPoint只能作为一个备选方案来做兼容处理。

本文地址:https://www.deanhan.cn/js-through.html
版权声明:本文为原创文章,版权归 Dean 所有,欢迎分享本文,转载请保留出处!
  • 支付宝二维码 支付宝
  • 微信二维码 微信