Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/413.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/73.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 条件鼠标事件在重叠的同级元素之间传递_Javascript_Html_Mouseover_Event Passthrough - Fatal编程技术网

Javascript 条件鼠标事件在重叠的同级元素之间传递

Javascript 条件鼠标事件在重叠的同级元素之间传递,javascript,html,mouseover,event-passthrough,Javascript,Html,Mouseover,Event Passthrough,有没有标准的Javascript技术或库来管理不相关的重叠HTML元素之间的条件鼠标事件传递 例如,我在一堆HTML元素前面有一个部分透明的WebGL画布(由Three.js管理)(由e.js CSS3渲染器管理,但这不应该相关)。这些HTML元素已注册mouseover和mouseout事件。我希望漂浮在这些元素前面的3D对象能够阻止鼠标事件 我已经知道如何使用光线投射器来确定鼠标是否在3D对象上。我不知道的是,当3D对象不在画布之间时,如何允许鼠标事件“通过”画布到达底层HTML元素 我读

有没有标准的Javascript技术或库来管理不相关的重叠HTML元素之间的条件鼠标事件传递

例如,我在一堆HTML元素前面有一个部分透明的WebGL画布(由Three.js管理)(由e.js CSS3渲染器管理,但这不应该相关)。这些HTML元素已注册mouseover和mouseout事件。我希望漂浮在这些元素前面的3D对象能够阻止鼠标事件

我已经知道如何使用光线投射器来确定鼠标是否在3D对象上。我不知道的是,当3D对象不在画布之间时,如何允许鼠标事件“通过”画布到达底层HTML元素

我读过一些关于解决方案的书,在这些解决方案中,您将遍历DOM树,直到找到鼠标下面的元素。但这似乎过于复杂和缓慢。如果可能的话,我想做的是假装画布暂时不在那里,这样事件就可以自然地通过了


为了避免重新发明轮子,如果已经有一个用于此的库,那就太好了。

因为您不想像David Thomas建议的那样使用指针事件,那么鼠标将始终指向具有最高z索引的元素,或者具有相同z索引的最后一个同级元素(当相对堆叠在其他元素之上时)

