代码说明

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 functionmarkerinfoWindow
  参数被传递给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>

10-05 21:44