在另一个元素后面的画布上的事件侦听器

Event listener on a canvas behind another element

本文关键字:事件 侦听器 元素 另一个      更新时间:2023-09-26

我有一个鼠标移动事件监听器附加到我的画布。但是在画布的顶部是一个div,它的z-index更高,它包含了一些菜单按钮。

我面临的问题是,我希望鼠标移动事件仍然激活当鼠标在菜单元素-其中是在画布元素。

当前,它的行为就好像鼠标不再位于画布的顶部,因为菜单元素由于z-index顺序而优先。

是否有一种方法可以使这个事件侦听器忽略任何妨碍它的元素?

我代码:

var canvas = new function(){
      var self = this
      self.outputMouseData = function(evt,el){
        var pos = mouse.relativePosition(evt,el);
        el.ctx.clearRect(0,0,el.width,el.height);
        el.ctx.fillStyle    = "white";
        el.ctx.font         = "bold 16px Arial";
        el.ctx.fillText(pos.x+' | '+pos.y, el.width-150,el.height-10);  
      }
}
   elements.addEvent(foreground,'mousemove',
                     function(evt){ canvas.outputMouseData(evt,foreground); }
                     );
我HTML

<div class="parent"> 
   <canvas id="canvas"></canvas>
   <div class="menu">Menu output</div>
</div>

父元素是相对定位的。Canvas和menu是绝对位置的,但是menu的z-index在Canvas的顶部

HTML事件在节点树中冒泡(您可以在这里阅读关于此的很好的解释)。

这意味着,如果您将事件处理程序附加到包含其他元素的元素上,则当事件发生在子元素上时(假定冒泡没有显式终止),该处理程序将调用甚至。你可以把你的画布包起来。Div放在包装器元素(例如span)中,并在其上附加处理程序。无论z-index如何,您都将获得事件。

下面是一个简短的代码示例(从这里获取的getOffsetSum):

var canvas = document.getElementById('canvas');
var canvasPos = getOffsetSum(canvas);
var ctx = canvas.getContext('2d');
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(0, 0, 99, 99);
var container = document.getElementById('container');
var mousemove = document.getElementById('mousemove');
container.addEventListener('mousemove', function(evt) {
  var pos = getOffsetSum(evt.target);
  pos.top += evt.offsetY - canvasPos.top;
  pos.left += evt.offsetX - canvasPos.left;
  mousemove.innerHTML = 'offsetX: ' + evt.offsetX + ' | offsetY: ' + evt.offsetY + '<br/>' +
    'canvasX: ' + pos.left + ' | canvasY: ' + pos.top;
});
function getOffsetSum(elem) {
  var top = 0, left = 0;
  while (elem) {
    top = top + parseInt(elem.offsetTop);
    left = left + parseInt(elem.offsetLeft);
    elem = elem.offsetParent;
  }
  return {
    top: top,
    left: left
  }
}
.ontop {
  position: absolute;
  top: 20px;
  left: 20px;
}
<span id="container">
  <canvas id="canvas" width="100" height="100"></canvas>
  <div class="ontop">ON TOP</div>
</span>
<div id="mousemove"></div>

将canvas和menu-div放到一个容器div中。

然后使用jQuery事件委托来监听容器上的鼠标移动事件,但是让你的画布响应这些鼠标移动事件。

$('#container').on('mousemove','#myCanvas',function(){ doSomething(); }

您可以在这里了解更多关于事件委托的信息:http://api.jquery.com/on/

您可以简单地将pointer-events: none;应用于菜单div,而不是像其他答案中建议的那样使用包装器。这将允许画布发出mousemove事件。

.menu {
  pointer-events: none;
}

我最初的想法是将" mousmove "事件添加到文档本身(而不是画布元素或元素),并使用evt跟踪元素。currTarget或event .target。通过这种方式,无论您将鼠标悬停在菜单上还是画布上(或任何地方),mousemovet都将始终存在。