【问题标题】:showing one info window at a time一次显示一个信息窗口
【发布时间】:2018-07-01 13:41:55
【问题描述】:

我有这个项目使用 Google 和 Foursquare API 显示多个位置。我能够显示位置并创建标记。我的问题是如何一次显示一个信息窗口?如果我单击新位置,则其他位置信息窗口不会关闭。现在,如果我点击一个地方和另一个地方。两个信息窗口都保持打开状态。

我的代码如下。谢谢。

var initialLocations = [{
            name: 'Golden Gate',
            lat: 37.819929,
            long: -122.478255
        }, {
            name: 'AT&T Park',
            lat: 37.7749,
            long: -122.4194

        }, {
            name: 'Twin Peaks',
            lat: 37.7544,
            long: -122.4477
        },
    ];

var clientID = "xxxxxxxxxxxxxxxxxxxxxxxxxx";
var clientSecret = "xxxxxxxxxxxxxxxxxxxxxxxx";

var Location = function(data) {
    var self = this;

    this.name = data.name;
    this.lat = data.lat;
    this.long = data.long;
    this.URL = "";
    this.street = "";
    this.city = "";
    this.phone = "";

    this.visible = ko.observable(true);

    var foursquareURL = 'https://api.foursquare.com/v2/venues/search?ll=' + this.lat + ',' + this.long + '&client_id=' + clientID + '&client_secret=' + clientSecret + '&v=20160118' + '&query=' + this.name;

    $.getJSON(foursquareURL).done(function(data) {
        var results = data.response.venues[0];
        self.URL = results.url || 'No url found';
        self.street = results.location.formattedAddress[0];
        self.city = results.location.formattedAddress[1];
        self.phone = results.contact.phone  || 'No phone found';;

    }).fail(function() {
        alert("Error found. Please refresh your page.");
    });

    // Info window


    this.infoWindow = new google.maps.InfoWindow({


    });


    // Marker

    this.marker = new google.maps.Marker({
        position: new google.maps.LatLng(data.lat, data.long),
        map: map,
        title: data.name
    });


    this.marker.addListener('click', function() {

        self.contentString = '<div class="info-window-content"><div class="title"><b>' + data.name + "</b></div>" +
            '<div class="content"><a href="' + self.URL + '">' + self.URL + "</a></div>" +
            '<div class="content">' + self.street + "</div>" +
            '<div class="content">' + self.city + "</div>" +
            '<div class="content"><a href="tel:' + self.phone + '">' + self.phone + "</a></div></div>";

        self.infoWindow.setContent(self.contentString);

        self.infoWindow.open(map, this);

        self.marker.setAnimation(google.maps.Animation.BOUNCE);
        setTimeout(function() {
            self.marker.setAnimation(null);
        }, 2100);
    });

    this.bounce = function(place) {
        google.maps.event.trigger(self.marker, 'click');
    };
};


//-ViewModel
function AppViewModel() {
    var self = this;

    // create array of places

    this.locationList = ko.observableArray([]);
    this.searchLocation = ko.observable('');

    map = new google.maps.Map(document.getElementById('map'), {
        zoom: 12,
        center: {
            lat: 37.77986,
            lng: -122.429
        }
    });

    initialLocations.forEach(function(locationItem) {
        self.locationList.push(new Location(locationItem));
    });

    this.filteredList = ko.computed(function() {
        var filter = self.searchLocation().toLowerCase();
        if (!filter) {
            self.locationList().forEach(function(locationItem) {
                locationItem.visible(true);
            });
            return self.locationList();
        } else {
            return ko.utils.arrayFilter(self.locationList(), function(locationItem) {
                var string = locationItem.name.toLowerCase();
                var result = (string.search(filter) >= 0);
                locationItem.visible(result);
                return result;
            });
        }
    }, self);

    this.mapElem = document.getElementById('map');
    this.mapElem.style.height = window.innerHeight - 50;
}
// Bind the VeiewModel to the view using knockout
function startApp() {
    ko.applyBindings(new AppViewModel());
}

