如何在Mapbox GL中以编程方式关闭所有弹出窗口?

21

我知道在Mapbox GL API中有Marker.togglePopup(),但我们能否通过编程的方式关闭所有弹出窗口呢?


1
与 https://dev59.com/35zha4cB1Zd3GeqPL-Mu 相同,这假设弹出窗口与某些标记相关联。我在地图上使用的是不附加到任何标记的弹出窗口(就像在示例 https://www.mapbox.com/mapbox-gl-js/example/popup/ 中一样)。有没有办法从地图中获取所有打开的弹出窗口? - Suma
6个回答

19

这里是一个例子:https://jsfiddle.net/kmandov/eozdazdr/
点击右上角的按钮来打开/关闭弹出窗口。

假设你有一个弹出窗口和一个标记:

var popup = new mapboxgl.Popup({offset:[0, -30]})
    .setText('Construction on the Washington Monument began in 1848.');

new mapboxgl.Marker(el, {offset:[-25, -25]})
    .setLngLat(monument)
    .setPopup(popup)
    .addTo(map);

您可以通过调用以下方式关闭弹出窗口:

popup.remove();

或者你可以通过调用以下方法来打开它:

or you can open it by calling:

-->

或者您可以调用以下方式进行打开:

popup.addTo(map);

正如在标记源代码中所看到的,togglePopup内部使用了这两种方法:

togglePopup() {
    var popup = this._popup;

    if (!popup) return;
    else if (popup.isOpen()) popup.remove();
    else popup.addTo(this._map);
}

5
这段代码可以关闭特定的弹窗,但并没有解决地图上“所有弹窗”的问题,因为它假设你有popup的引用才能调用popup.remove()。有没有一种方法可以获取地图上所有弹出窗口的句柄? - Stephen Lead
1
@StephenLead 请查看我的回答,了解如何关闭所有弹出窗口,无论它们是如何创建的。 - squarecandy

16

已接受的答案不适用于我的用例(我没有使用标记)。我能够通过利用mapbox内置的事件工作流来想出一种不同的解决方案。希望这能帮助其他人。

Mapbox允许您在地图上监听事件(并手动触发它们)。文档没有提到,但您可以使用自定义事件。

假设您有一个弹出窗口:

// Create popup and add it to the map
const popup = new mapboxgl.Popup({ offset: 37, anchor: 'bottom' }).setDOMContent('<h5>Hello</h5>').setLngLat(feature.geometry.coordinates).addTo(map);

// Add a custom event listener to the map
map.on('closeAllPopups', () => {
  popup.remove();
});

当你想关闭所有弹出窗口时,请触发该事件:

map.fire('closeAllPopups');

你基本上是将弹出窗口存储在一个变量中,并通过该变量访问它。但希望有一种方法可以直接从地图本身访问它。例如:map.getMarker(id) - Pankaj
我真的很喜欢这种方法,之前不知道可以创建和调用自定义函数(例如“closeAllPopups”),直到看了这个答案。在未来使用Mapbox时,我会更多地使用它。 - Harry Ronchetti

8

Mapbox会自动为弹出窗口使用类.mapboxgl-popup。您还可以使用options.className添加其他类。

因此,如果您有jQuery可用,只需执行以下操作:

$('.mapboxgl-popup').remove();

或者纯Javascript:

const popup = document.getElementsByClassName('mapboxgl-popup');
if ( popup.length ) {
    popup[0].remove();
}

我相信你可以假定只有一个弹出框是打开的。默认行为似乎是,如果一个弹出框已经打开并且点击了第二个项目,则第一个弹出框在第二个弹出框打开时会被完全从DOM中移除。如果您的应用程序以某种方式允许多个弹出框同时打开,则需要使用纯js循环遍历并删除每个弹出框,而不仅仅使用第一个项目。


1
不能假设只有一个弹出窗口是安全的。您可以设置 {closeOnClick: false} 并且在屏幕上适合的数量有多少个弹出窗口。 - blindguy
好的,很酷,做得好,但基本前提仍然有效。上面的jQuery应该“只是工作”,而纯js则需要循环遍历popup以删除每一个。 - squarecandy

2
遍历活动弹出窗口并将其移除
var popups = []; // all your popups
popups.forEach(function (item) {
   item.popup.remove();
});

1

我知道这是一个老问题,但最近我在 Mapbox 上工作。从 mapbox-gl v2.3 开始,mapboxgl.Popup 有一个 closeOnClick 属性,如果设置为true,则在您点击弹出窗口外部时,弹出窗口会消失。

let popup = new mapboxgl.Popup({
  anchor: "top",
  closeOnClick: true,
});

map.on(
  "click",
  "location",
  (e) => {
    map.getCanvas().style.cursor = "pointer";

    let coordinates = e.features[0].geometry.coordinates.slice();

    popup
      .setLngLat(coordinates)
      .setHTML("what I want to display")
      .addTo(map);
  }
);

或者,您可以在“mouseenter”上显示弹出窗口,而不是在“click”上,并添加一个“mouseleave”事件来删除弹出窗口:

  map.on(
  "mouseleave",
  "location",
  () => {
    map.getCanvas().style.cursor = "";
     popup.remove();
  }
);

0
将你的弹出窗口包装在 React.StrictModecloseOnClick={false} 中。
const [popup, setPopup] = useState<boolean>(false);
...
{popup && (
<React.StrictMode>
    <Popup longitude={52.001126260374704} latitude={34.906269171550214}
           anchor="bottom"
           onClose={() => {
               setPopup(false)
           }}
           closeOnClick={false}
    >
        You are here
    </Popup>
</React.StrictMode>
)}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接