“穿透”层的鼠标事件

标题可能不是一读让人容易明白,上张图(转载的)

需要实现如下的效果,有一个浮动层,需要层级在它之下的一个元素也能照常响应相应的事件

一个100*100的元素,边框为1px solid #406c99,它有两个事件(鼠标移入、鼠标移出):

onmouseover="this.style.borderColor='#f00';"

onmouseout="this.style.borderColor='#406c99';"

在不做特殊处理的情况下,它的事件将会是无法触发的,现在想让它正常触发,效果如下:

解决这样的问题有以下方案:

1、纯使用CSS的属性pointer-events,设置其为none (默认为auto)

优点:无需额外的代码

缺点:不支持IE(IE不支持此属性,IE9是否支持有待考评..)

2、捕捉事件获取鼠标的位置X、Y,然后触发层级较低元素的相应事件 (平时我们用调试工具选取页面中的元素,高亮显示的区域就是依据这个原理)

优点:兼容各浏览器

缺点:需要编写Javascript,效率并不高

这样获取有也有两种处理方法:

循环获取每一个元素的位置,然后对比鼠标的X、Y,效率低,不推荐;这里推荐使用elementFromPoint(浏览器都支持),直接传入X、Y,便可直接获取相应的DOM元素

比较折中的办法是,针对非IE的浏览器直接使用方案1,IE使用方案2进行优化。这种应用场景,可能会是一个新的产品上线了,需要引导用户如何去使用,会使用蒙板遮住整个页面,然后让某一元素可点击。

elementFromPoint的使用例子(移动鼠标时,如果那一点在某一元素的占位区域则添加3像素的红色边框,鼠标移开该元素时清除边框)

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<script type="text/javascript" >
var selElem =null;
var origBorder ="";

function OnMouseMove (event) {
    var posX = event.clientX, 
        posY =event.clientY;
    
    var ua = navigator.userAgent,
        isIE = /msie/i.test(ua),
        isFF = /firefox/i.test(ua);
        
    if(!isIE && !isFF) {
        posX = event.pageX; 
        posY = event.pageY;
    }
    
    var info = document.getElementById("info"); 
    info.innerHTML = event.clientX + ", " + event.clientY;
    
    var overElem = document.elementFromPoint(posX, posY);

    if(overElem && !overElem.tagName) {
        overElem = overElem.parentNode;
    }

    if (selElem) {
        if (selElem == overElem) {
            return ;
        }
        selElem.style.border = origBorder;

        selElem = null;
    }
    
    if (overElem && !/^(html|body)$/.test(overElem.tagName.toLowerCase()) ) { 
        selElem = overElem;
        origBorder = overElem.style.border;
        overElem.style.border = "3px solid red" ;
    }
}


    </script>
    </head>
    <body onmousemove="OnMouseMove (event);">
    <div style="height:200px">
        test test test test test test test
    </div>

    <div style="position:absolute; right:20px; top:30px;">
        The current mouse position: <span id="info" style="border:1px solid #606060; background-color:e0d0e0; padding:5px;"></span>
    </div>
    <br/><br/>
    <textarea rows="4" style="width:200px; height:100px;">
        test test test test test test test test test test test test test test
    </textarea>
    
    <div style="height:100px; margin-top:20px;">
        test test test test test test testtest test test test test test testtest test test test test test testtest test test test test test test
    </div>
</body>
</html>

