Google Maps API v3事件mouseover与InfoBox插件

5
我正在使用Google Maps API的v3版本,并使用InfoBox插件(该插件是http://google-maps-utility-library-v3.googlecode.com/套件的一部分),以便制作出对标记交互有反应的漂亮样式的信息窗口。
对于这个特定的实验,我试图在鼠标悬停和移开时使InfoBox窗口弹出,但是我无法解决关于InfoBox窗口上的mouseover/mouseout事件系统的问题。发生的情况是,我可以找到DIV并使用google.maps.event.addDomListener将mouseover和mouseout事件附加到InfoBox上,但它太过繁琐了——当我在InfoBox内的子节点上悬停时,它会计算为父节点的mouseout并触发事件。
这是否与传播有关?我知道InfoBox在创建新的InfoBox时有一个enableEventPropagation开关,但我不太确定它应该如何和为什么使用。
实验的目的是创建一个信息窗口,其中包含相关链接,当鼠标悬停在标记上时出现。然后,您可以将鼠标移动到信息窗口内并进行交互,当您将鼠标移出时,它将关闭信息窗口。我尝试了另一种方法,在该方法中,标记上的鼠标悬停会触发一个外部函数,该函数创建一个外部信息窗口元素,该元素定位并具有自己的事件处理。这很有效,但自定义信息窗口覆盖在地图上的层次结构意味着,当您在紧邻的另一个标记上悬停鼠标(在自定义信息窗口下方)时,无法注册标记的鼠标悬停事件。
这是我尝试使用InfoBox方法的结果:
 <!DOCTYPE html>
 <html>
 <head>
 <style type="text/css">
 <!--
    #map {
        width:                  800px;
        height:                 600px;
        margin:                 50px auto;
    }

    .map-popup {
        overflow:               visible;
        display:                block;
    }

    .map-popup .map-popup-window {
        background:             #fff;
        width:                  300px;
        height:                 140px;
        position:               absolute;
        left:                   -150px;
        bottom:                 20px;
    }

    .map-popup .map-popup-content {
        padding:                20px;
        text-align:             center;
        color:                  #000;
        font-family:            'Georgia', 'Times New Roman', serif;
    }
 -->
 </style>
 <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
 <script type="text/javascript" src="http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/src/infobox_packed.js"></script>
 <script type="text/javascript">

    var gmap, gpoints = [];

    function initialize() {
        gmap = new google.maps.Map(document.getElementById('map'), {
            zoom:               9,
            streetViewControl:  false,
            scaleControl:       false,
            center:             new google.maps.LatLng(-38.3000000,144.9629796),
            mapTypeId:          google.maps.MapTypeId.ROADMAP
        });

        for ( var i=0; i<5; i++ ) {
            gpoints.push( new point(gmap) );
        }
    }

    function popup(_point) {
        _point.popup = new InfoBox({
            content:            _point.content,
            pane:               'floatPane',
            closeBoxURL:        '',
            alignBottom:        1
        });

        _point.popup.open(_point.marker.map, _point.marker);

        google.maps.event.addListener(_point.popup, 'domready', function() {
            // Have to put this within the domready or else it can't find the div element (it's null until the InfoBox is opened)
            google.maps.event.addDomListener(_point.popup.div_, 'mouseout', function() {
                _point.popup.close();
            });
        });
    }

    function point(_map) {
        this.marker = new google.maps.Marker({
            position:           new google.maps.LatLng(-37.8131869 - (1 * Math.random()),144.9629796  + (1 * Math.random())),
            map:                _map
        });

        this.content = '<div class="map-popup"><div class="map-popup-window"><div class="map-popup-content"><a href="http://www.google.com/">Just try to click me!</a><br/>Hovering over this text will result in a <code>mouseout</code> event firing on the <code>map-popup</code> element and this will disappear.</div></div>';

        // Scope
        var gpoint = this;

        // Events
        google.maps.event.addListener(gpoint.marker, 'mouseover', function() {
            popup(gpoint);
        });
    }

 </script>
 </head>
 <body onload="initialize()">
    <div id="map"></div>
 </body>
 </html>

我猜如果有人知道如何使这个程序正常工作并正确响应(或提供相关的技巧/窍门),那就太好了!


你有没有找到这个问题的好解决方案?下面的jQuery示例似乎是针对弹出窗口本身而不是标记。我很难看到如何使用InfoBox以那种方式实现它。通过升级到最新的InfoBox开发版本并打开事件传播,我能够使得在弹出窗口下面的任何底层标记上的弹出窗口不再跳动。 - Jeremy Hicks
2个回答

11
我也遇到过同样的问题。正如你所说,问题在于当鼠标移动到其中一个子元素时,会触发mouseout事件。解决方法是使用mouseenter和mouseleave事件(需要jQuery),更多信息请参见此帖子:Hover, mouseover and mouse out
在这种情况下,无法使用Google Maps事件监听器(它不支持mouseenter)。相反,您可以附加普通的jQuery事件,或者使用以下代码中显示的hover函数。
google.maps.event.addListener(_point.popup, 'domready', function() {
//Have to put this within the domready or else it can't find the div element (it's null until the InfoBox is opened)

    $(_point.popup.div_).hover(
        function() {
            //This is called when the mouse enters the element
        },
        function() {
            //This is called when the mouse leaves the element
            _point.popup.close();
        }
    );
});    

在悬停功能中,我设置了一个变量来指示弹出窗口是否打开。然后在标记的'mouseover'回调函数中,只有在它没有打开时才显示信息框。最后,我添加了一个'clickclose'事件来重置指示弹出窗口已关闭的变量。当信息框覆盖标记时,信息框最终可以正确地工作。 - yitwail
最近使用jQuery的方法:google.maps.event.addListener(_point, 'domready', function() { $(_point.div_).mouseover(function(e){ ... - user151496

2
发生的情况是,我可以定位DIV并使用google.maps.event.addDomListener将mouseover和mouseout事件附加到InfoBox上,但这太过繁琐 - 当我在InfoBox内部的子节点上悬停时,它会被视为鼠标移出父节点并触发事件。
克服这个问题的一个天真的方法是,在你的mouseout处理程序中向上遍历元素树,并检查是否找到DIV或者到达文档根。如果你找到了DIV,则鼠标仍然在弹出窗口内,你不需要关闭它。
jQuery通过引入第二个事件mouseleave来很好地解决了这个问题,它的行为与你期望的相同,并以类似上述方式实现。jQuery源代码有一个特殊的闭包withinElement用于这种情况,值得一看。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接