Change icon on mouseover/out fails

旧巷老猫 提交于 2019-12-25 12:13:06

问题


I'm tearing my hair out over this code. As you may guess, I'm relatively new to coding. I would appreciate any insight you have into why it is not working.

I am trying to change marker icons on mouseover/out. I am trying to create and add listeners in a for-loop. In the loop, the markers are created from an array of locations and pushed to another array, a listener is added for mouseover events to change the icon, and another listener is added for mouseout events to nullify the marker icon. The code below displays the map, adds the markers and seems to listen for mouseover and mouseout events (the cursor changes when hovering over a marker), but the icon does not change at these events.

    function initialize(){  
        //Marker locations
        var NYC = new google.maps.LatLng(40.721505, -74.004783);
        var LA = new google.maps.LatLng(34.049519, -118.238698);
        var Chicago = new google.maps.LatLng(41.877461, -87.624352);
        var Seattle = new google.maps.LatLng(47.606747, -122.330349);
        var Miami = new google.maps.LatLng(25.788661, -80.226617);
        var Boston = new google.maps.LatLng(42.357913, -71.059217);
        var Houston = new google.maps.LatLng(29.758182, -95.364213);
        var KansasCity = new google.maps.LatLng(39.097781,-94.588079);
        var locations = new Array(NYC, LA, Chicago, Seattle, Miami, Boston, Houston, KansasCity);

        //Array to store markers
        var markers = new Array ();

        //Icon
        var gif = 'http://demers-ambulances.com/assets/img/news/mapPinOver2.gif';

        //Map options
        var mapOptions = {
            center: KansasCity,
            zoom: 5,
            zoomControl: true,
            zoomControlOptions: {
                style: google.maps.ZoomControlStyle.SMALL,
                position: google.maps.ControlPosition.TOP_LEFT
            },
            mapTypeControl: true,
            mapTypeControlOptions: {
                style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
                position: google.maps.ControlPosition.TOP_RIGHT,
            },
        };

        //Create map
        var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); 

        //Create markers and add listener to change marker icon on mouseover/out
        for (i = 0; i<locations.length; i++){
            var marker = new google.maps.Marker({
                position: locations[i],
                draggable: true,                
                map: map,
            });
            markers.push(marker);               
            google.maps.event.addListener(markers[i], 'mouseover', function() {
                markers[i].setIcon(gif);
            });
            google.maps.event.addListener(markers[i], 'mouseout', function() {
                markers[i].setIcon(null);
            });         
        };          
    };

    google.maps.event.addDomListener(window, 'load', initialize);

Thanks for your help :)


回答1:


Closure problem: there is error reported:

Uncaught TypeError: Cannot read property 'setIcon' of undefined

Code has to be changed to:

        (function(i) {
            google.maps.event.addListener(markers[i], 'mouseover', function() {
                markers[i].setIcon(gif);
            });

            google.maps.event.addListener(markers[i], 'mouseout', function() {
                markers[i].setIcon(null);
            });         
        })(i);



回答2:


Basically the problem is in here:

    for (i = 0; i<locations.length; i++){
        var marker = new google.maps.Marker({
            position: locations[i],
            draggable: true,                
            map: map,
        });
        markers.push(marker);               
        google.maps.event.addListener(markers[i], 'mouseover', function() {
            markers[i].setIcon(gif);
        });
        google.maps.event.addListener(markers[i], 'mouseout', function() {
            markers[i].setIcon(null);
        });         
    };          

This code looks innocent, but the problem comes from the part that, once the loop has finished executing and our event listeners are called, the variable i is already equal to locations.length.

So whenever the event listener is called, i is already changed to locations.length, and markers[i] will return undefined, because the last push index was i = locations.length - 1 since the loop condition is i<locations.length.

Since markers[i] is undefined when the event listener is called, then it will throw the following error as it doesn't have setIcon method anymore: TypeError: Cannot read property 'setIcon' of undefined.

To fix this, you should capture value of i, in a closure(as Anto Jurković described above, don't forget to upvote him):

    (function(i) {
        google.maps.event.addListener(markers[i], 'mouseover', function() {
            markers[i].setIcon(gif);
        });

        google.maps.event.addListener(markers[i], 'mouseout', function() {
            markers[i].setIcon(null);
        });         
    })(i);

Here we create a function on each loop and call it with i immediately so the value of i is captured in the closure, and since javascript functions have block scope(loops don't), the variable i will be the same for each iteration of loop.

The problem and it's solution is also described in the following question: Javascript closure inside loops - simple practical example




回答3:


After further experimenting with the code that Anto and Farid recommended I found another solution. For this solution a function is created outside the initialize function to add listeners to the markers, and then called when each marker is created in the for loop. If you have any thoughts on this, please comment below. I have no clue if this is a good way to do this, I just know it works :)

        for (i = 0; i<locations.length; i++){
            var marker = new google.maps.Marker({
                position: locations[i],
                draggable: true,                
                map: map,
            });
            animateit(marker);
            markers.push(marker);               
        };          
    };


    function animateit(marker) {
                google.maps.event.addListener(marker, 'mouseover', function() {
                    marker.setIcon(gif);
                });

                google.maps.event.addListener(marker, 'mouseout', function() {
                    marker.setIcon(null);
                }); 


来源:https://stackoverflow.com/questions/23119744/change-icon-on-mouseover-out-fails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!