代码说明
1.在viewModel内部声明了animateMarker
函数,其中一个参数为marker
。
2.在viewModel内部用三个参数(标记,信息窗口,元素)声明populateInfoWindow
,并在其中调用animateMarker
函数。
3.在遍历位置的循环内的click事件监听器中调用populateInfoWindow
。
4.将数据绑定:“单击:$ root.populateInfoWindow”添加到<li data-bind : "click : $root.populateInfoWindow >
错误
无法读取未定义的属性“标题”
同样,既不会标记动画,也不会显示infowindo。在单击列表项时。
是否存在针对此问题或想法的其他建议方法来解决该错误。
app.js
//模型包含有关位置的必需数据
var model = [
{
title: 'Park Ave Penthouse',
latLng: {
lat: 40.7713024,
lng: -73.9632393
}
},
{
title: 'Chelsea Loft',
latLng: {
lat: 40.7444883,
lng: -73.9949465
}
},
{
title: 'Union Square Open Floor Plan',
latLng: {
lat: 40.7347062,
lng: -73.9895759
}
},
{
title: 'East Village Hip Studio',
latLng: {
lat: 40.7281777,
lng: -73.984377
}
},
{
title: 'TriBeCa Artsy Bachelor Pad',
latLng: {
lat: 40.7195264,
lng: -74.0089934
}
},
{
title: 'Chinatown Homey Space',
latLng: {
lat: 40.7180628,
lng: -73.9961237
}
}
];
//declaring global variables
var infoWindow, map;
function initMap() {
//initialize the map
map = new google.maps.Map(document.getElementById('map'), {
center: model[3].latLng,
zoom: 12
});
myViewModel = new ViewModel();
ko.applyBindings(myViewModel)
};
function ViewModel() {
var self = this;
this.filter = ko.observable();
this.places = ko.observableArray(model);
self.infowindow = new google.maps.InfoWindow();
// self.marker = [];
model.forEach(function(element) {
var position = element.latLng;
var title = element.title;
element.marker = new google.maps.Marker({
position: position,
title: title,
map: map,
animation: google.maps.Animation.DROP,
});
// self.marker.push(element.marker);
element.marker.addListener('click', function() {
self.populateInfoWindow(this, self.infowindow, element);
});
});
self.populateInfoWindow = (function(marker, infowindow, element) {
self.infowindow.setContent('<div><strong>' + element.title + '</strong><br>');
self.infowindow.open(map, marker);
self.animateMarker(marker);
});
self.animateMarker = (function(marker) {
marker.setAnimation(google.maps.Animation.BOUNCE);
setTimeout(function() {
marker.setAnimation(null)
}, 1500);
});
this.visibleLocations = ko.computed(function() {
var filter = self.filter();
if (!filter) {
ko.utils.arrayForEach(self.places(), function(item) {
item.marker.setVisible(true);
});
return self.places();
} else {
return ko.utils.arrayFilter(self.places(), function(item) {
// set all markers visible (false)
var result = (item.title.toLowerCase().search(filter) >= 0);
item.marker.setVisible(result);
return result;
});
}
});
};
//loading google maps error handling
function googleError() {
alert("check your internet connection and reload the page");
}
index.html
<!DOCTYPE html>
<html>
<head>
<title> Nighbour hood map </title>
<link rel="stylesheet" type="text/css" href="css/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script type="text/javascript" src="js/lib/knockout-3.4.2.js"></script>
</head>
<body>
<div class="search-menu ">
<nav class="navbar navbar-light bg-faded justify-content-between">
<h1 class="navbar-brand"> Find your favorite place</h1>
<form class="form-inline">
<input class="form-control mr-sm-2" type="text" placeholder="Search" data-bind="textInput: filter">
</form>
</nav>
<ul class="list-group" data-bind="foreach: visibleLocations">
<li class="list-group-item list-group-item-action" data-bind="text: title, click :$root.populateInfoWindow"></li>
</ul>
</div>
<div id="map"></div>
<script type="text/javascript" src="js/app.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCX6bSgdTWvavwA0O8B7KsObZhE5GAf6yQ&callback=initMap" / onerror="googleError()" async defer>
</script>
</body>
</html>
最佳答案
由于InfoWindow.open
方法期望MVCObject
对象(此示例中的标记对象)为第二个参数,因此click
事件绑定需要从以下更改:
data-bind="click: $root.populateInfoWindow"
对此:
data-bind="click: $root.populateInfoWindow.bind(this,$data.marker,$root.infowindow)"
这样(通过
bind
function)marker
和infoWindow
参数被传递给
populateInfoWindow
函数修改示例
var model = [
{
title: 'Park Ave Penthouse',
latLng: {
lat: 40.7713024,
lng: -73.9632393
}
},
{
title: 'Chelsea Loft',
latLng: {
lat: 40.7444883,
lng: -73.9949465
}
},
{
title: 'Union Square Open Floor Plan',
latLng: {
lat: 40.7347062,
lng: -73.9895759
}
},
{
title: 'East Village Hip Studio',
latLng: {
lat: 40.7281777,
lng: -73.984377
}
},
{
title: 'TriBeCa Artsy Bachelor Pad',
latLng: {
lat: 40.7195264,
lng: -74.0089934
}
},
{
title: 'Chinatown Homey Space',
latLng: {
lat: 40.7180628,
lng: -73.9961237
}
}
];
//declaring global variables
var infoWindow, map;
function initMap() {
//initialize the map
map = new google.maps.Map(document.getElementById('map'), {
center: model[3].latLng,
zoom: 12
});
myViewModel = new ViewModel();
ko.applyBindings(myViewModel)
};
function ViewModel() {
var self = this;
this.filter = ko.observable();
this.places = ko.observableArray(model);
self.infowindow = new google.maps.InfoWindow();
// self.marker = [];
model.forEach(function (element) {
var position = element.latLng;
var title = element.title;
element.marker = new google.maps.Marker({
position: position,
title: title,
map: map,
animation: google.maps.Animation.DROP,
});
// self.marker.push(element.marker);
element.marker.addListener('click', function () {
self.populateInfoWindow(this, self.infowindow, element);
});
});
self.populateInfoWindow = (function (marker, infowindow, element) {
self.infowindow.setContent('<div><strong>' + marker.title + '</strong><br>');
self.infowindow.open(map, marker);
self.animateMarker(marker);
});
self.animateMarker = (function (marker) {
marker.setAnimation(google.maps.Animation.BOUNCE);
setTimeout(function () {
marker.setAnimation(null)
}, 1500);
});
this.visibleLocations = ko.computed(function () {
var filter = self.filter();
if (!filter) {
ko.utils.arrayForEach(self.places(), function (item) {
item.marker.setVisible(true);
});
return self.places();
} else {
return ko.utils.arrayFilter(self.places(), function (item) {
// set all markers visible (false)
var result = (item.title.toLowerCase().search(filter) >= 0);
item.marker.setVisible(result);
return result;
});
}
});
};
google.maps.event.addDomListener(window, 'load', initMap);
#map {
height: 140px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-debug.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript" src="app.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ"
crossorigin="anonymous">
<link href="style.css" rel="stylesheet">
<div class="search-menu ">
<nav class="navbar navbar-light bg-faded justify-content-between">
<h1 class="navbar-brand"> Find your favorite place</h1>
<form class="form-inline">
<input class="form-control mr-sm-2" type="text" placeholder="Search" data-bind="textInput: filter">
</form>
</nav>
<ul class="list-group" data-bind="foreach: visibleLocations">
<li class="list-group-item list-group-item-action" data-bind="text: title, click: $root.populateInfoWindow.bind(this,$data.marker,$root.infowindow)"></li>
</ul>
</div>
<div id="map"></div>