如何仅使用 DOM 对象获取 leaflet.js 实例?

Posted

技术标签:

【中文标题】如何仅使用 DOM 对象获取 leaflet.js 实例?【英文标题】:How can I get a leaflet.js instance using only a DOM object? 【发布时间】:2014-04-02 03:24:33 【问题描述】:

我现在正在构建一个自定义的 Knockout.js 绑定来处理多边形的绘制。在这种情况下,Knockout API 只为我提供了对 DOM 对象的引用,以访问我需要更新的任何内容。然而,leaflet.js 的设计似乎希望用户将地图实例存储在他们的实现中。我没有那个选项。

尝试这个给了我一个错误:var existingMap = L.map('aMapIDGoesHere')

错误是:map already initialized

我可以使用 DOM 元素或元素 ID 访问地图实例吗?

根据要求,这是自定义绑定,请注意这是一项正在进行的工作:

ko.bindingHandlers.leafletDraw = 
  init: function(element, valueAccessor, allBindingsAccessor) 
    var map = L.map(element).setView([40, -90], 3);
    var tiles = L.tileLayer('http://s.tile.osm.org/z/x/y.png', 
        attribution: 'OSM',
        minZoom: 2
    ).addTo(map);

    // Initialise the FeatureGroup to store editable layers
    var editableLayers = new L.FeatureGroup();
    map.addLayer(editableLayers);

    // Initialise the draw control and pass it the FeatureGroup of editable layers
    var drawOptions = 
      edit: 
        featureGroup: editableLayers,
        remove: false
      ,
      draw: 
        polyline: false,
        circle: false,
        marker: false,
        polygon: 
          allowIntersection: false,
          showArea: true
        
      
    
    var drawControl = new L.Control.Draw(drawOptions);
    map.addControl(drawControl);

    // when a shape is first created
    map.on('draw:created', function (e) 
      var shapeString = $.map(e.layer._latlngs, function(pair)  return pair.lng.toString()+"::"+pair.lat.toString(); ).join(";;;");
      var value = valueAccessor();
      if (ko.isObservable(value)) 
        value(shapeString);
      

      editableLayers.addLayer(e.layer);

      drawControl.removeFrom(map);
      drawOptions.draw.polygon = false;
      drawOptions.draw.rectangle = false;
      var editControl = new L.Control.Draw(drawOptions);
      map.addControl(editControl);
    );

    // handle when a shape is edited
    map.on('draw:edited', function (e) 
      var editedLayer = e.layers._layers[Object.keys(e.layers._layers)[0]];
      var shapeString = $.map(editedLayer._latlngs, function(pair)  return pair.lng.toString()+"::"+pair.lat.toString(); ).join(";;;");
      var value = valueAccessor();
      if (ko.isObservable(value)) 
        value(shapeString);
      
    );
  ,
  update: function(element, valueAccessor) 
    // need to figure this out since we can't access leaflet params from 
  
;

特别说明 您会注意到我正在将点转换为串联字符串。这暂时是必要的。

【问题讨论】:

你能添加你的代码吗? @leszek.hanusz 完成。代码重要的部分位于底部的update 属性下。仅使用element 无法获取地图实例。 【参考方案1】:

只要您确定 DOM 元素不会被删除,您就可以将其作为子属性添加到 DOM 元素本身。这是一个绑定处理程序,它使用传单首页上的代码来设置传单地图:

ko.bindingHandlers.leaflet = 
    init: function(element, valueAccessor)
        var map = L.map(element);
        element.myMapProperty = map;
        L.tileLayer('http://s.tile.osm.org/z/x/y.png', 
            attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        ).addTo(map);
    ,
    update: function(element, valueAccessor)
        var existingMap = element.myMapProperty;
        var value = ko.unwrap(valueAccessor());
        var latitude = ko.unwrap(value.latitude);
        var longitude = ko.unwrap(value.longitude);
        var zoom = ko.unwrap(value.zoom);
        existingMap.setView([latitude, longitude], zoom);
    
;

要使用绑定处理程序,您只需像下面这样绑定:

<div data-bind="leaflet:  latitude: latitudeProperty, longitude: longitudeProperty, zoom: zoomProperty "></div>

只需确保您还设置了div 的样式,以确保它具有高度和宽度。我写了a jsfiddle which uses the above leaflet bindingHandler,你可以试试看。

我只在 Internet Explorer 11、Firefox 26.0 和 Firefox 27.0.1 中测试过这个 jsfiddle。

【讨论】:

哇,从未想过将其实际存储在 DOM 对象本身中。不错的想法 :) 在我的用例中,如果删除了 DOM 对象,那么无论如何都没有理由进一步访问它。谢谢! 您可能需要查看ko.utils.domNodeDisposal.addDisposeCallback,以确保在移除 DOM 对象时释放地图对象和事件侦听器。 ko.utils.domNodeDisposal.addDisposeCallback(element, function() element.myMapProperty.remove(); ); 或类似的东西应该可以正常工作。 (请注意,此注释中的代码完全未经测试。)【参考方案2】:

注意在非常有​​限的情况下,这可能是一个解决方案:https://***.com/a/60836683/1116657

window[Object.keys(window).find(key => key.substr(0,3) === "map")];

阅读我关于 cmets 的原始帖子,了解它的脆弱性和局限性,但认为这可能对某人有所帮助。谢谢!

【讨论】:

以上是关于如何仅使用 DOM 对象获取 leaflet.js 实例?的主要内容,如果未能解决你的问题,请参考以下文章

leaflet.js IE11:Tile imgs不可见,但它们仍在DOM中

Leaflet.js网格的白线

前端学习-使用JS库Leaflet.js生成世界地图并获取标注地址经纬度。

如何将 Angular JS 与 Leaflet.js 一起使用

在 Leaflet.js 地图周围包裹 GeoJSON 对象

如何在 iframe 中使用 Leaflet.js 中的地图