在动态生成的DIV的鼠标悬停上显示谷歌地图标记信息名称

Showing Google Maps Marker infoname on Mouseover of a Dynamically Generated DIV

本文关键字:图标 地图 谷歌 显示 信息 动态 DIV 悬停 鼠标      更新时间:2023-09-26

我想引入一个功能,该功能允许标记的信息名称在从jQuery生成的相应div元素鼠标悬停或移出时出现或消失。然而,我在main.js的第19行遇到了一个">a is undefined"错误。经过对我的脚本的广泛测试,我意识到这与新添加的行中的标记有关,如下所述:

function addMarker(A) {
 var point = new google.maps.LatLng(A.lat, A.lng);      
 var image = new google.maps.MarkerImage('images/r.png',
  new google.maps.Size(30, 30),
  new google.maps.Point(0, 0),
  new google.maps.Point(0, 30));
 marker = new google.maps.Marker({
  map: map,
  position: point,
  icon: image,
 });
}
function addInfoName(A) {
 var infoname = new infoName; // custom object
 google.maps.event.addListener(marker, 'mouseover', function(event) {infoname.show();});
 google.maps.event.addListener(marker, 'mouseout', function(event) {infoname.hide();});
 infoname.open(map, marker);
}
function showResult(A) {
 $('#results').append('<DIV id=' + A.pid + '>{Blah Blah Blah}</DIV>');
 return document.getElementById(A.pid);
}
function process(json) {
 $('#results').empty();
 total = json.details.length;
 for(i=0; i<total; i++) {
  var detail = json.details[i];
  var marker;
  addMarker(detail);
  addInfoName(detail);
// these new lines are added
  var listDisplay = showResult(detail);
  listDisplay.onmouseover = function(){google.maps.event.trigger(marker, 'mouseover');};
  listDisplay.onmouseout = function(){google.maps.event.trigger(marker, 'mouseout');};
 }
}
google.maps.event.addListener(map, 'idle', function () {$.getJSON(query, process);});

如果我将函数addInfoName合并到process,则错误消失。然而,如果我这样做,所有的DIV都会指向最后一个标记。我的问题是,我如何修改我的脚本以实现上面提到的功能

当前,您有一个声明为process函数本地的变量marker,但您正在尝试从其他函数读取和写入它。特别地,addMarker在没有var的情况下写入marker,这会导致意外的全局变量被创建。同时,process实际上并没有写入它声明的marker本地,所以它包含undefined,当你传入它时,它会绊倒谷歌地图代码。

(像jslint或ECMAScript 5 Strict Mode这样的工具可以为您捕获意外全局。注意totali也是意外全局。(

看起来addMarkeraddInfoname已经从process的主体中被黑客入侵,而没有绑定它们都使用的process中的变量。如果它们包含在process的主体中,它会起作用,但您会得到所描述的行为,因为闭包循环问题,每个div都使用相同的marker值。

这个问题发生在具有闭包和函数级作用域的语言中,包括JavaScript、Python和其他语言。在这些语言中,for循环定义的或循环内部的任何变量都是包含函数的本地变量,而不是每次循环时重新分配的。因此,如果在循环的第一次迭代中创建一个引用i的闭包,那么它与循环的第二次迭代中引用的变量i相同;函数的每个实例在相同的变量CCD_ 22上都有一个闭包,因此每个函数都将看到相同的值。CCD_ 23也是如此。

闭包循环问题可以通过使用第二个闭包来避免,该闭包将循环变量保持在参数中,或者更干净地说,使用基于闭包的循环机制而不是类似C的for循环。ECMAScript 5为此提供array.forEach(),jQuery提供$.each():

function process(json) {
    $('#results').empty();
    var gev= google.maps.event;
    $.each(json.details, function(detaili, detail) {
        var marker= addMarker(detail.lat, detail.lng);
        $('#results').append($('<div>', {
            text: detail.name,
            mouseover: function() { gev.trigger(marker, 'mouseover'); },
            mouseout: function() { gev.trigger(marker, 'mouseout'); }
        }));
        var infoname= new InfoName();
        gev.addListener(marker, 'mouseover', function() { infoname.show(); });
        gev.addListener(marker, 'mouseout', function() { infoname.hide(); });
        infoname.open(map, marker);
    });
}
function addMarker(lat, lng) {
    return new google.maps.Marker({
        map: map,
        position: new google.maps.LatLng(lat, lng),
        icon: new google.maps.MarkerImage(
            'images/r.png',
            new google.maps.Size(30, 30),
            new google.maps.Point(0, 0),
            new google.maps.Point(0, 30)
        )
    });
}

"a未定义"错误可能是因为您试图在dom准备好之前创建映射。至少,这是我唯一一次看到它。我无法从你的代码中判断你在哪里创建它,但要确保mapdiv已经准备好了。您必须将对initialize函数的调用放在页面底部或页面加载侦听器中。这里有一种方法可以做到这一点(这可以在页面中的任何地方进行(:

function initialize() {
    var map = new google.maps.Map(document.getElementById("map_canvas"), {
        zoom: 6,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });
    google.maps.event.addListener(map, 'idle', function () {
        $.getJSON(query, process);
    });
}
google.maps.event.addDomListener(window, 'load', initialize);

还要注意,您的空闲侦听器也会进入init函数,因为在创建映射之前,它将无法运行。

如果这不是导致"a未定义"错误的原因,那么我在您发布的代码中看不到它。但是,我确实看到您的代码存在其他一些问题。所以也许这就是造成它的原因。首先,process中的var marker;定义没有任何作用。在这里,您正在创建一个局部变量,但该局部变量从未被定义。那么addMarker就是通过定义不带varmarker来创建全局变量。因此,addInfoname中的标记总是指全局标记,它将始终是最后定义的标记。这就是为什么div总是带着最后一个标记出现的原因。我会在addMarker中的marker = ...之前放一个return,并用它来设置标记变量,如下所示:

var marker = addMarker(detail);

当然,在process中。然后,您还必须将其作为参数发送到addInfoname,以便它获得正确的参数。