Backbone.js と Google マップ - これとリスナーの問題
-
09-10-2019 - |
質問
Google Maps v3 用に作成したモジュールがあり、Backbone.js ビュー コンストラクターに変換しようとしています。
これまでのビューモジュールは次のとおりです。コードの後で発生する問題について説明します。
pg.views.CreateMap = Backbone.View.extend({
tagName: "div",
className: "map",
events: {},
latitude: "-23.56432",
longitude: "-46.65183",
initialize: function() {
_.bindAll(this, 'render', 'dragMarker', 'dragMap');
this.latlng = new google.maps.LatLng(this.latitude, this.longitude);
var myOptions = {
zoom: 16,
center: this.latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
this.map = new google.maps.Map($(this.el)[0], myOptions);
this.marker = new google.maps.Marker({
map: this.map,
position: this.latlng,
draggable: true
});
google.maps.event.addListener(this.marker, "dragend", this.dragMarker());
google.maps.event.addListener(this.map, "dragend", this.dragMap());
},
render: function() {
return this;
},
dragMarker: function() {
this.latlng = this.marker.getPosition();
this.map.panTo(this.latlng);
},
dragMap: function() {
this.latlng = this.map.getCenter();
this.marker.setPosition(this.latlng);
}
});
私が抱えている問題は、Google マップのイベント リスナーと「this」の処理方法にあります。
当初は、dragMarker メソッドと dragMap メソッドはなく、代わりに次の 2 つが初期化ブロック内にありました。
google.maps.event.addListener(this.marker, "dragend", function() {
this.latlng = this.marker.getPosition();
this.map.panTo(this.latlng);
});
google.maps.event.addListener(this.map, "dragend", function() {
this.latlng = this.map.getCenter();
this.marker.setPosition(this.latlng);
});
この最初のアプローチで私が遭遇した問題は、これらの匿名関数内の "this" がそれぞれ "this.marker" と "this.map" を参照していることです。この最初のアプローチの問題は、最初のリスナーでは「this.map」を参照する方法がないため、panTo() を実行できないことでした。2 番目のリスナーでは、「this.marker」を参照する方法がなかったため、setPosition() を使用してそのマーカーの周囲にマップを再配置することができませんでした。
次に、リスナー内の匿名関数を取り出してビューのメソッドとして宣言し、 _.bindAll(this, "dragMarker", "dragMap"); を実行できると考えました。
このアプローチの問題は、次のようにイベント ブロックにリスナーを記述しなければならないことです。
google.maps.event.addListener(this.marker, "dragend", this.dragMarker());
google.maps.event.addListener(this.map, "dragend", this.dragMap());
これは、newmap = new pg.views.CreateMap; でコンストラクターを呼び出したときを意味します。「this.dragMarker()」と「this.dragMap()」は、「dragend」イベントがトリガーされたときにコールバックとして評価されるのではなく、すぐに評価されることを確認します。
問題ないと思い、これらを次のように匿名関数でラップしました。
google.maps.event.addListener(this.marker, "dragend", function() {
this.dragMarker();
});
google.maps.event.addListener(this.map, "dragend", function() {
this.dragMap();
});
残念ながら、これにより、「this.dragMarker」の「this」が私が構築した親オブジェクトを参照しなくなり、代わりに「this.marker」を再度参照するという以前の問題に戻ります。2 番目のリスナーでも同じ問題が発生します。
ここで完全に行き詰まってしまいました。これを解決する方法について何かアイデアがある人はいますか?
解決
呼び出される匿名関数を取得します dragend
そして明示的にバインドします。
_.bindAll(this, 'dragMarker', 'dragMap');
google.maps.event.addListener(this.marker, "dragend", this.dragMarker);
/* etc ... */
こちらです this
コンテキスト外で呼び出された場合でも、常に CreateMap に関連付けられます。
他のヒント
私は、JavaScript で一般的な that/self ハックを使用して、この問題を解決しました。
var self = this;
google.maps.event.addListener(this.marker, "dragend", function() {
self.latlng = this.getPosition();
self.map.panTo(self.latlng);
});
google.maps.event.addListener(this.map, "dragend", function() {
self.latlng = this.getCenter();
self.marker.setPosition(self.latlng);
});
このハックを必要としない解決策を持っている人がいたら、私は大歓迎です。