如何禁用mapbox中的事件监听器?

问题描述 投票:0回答:8

我正在尝试使用 React 上的 Mapbox 来控制图层上的事件监听器。 map.off 应该可以做到这一点,但它并没有删除图层中的 onclick 事件。 https://docs.mapbox.com/mapbox-gl-js/api/map/#map#off

但我做错了什么,所以我无法删除该事件。 这是我到目前为止所做的...

要添加事件,我这样做

map.on('click', 'building_footprints_click', addBuildingPopUp)

为了尝试删除它,我尝试过:

map.off('click', 'building_footprints_click', addBuildingPopUp); 

map.off('click', 'building_footprints_click');

map.off('click', addBuildingPopUp);

但它们都不起作用。 我读到我必须发送 on 事件的实例。所以我尝试:

let event = map.on('click', 'building_footprints_click', addBuildingPopUp)

以及与上面相同的三个关闭操作,但它们也不起作用

map.off('click', 'building_footprints_click', event); 

map.off('click', 'building_footprints_click');

map.off('click', event);

还有监听器功能, 我尝试过:

const addBuildingPopUp = (e) => {} 

and 
function addBuildingPopUp (e) {} 

and 
let addBuildingPopUp = function building (e) {}

这是一个基本的 Stackblitz,其中包含非工作函数的示例 https://stackblitz.com/edit/react-5maykf?file=src/App.js

https://react-5maykf.stackblitz.io/

javascript event-handling layer mapbox-gl
8个回答
5
投票

根据您的 stackblitz 我可以看到问题是您正在尝试取消注册不再存在的函数。

对于mapbox,您需要注册和注销相同的功能。我是说

map.on('mousemove', f1)
map.off('mousemove', f1)
您需要确保 f1 保持不变。

让我解释一下,每当 React 组件渲染时,它都会重新创建其体内的所有变量,除非它是状态变量的一部分,因为函数

addBuildingPopUp
在每个渲染上创建,mapboxgl 不会取消注册事件。

您需要做的唯一更改是确保

addBuildingPopUp
保持不变,您应该在 React 组件之外定义。


2
投票

我检查了您的 stackblitz 代码,并用注释相应地更新了工作答案。如果您对此有任何疑问,请告诉我

https://stackblitz.com/edit/react-mqjjkg?devtoolsheight=33&file=src/App.js


1
投票

传递给mapbox事件监听器的函数必须完全相同。每次在 React 中渲染组件时,该函数(尽管保持不变)都会被 javascript 识别为新声明的函数。因此,mapbox 将“关闭”一个不存在事件的监听器,因为它是一个从未存在过的函数。为了解决这个问题,你必须使用React“useCallback”。它确保功能在组件存在的过程中保持不变

export default function MapListeners() {
  const mode = useRecoilValue(interactivityMode);
  const setModal = useSetRecoilState(modalState);

  const removeListeners = () => {
    cuMap.off("click", setAddBeaconModal);
  };

  const setAddBeaconModal = useCallback(
    // useCallback ensures the functions stays identical
    (e: mapboxgl.MapMouseEvent & mapboxgl.EventData) => {
      // const coordinates = e.lngLat;

      setModal({
        key: AddBeaconModal.toString(),
        body: {
          component: AddBeaconModal,
          props: { word: "irgendwas", title: "Irrr" },
        },
        title: "Add Beacon",
      });
    },
    []
  );

  const setMapListeners = () => {
    removeListeners();

    switch (mode) {
      case "add":
        cuMap.on("click", setAddBeaconModal);
        break;
      case "lock":
        break;
      default:
    }
  };

  useEffect(setMapListeners, [mode]);

  return null;
}

1
投票

我已经在 React 中完成了。我花了几天时间尝试这样做。因此,就我而言,我想删除一个单击侦听器,该侦听器将添加一些自定义标记。这是我的做法(用于测试):

Attributes in File

const map = useRef(null);

map.current.on('click', (event) => addMarkerOnClick(event));
setTimeout(() => {
  console.log("Disabled")
  map.current.off('click', (event) => addMarkerOnClick(event));
}, 5000)

上面是我最初的代码,它不起作用。

    map.current.on('click', addMarkerOnClick);
    setTimeout(() => {
      console.log("Disabled")
      map.current.off('click', addMarkerOnClick);
    }, 5000)

这就是解决方案^

对于没有 React 用户,我建议:

// Attributes
let map = null

    map.on('click', addMarkerOnClick);
    setTimeout(() => {
      console.log("Disabled")
      map.off('click', addMarkerOnClick);
    }, 5000)

0
投票

如果您使用 React,只需将处理程序存储在 useRef 中,瞧,一切都会正常工作,这是类似的情况和建议的解决方案

这是解决方案的代码:

  const handleClickRef = useRef(handleClick)
  handleClickRef.current = handleClick
  map.on('mousedown', 'layer-id', handleClickRef.current)
  map.off('mousedown', 'layer-id', handleClickRef.current)

0
投票

我会帮忙的,因为今天早上我也遇到了类似的问题。我最终采用的解决方案是将传递给 map.on 和 map.off 的函数存储在带有空括号的 useCallback 挂钩内。效果非常好!


0
投票

在 React 上,您需要在组件外部定义函数

const showLayerInfo = (e: MapMouseEvent & { features?: MapboxGeoJSONFeature[] | undefined; } & EventData) => {
    console.log(e)
}

export default function Map(props: MapProps) {
  const mapContainer = useRef<HTMLDivElement>(null)
  const map = useRef<mapboxgl.Map>()

  map.current.off("mouseenter", layerData.name, showLayerInfo)
  map.current.on("mouseenter", layerData.name, showLayerInfo)

   return <>
     <div
        ref={mapContainer}
        className="map-container"
        style={{width: "100%", height: "100vh"}}
      />
    </>

}

-3
投票

我不知道你写这个问题时是否写错了,但你写了

map.on('click', 'building_footprints_click', addBuildingPop**UP**);
map.off('click', 'building_footprints_click', addBuildingPop**Up**); 

注意到函数名称中大小写的差异吗?

此语法是正确的,您应该使用它

如果问题是由于拼写错误造成的,我建议使用 linter 来避免将来出现这种情况

© www.soinside.com 2019 - 2024. All rights reserved.