首页 > 解决方案 > 如何在地图加载时打开特定的弹出窗口?

问题描述

将 React-Leaflet V3.1.0 与 Express 服务器一起使用。

我的用户要求能够使用以下格式的链接:

https://www.mymap.com/id/:category/:id/:zoom

这会向服务器发送一个请求,以获取它们链接到的标记的纬度/经度坐标,然后将起始位置设置为这些坐标。我已经设法使用 React Router Dom 使这部分工作。现在理想情况下,我希望能够在地图加载时打开这个特定标记的弹出窗口。通过我设置查询组件的方式,能够在生成标记以指示这是感兴趣的标记时通过道具传递布尔值不是问题,我只是不确定如何激活弹出窗口。

我不太熟悉 useRef 以及如何准确地使用它来访问不同的 Leaflet 方法,但我昨天做了一些实验,并且能够获得一些似乎是朝着正确方向迈出的行为。弹出窗口在初始启动时没有加载,但是当我在地图上导航时,其他弹出窗口开始自动打开。话虽如此,我的地图渲染了数千个标记,并且每个标记超过 1 个渲染不值得权衡这个相对利基的功能,除非第二次渲染可以仅隔离到感兴趣的标记。

我认为可以让我到达我想要的地方但我无法让这个特定的方法触发: https ://leafletjs.com/reference-1.6.0.html#popup-openon

我最终使用了openPopup()类似于此链接: https ://stackblitz.com/edit/react-awtgn6?file=Map.js

但是我只能通过 useEffect + useRef 来实现(上面提到的结果)。

在将弹出窗口打开状态存储为状态时,我觉得我遗漏了一些明显的东西?

基本代码示例:

<Marker
  position={[item.lat, item.lon]}
  icon={getIcon(item)}
>
  <Popup position={[item.lat, item.lon]}>
    <PopupContent
      item={item}
      userSettings={userSettings}
    />
  </Popup>
</Marker>

谢谢!

标签: reactjsleafletreact-leafletreact-leaflet-v3

解决方案


如果目标是打开标记的弹出窗口,条件id是在 url 参数(即url?id=3)中指定标记,这是可行的。

一个 ref 对象中的多个 ref

您需要映射一组标记,每个标记都有一个唯一的 id。您需要保留一个数组或引用对象,并且在映射时,在ref道具中,将引用添加到该对象数组:

const Map = (props) => {
  const [done, setDone] = React.useState(false);
  const markerRefs = React.useRef({});

return (
    <MapContainer {...mapContainerProps}>
      {data.map((marker, index) => {
        return (
          <Marker
            position={marker.coord}
            ref={(m) => {  // <--- add marker refs to ref object here
              markerRefs.current[marker.id] = m;
              if (index === data.length - 1 && !done) {
                setDone(true);
              }
            }}
          >
            <Popup>{marker.content}</Popup>
          </Marker>
        );
      })}
    </MapContainer>

在您的 map 语句执行后,您markerRefs将成为一个对象,其键是 id,其值是底层传单标记对象。

参考!==状态

一旦裁判准备好,您将需要一种方法来采取一些行动。您可以使用 useEffect 来做到这一点。现在请记住,将 ref 放在 useEffect 依赖数组中并不是一个好主意,因为对 ref 的更新不会触发重新渲染。因此,我创建了 state 变量done,它以 false 开头,但在地图的最后一次迭代中设置为 true。

打开弹出窗口

现在,我们创建了一个 useEffect,它在done为 true 时运行,这意味着 refs 已创建并且可用:

  useEffect(() => {
    let params = new URLSearchParams(document.location.search.substring(1));
    let id = params.get("id");
    if (id && done) {
      const markerToOpen = markerRefs.current[id];
      markerToOpen.openPopup();
    }
  }, [done]);

在这个 useEffect 中,我们检查 url 参数以获取 id。如果有 id,并且映射和引用是done,我们将根据标记的 id 获取标记 ref,并调用openPopup()它。

工作代码框

请记住,像codesandbox 或stackblitz 这样的沙盒类型网站有iframe,并且url 参数需要在那里可用。对于该沙箱,您需要将预览弹出到它自己的窗口中,或者使用 iframe 的 url:

在此处输入图像描述

您会看到,当您id在 url 搜索参数中指定时,该标记的弹出窗口在装载时打开。(我没有编写任何代码来检查标记是否存在,所以如果你id=doesnt_exist在那个例子中尝试,它会中断。你需要添加额外的逻辑来检查它)。

将其与 react-router 和您要使用的其他 url 参数集成需要一些额外的工作,但这就是我将如何使用 refs 和 state 的组合来通过对底层传单组件做出反应并完成您的工作想。

就带有许多标记的重新渲染而言,请记住,react-leaflet 3 进行了优化,不会导致重新渲染,而是为了触及底层的传单组件并调用它们的方法。您可能希望创建其他状态变量来跟踪以帮助解决此问题。例如,您可能有const [currentOpenMarker, setCurrentOpenMarker] = useState(), 并在其上放置一个 useEffect 以进入底层传单地图并调用map.closePopup()then currentOpenMarker.openPopup()


推荐阅读