How to detecting a click under an overlapping elem

2019-08-13 01:48发布

问题:

I have two HTML documents, b.html contains c.html using an iframe.

On b.html I need to draw some DIV (in my example id=selector), which partially cover content of c.html visualized in the iframe.

I need to get the ID of a DOM element corresponding to the mouse coordinate under the DIV selector.

At the moment Using document.elementFromPoint() directly in in c.html works partially, as when the mouse it is on DIV selector I cannot identify the underling DOM element in c.html (in this example DIV c).

I would need to know:

  • Is it possible to select element under another, using document.elementFromPoint() or any other means?
  • What could be a possible alternatively solution possibly using DOM and native API?

Example here (Please look at the console in Chrome):

http://jsfiddle.net/s94cnckm/5/

----------------------------------------------- b.html

<!doctype html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>B</title>
    <script type="text/javascript">
        window.app = {
            start: function () {
            }
        };
    </script>
    <style>
        #selector {
            position: absolute;
            top: 150px;
            left: 150px;
            width: 250px;
            height: 250px;
            -webkit-box-shadow: 0px 0px 0px 5px yellow;
            -moz-box-shadow: 0px 0px 0px 5px yellow;
            box-shadow: 0px 0px 0px 5px yellow;
        }

        #iframe {
            width: 500px;
            height: 500px;
            border: none;
        }
    </style>
</head>
<body onload="app.start();">
    <div id="selector">SELECTOR</div>
    <iframe id="iframe" src="c.html"></iframe>
</body>
</html>

----------------------------------------------- c.html

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>C</title>
    <script type="text/javascript">
        window.app = {
            start: function () {
                document.querySelector('body').addEventListener('mousemove', function (event) {
                //console.log(event.pageX, event.pageY, event.target.id);
                var item = document.elementFromPoint(event.pageX, event.pageY);
                console.log(item.id);
                }.bind(this));
            }
        };
    </script>
    <style>
        body {
            background-color: lightslategray;
        }

        #a {
            position: absolute;
            top: 50px;
            left: 50px;
            width: 100px;
            height: 100px;
            background-color: green;
            z-index: 2;
        }

        #b {
            position: absolute;
            top: 100px;
            left: 100px;
            width: 100px;
            height: 100px;
            background-color: #ffd800;
            z-index: 1;
        }
    </style>
</head>
<body onload="app.start();">
    <h1>Content</h1>
    <div id="a">a</div>
    <div id="b">b</div>
</body>
</html>

回答1:

A possible soltion is the usage of pointer-events.

The CSS property pointer-events allows authors to control under what circumstances (if any) a particular graphic element can become the target of mouse events. When this property is unspecified, the same characteristics of the visiblePainted value apply to SVG content.

When you apply

#selector {
    /* ... */
    pointer-events: none;
 }

All content of #selector and the element itself are no more interactive. Content may not be selected and events like :hover or click are not applicable.

Here is the demo with the above css: http://jsfiddle.net/s94cnckm/6/



回答2:

Another possible solution, is to capture the document coordinates of a mouse event fired on the masking item(DIV.selector), momentarily hide that masking item, and then ask the document what is under that coordinate position (using document.elementFromPoint(x,y)) before showing the masking item again.

The support for document.elementFromPoint() cover also old version of IE. Unfortunately pointer-events has limited support for older version of IE.

Here a working example:

http://jsfiddle.net/s94cnckm/14/

 document.getElementById('iframe').contentDocument.addEventListener('click', function (event) {
     alert(event.target.id);
 }.bind(this));

 document.getElementById('selector').addEventListener('click', function (event) {
     var selector = document.getElementById('selector');
     selector.style.display = 'none';
     var item = document.getElementById('iframe').contentDocument.elementFromPoint(event.pageX, event.pageY);
     selector.style.display = '';
     alert(item.id);
 }.bind(this));

Regarding the use of pointer-events I link to mention some related article, included a work around for older version of IE.

How to make Internet Explorer emulate pointer-events:none?

https://css-tricks.com/almanac/properties/p/pointer-events/

http://davidwalsh.name/pointer-events

http://robertnyman.com/2010/03/22/css-pointer-events-to-allow-clicks-on-underlying-elements/

This solution was inspired by this article:

http://www.vinylfox.com/forwarding-mouse-events-through-layers/