话虽如此,我唯一能想到的办法是:

  • 隐藏画布
  • 读取下面的元素
  • 立即显示画布
  • 这是如此之快,以至于不会产生明显的闪烁

    如果鼠标下方有元素,则触发该元素鼠标事件


    我为你找到了一个非常简单的解决方案。由于您在一篇评论中提供了一个JSFIDLE示例,我想我只是稍微调整一下代码,让您看看

    我所做的很简单。我检查鼠标是否与div重叠,并且在Three.js raycaster未命中任何框时调用函数“changeTheDivBox”

    var divBox = document.getElementById("background");
    divBox.addEventListener("mouseover", mouseOver, false);
    divBox.addEventListener('mouseout', mouseOut, false);
    var mouseOverBox = false; // Are you currently hovering over the "background" div?
    function mouseOver () {
        mouseOverBox = true;
    }
    function mouseOut () {
        mouseOverBox = false;
    }
    function changeTheDivBox () { // This function is called when your raycaster does not hit any boxes
        if ( mouseOverBox ) {
            divBox.style.backgroundColor = 'blue';
        }
        else {
            divBox.style.backgroundColor = 'green';
        }
    }
    
    基本上:

    Is the mouse overlapping the <div> ?
        Yes.
        Is the mouse (raycaster) hitting any boxes?
        No.
            Then Change the <div>'s color!
    
    鼠标是否与鼠标重叠?
    对
    鼠标(raycaster)是否碰到任何盒子?
    不
    那就换个颜色吧!
    
    我做的另一件事是使用css属性
    指针事件
    。这使您可以通过使任何选择的元素不注册到鼠标事件来单击divs“再向后”。我添加了
    指针事件:无
    主体
    以禁用所有鼠标事件,然后我添加了
    指针事件:auto编码到div元素以在其上重新启用它们。所以鼠标现在只检测该分区上的事件。非常好

    我保留了代码的其余部分。我个人更喜欢使用循环来不断检查重叠/光线投射是否仍然有效,而不是依赖于mouseIn/mouseOutSo,但这是您的示例,所以请尝试一下:)


    就像个人喜好一样。我建议您避免将函数放在HTML中。它们并不总是像预期的那样工作。(此
    对象一直引用窗口),它们会使代码更加混乱。我个人更喜欢将JavaScript保存在标记中。无论如何,EventListener比内联函数调用更强大:)

    您在代码中设置了
    z-index:-1显示的代码>绝对值。这意味着:它位于body z层的后面,鼠标事件将以body或上面层中的任何其他对象为目标

    您可以设置
    指针事件:无的主体,甚至所有元素,但这可能是一件坏事与其他代码包括在网站以后。更喜欢用更高的z指数定位其他绝对覆盖元素,它们是:#container和#container>canvas

    请参见路径是如何传播DOM事件的:

    在捕获阶段,事件首先传播到视图,然后传播到、html和body,然后再传播到鼠标光标下显示的目标。而在鼓泡阶段,传播以相反的方式返回到视图

    渲染的场景对象不在此DOM事件路径中。您已经对文档事件侦听器中的命中进行了光线跟踪。在传播到达#background元素之前执行此操作,如果已知事件已被处理,则在某个安全的地方执行此操作。您已经尝试了
    preventDefault()
    。不幸的是,mousemove事件是不可取消的,因此这没有任何效果。稍后调用的事件侦听器检查
    preventedDefault
    将得到
    false
    preventDefault()
    的意思是防止在用户代理传播后执行默认操作,例如双击鼠标指针下的单词。如果应该执行默认操作,则不能使用
    preventDefault()
    告诉其他侦听器该事件已被处理

    您可以将Event的自定义属性设置为true。它至少可以在firefox中使用,但是W3C并没有严格指定主机对象。这可能会导致其他浏览器或将来出现一些错误。如果不应调用其他侦听器,则可以使用
    stopPropagation()
    。在某些情况下,这可能会导致一些JavaScript框架出现不良行为或bug

    另一种方法是在可供所有事件侦听器访问的范围内设置变量,例如全局范围或更好的封装匿名函数。这可能会保存最新处理的事件,并且在传播完成之前不会更改(之前不会触发下一个事件)

    如果光线跟踪器未命中场景对象,还可以在文档的侦听器中处理以#背景为目标的事件<代码>事件。目标
    保存被鼠标事件击中的最顶端的DOM元素

    您的修改代码与演示
    Is the mouse overlapping the <div> ?
        Yes.
        Is the mouse (raycaster) hitting any boxes?
        No.
            Then Change the <div>'s color!
    
    <!DOCTYPE html>
    <html>
      <head>
        <title>events passthrough</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style type="text/css">
    body {
      font-family: Monospace;
      margin: 0px;
      overflow: hidden;
    }
    
    div#background {
      position: absolute;
      top: 40px;
      left: 40px;
      width: 100px;
      height: 100px;
      background-color: pink;
      /*z-index: -1;            /* this is behind the body */
    }
    
    
    #container>canvas
    { position: absolute;
      z-index: 100;
    }
    
    /* Explicitly disable mouse events on covering element. */
    /* If z-index of background object is below zero then also disable body */
    
    /* body, */
    #container, #container canvas
    { pointer-events:none;
    }
    
    /* but let enabled all other elements */
    *
    { pointer-events:auto;
    }
        </style>
      </head>
    
      <body>
        <script type="text/javascript" src="https://mrdoob.github.io/three.js/build/three.min.js"></script>
        <script type="text/javascript" src="https://mrdoob.github.io/three.js/examples/js/libs/stats.min.js"></script>
    
        <div id="background"></div>
        <div id="container"></div>
    
        <script type="text/javascript">
    
    var lastHandledEvent;
    
    var container, stats;
    var camera, scene, projector, renderer;
    var particleMaterial;
    
    var objects = [];
    
    // don't run DOM relevant scripts before construction of DOM is guaranteed
    document.addEventListener("DOMContentLoaded", function()
    {
      init();
      animate();
    }, false);
    
    function init() {
        container = document.getElementById( 'container' );
        camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
        camera.position.set( 10, 300, 500 );
        scene = new THREE.Scene();
        var geometry = new THREE.BoxGeometry( 100, 100, 100 );
        for ( var i = 0; i < 10; i ++ ) {
            var object = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, opacity: 0.5 } ) );
            object.position.x = Math.random() * 800 - 400;
            object.position.y = Math.random() * 800 - 400;
            object.position.z = Math.random() * 800 - 400;
            object.scale.x = Math.random() * 2 + 1;
            object.scale.y = Math.random() * 2 + 1;
            object.scale.z = Math.random() * 2 + 1;
            object.rotation.x = Math.random() * 2 * Math.PI;
            object.rotation.y = Math.random() * 2 * Math.PI;
            object.rotation.z = Math.random() * 2 * Math.PI;
            scene.add( object );
            objects.push( object );
        }
    
        var PI2 = Math.PI * 2;
        particleMaterial = new THREE.SpriteCanvasMaterial( {
            color: 0x000000,
            program: function ( context ) {
                context.beginPath();
                context.arc( 0, 0, 0.5, 0, PI2, true );
                context.fill();
            }
        } );
        projector = new THREE.Projector();
        renderer = new THREE.WebGLRenderer({ alpha: true });
        renderer.setSize( window.innerWidth, window.innerHeight );
        // renderer.domElement.style.position = 'absolute';  // is done in CSS
        // renderer.domElement.style.zIndex = 100;           // is done in CSS
        container.appendChild( renderer.domElement );
    
        // register document mousemove in capturing phase
        // if you want to use another handlers subsequently
        document.addEventListener('mousemove', onDocumentMouseMove, true );
        document.querySelector('#background').addEventListener('mousemove', onMouseMove, false);
    
        window.addEventListener( 'resize', onWindowResize, false );
    }
    
    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize( window.innerWidth, window.innerHeight );
    }
    
    var background = document.getElementById('background');
    
    function onDocumentMouseMove( event ) 
    {
        var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
        projector.unprojectVector( vector, camera );
        var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
        var intersects = raycaster.intersectObjects( objects );
        if ( intersects.length > 0 ) 
        {
            intersects[ 0 ].object.material.color.setHex( Math.random() * 0xffffff );
            //event.preventDefault();   // mousemove is not cancelable
    
            // extending event objects works at least in Firefox, not sure if crossbrowser combatible
            // always be careful when extending DOM
            event.handled = true;       // add custom property
            lastHandledEvent = event;   // another way: store in a variable accessible by all handlers
                                        //              to remember this one was the last handled event
            console.log('event marked as handled in document listener');
            //event.stopPropagation();  // or could stop propagation, however,
                                        // often not a good praxis in conjuction with frameworks
        }
        else if(event.target === background)
          console.log('background could be handled in document listener');
    }
    
    function onMouseMove( event )
    { 
      // if(event.defaultPrevented   // mousemove not cancable, always false
      if(event.handled)              // TODO: check crossbrowser compatibility
                                     //       of custom properties on event objects.
                                     //       In doubt use a var outside the functions.
        console.log('other listener: event.handled is: '+event.handled);
    
      if(lastHandledEvent === event) // the safer way: use variable accessible
      {
        console.log('NOT handling event in other listener');
        return;
      }
      console.log(event.target, '...or handled in other listener');
      event.target.style.backgroundColor = '#'+('00000' + (Math.random() * 0xffffff).toString(16)).slice(-6);
    }
    
    function animate() {
        requestAnimationFrame( animate );
        render();
    }
    
    var radius = 600;
    var theta = 0;
    
    function render() {
        theta += 0.1;
        camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) );
        camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) );
        camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
        camera.lookAt( scene.position );
        renderer.render( scene, camera );
    }
        </script>    
      </body>
    </html>