遍历元素,然后找到相应的元素示例(效率比较低的一种)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
<head> 
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> 
<title>Sandbox</title> 
<meta http-equiv="Content-type" content="text/html; charset=utf-8" /> 
<style type="text/css" media="screen"> 
body { background-color: #000; }
.box {width: 50px; height: 50px; border: 1px solid white}
.highlight {background-color: yellow;}
#controls {position:absolute; top: 300px; color: white;}
</style> 
</head> 
<body> 
  <div id="container"> 
     <div class="box" style="position:absolute; top: 25px; left: 25px;"></div> 
     <div class="box" style="position:absolute; top: 50px; left: 125px;"></div> 
     <div class="box" style="position:absolute; top: 100px; left: 25px;"></div> 
     <div class="box" style="position:absolute; top: 125px; left: 180px;"></div> 
     <div class="box" style="position:absolute; top: 225px; left: 25px;"></div> 
     <div class="box" style="position:absolute; top: 185px; left: 125px;"></div> 
     <div id="shield" style="position: absolute; width: 200px; top: 0px; background-color: #406c99; opacity: 0.5; filter:alpha(opacity=50);"></div> 
  </div> 
  <div id="controls"> 
    <input type="checkbox" checked="checked">Pass pointer events through</input> 
    Try clicking
  </div> 
<script> 
$(".box").click(function(){
     $(this).toggleClass("highlight");
});
 
 
function passThrough(e) {
    $(".box").each(function() {
       // check if clicked point (taken from event) is inside element
       var mouseX = e.pageX;
       var mouseY = e.pageY;
       var offset = $(this).offset();
       var width = $(this).width();
       var height = $(this).height();
 
       if (mouseX > offset.left && mouseX < offset.left+width 
           && mouseY > offset.top && mouseY < offset.top+height)
         $(this).click(); // force click event
    });
}
 
$("#shield").click(passThrough);
 
var dthen = new Date();
        
setInterval(function(){
    dNow = new Date();
    $('#shield').css('height', ((dNow.getSeconds()+(dNow.getMilliseconds()/1000))*50)%300 +'px');
},10)


var doPassThrough = true;
$('input').click(function(){
  doPassThrough =  !doPassThrough;
  if (doPassThrough){
    $("#shield").click(passThrough);
  } else {
    $('#shield').unbind('click', passThrough);
  }
});

</script>
</body> 
</html>

在非IE浏览器中,控制pointer-events来达到想要的效果的示例

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
 <head>
  <title>pointer-events test</title>
  <meta name="generator" content="editplus" />
  <meta name="author" content="" />
  <meta name="keywords" content="" />
  <meta name="description" content="" />
  <meta http-equiv="content-Type" content="text/html;charset=utf-8">
  <style type="text/css">
    * {margin:0; padding:0;}
    body {width:100%; height:100%;}
  </style>
 </head>

 <body>

<div style="border:1px solid #406c99; width:100px; height:100px; margin-top:300px; margin-left:300px;" onmouseover="this.style.borderColor='#f00';" onmouseout="this.style.borderColor='#406c99';" title="hahaniu"></div>

<div style="position:absolute; top:0; left:0; width:100%; height:100%; background-color:#000; opacity:.3; filter:alpha(opacity=30); overflow:hidden;" id="mask"></div>

<button style="position:absolute; z-index:9999; left:100px; top:80px; padding:2px;">开启pointer-events支持</button>

<script type='text/javascript'>

var isOpen = false;

document.getElementsByTagName("button")[0].onclick = function(evt) {
    evt = evt || window.event;
    
    this.innerHTML = (isOpen ? "开启" : "关闭") + "pointer-events支持";
    
    document.getElementById("mask").style.pointerEvents = isOpen ? "" : "none";

    isOpen = !isOpen;
}

</script>

 </body>
</html>

参考:

Forwarding Mouse Event Through Layers

ext-ux-datadrop

Basic Event Forwarding Example http://jsbin.com/uhuto

elementFromPoint method

More IE9 goodness and elementFromPoint()

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Coding迪斯尼

VUE+WebPack前端游戏设计:实现物体的拖拽动态特效

15230
来自专栏mini188

学习笔记:delphi之TStringGrid

1、说明 最近加入了一个项目组,使用的开发工具是delphi6,想想又要开始搞这个工具有点小忧伤,但没办法谁让咱就是个打杂的尼。。。 的需求是显示一个类似于Wo...

24850
来自专栏iOS开发攻城狮的集散地

iOS 瀑布流之栅格布局

20310
来自专栏技术小黑屋

Read Output From Shell

Python provides a lot of method to read output from a just executed shell. Howev...

13120
来自专栏HT

基于HT for Web矢量实现HTML5文件上传进度条

在HTML中,在文件上传的过程中,很多情况都是没有任何的提示,这在体验上很不好,用户都不知道到时有没有在上传、上传成功了没有,所以今天给大家介绍的内容是通过HT...

22390
来自专栏计算机编程

SNS项目笔记<六>--手势Gestures

这里直接贴上angular源码地址:angular源码之hammer_gestures <这里方便它更新后的修改> 这里又贴上该地址的源码以便说明:

21810
来自专栏QQ音乐技术团队的专栏

Lottie : 让动画如此简单

Lottie是Airbnb开源的一个面向 iOS、Android、React Native 的动画库,可实现非常复杂的动画,使用也及其简单,极大释放人力,值得一...

15.1K110
来自专栏hightopo

基于 HTML5 Canvas 的工控机柜 U 位动态管理

36940
来自专栏老司机的简书

老司机读书笔记——Weex学习笔记

Weex整体上与Vue语法大概一直,基本用法由阿里进行二次封装。以下主要介绍Weex的一些内置组件。

41740
来自专栏非著名程序员

基础篇章:关于 React Native 之 ListView 组件的讲解

? (友情提示:RN学习,从最基础的开始,大家不要嫌弃太基础,会的同学请自行略过,希望不要耽误已经会的同学的宝贵时间) 我们讲完ScrollView组件,其实...

22080

扫码关注云+社区

领取腾讯云代金券