function errorHandling() {
    alert("Error loading page, try refresh in page.");
}

【问题讨论】:

    标签: knockout.js


    【解决方案1】:
    1. 您必须创建一个全局变量来保存正在显示的 infoWindow:

      var infowindow = null;

    2. 每次你去显示一个信息窗口时,你都会检查它是否不为空,然后关闭它。

      如果(信息窗口){ infowindow.close(); }

    3. 然后创建一个新实例并将其分配给变量:

      infowindow = 新的 google.maps.InfoWindow (); ...

    如果您有任何问题,请写信给我,我会帮助您。

    请原谅我的英语

    您可以在这里找到更多答案: Close all infowindows in Google Maps API v3

    【讨论】:

    • 非常感谢您的回复。我试着按照你的建议去做,但没有奏效。你能帮我吗?感谢您的宝贵时间。
    • 最好避免全局变量。您可以在 ViewModel 中创建 infoWindow 并将其传递给 Location 对象。 :-)
    【解决方案2】:

    您可以与所有Location 对象共享infoWindow。您需要将infoWindowLocation 移动到AppViewModel,以便只有该对象的一个​​实例。

    那么,AppViewModel 应该是:

    //-ViewModel
    function AppViewModel() {
        var self = this;
    
        // create array of places
    
        this.locationList = ko.observableArray([]);
        this.searchLocation = ko.observable('');
    
        var map = new google.maps.Map(document.getElementById('map'), {
            zoom: 12,
            center: {
                lat: 37.77986,
                lng: -122.429
            }
        });
    
        // ** Move the infoWindow from Location to AppViewModel.    
        var infoWindow = new google.maps.InfoWindow({
        });
    
    
        initialLocations.forEach(function(locationItem) {
            // To each Location object, pass the same infoWindow object
            self.locationList.push(new Location(locationItem, infoWindow, map));
        });
    
        // from here, the same code you have in AppViewModel
        ...
    }
    

    现在给Location函数(对象)添加一个参数:

    function Location(data, infoWindow, map) {
    

    评论infoWindow(或删除它,因为你有它作为参数):

        //// Info window
        //this.infoWindow = new google.maps.InfoWindow({
        //});
    

    并更改click 监听器:

        this.marker.addListener('click', function() {
    
            self.contentString = '<div class="info-window-content"><div class="title"><b>' + data.name + "</b></div>" +
                '<div class="content"><a href="' + self.URL + '">' + self.URL + "</a></div>" +
                '<div class="content">' + self.street + "</div>" +
                '<div class="content">' + self.city + "</div>" +
                '<div class="content"><a href="tel:' + self.phone + '">' + self.phone + "</a></div></div>";
    
            // ** Here, remove the 'self' in order to use the infoWindow received as parameter.
            infoWindow.setContent(self.contentString);
    
            // ** Here, remove the 'self' in order to use the infoWindow received as parameter.
            infoWindow.open(map, this);
    
            self.marker.setAnimation(google.maps.Animation.BOUNCE);
            setTimeout(function() {
                self.marker.setAnimation(null);
            }, 2100);
        });
    

    这样,您的所有Location 对象都将看到相同的infoWindow 对象。将只有一个infoWindow

    更新 至于 cmets,我看到 map 变成了一个全局变量。它在AppViewModel() 中声明,但应使用varlet 声明。我改变了它的定义。

    然后,我们应该为Location 对象添加一个新参数,即地图,因为现在不是全局变量。

    【讨论】:

    • 非常感谢,这非常有效。然而 // ** 将 infoWindow 从 Location 移动到 AppViewModel。 self.infoWindow = new google.maps.InfoWindow({ });只需 infoWindow = new google.maps.InfoWindow({ });
    • 那么infoWindow就变成了一个全局变量。您需要使用varlet 声明它:var infoWindow = new google.maps.InfoWindow({ });map 变量应该是 var map
    • 请查看此链接:w3schools.com/js/js_scope.asp。 “如果你给一个没有声明的变量赋值,它会自动变成一个GLOBAL变量。”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-17
    相关资源
    最近更新 更多