如何防止 React-Leaflet 地图子元素的事件冒泡

10

我有一个React-Leaflet地图,我在里面呈现了一个div

不知何故,与

的内容交互会导致位于下方的地图产生反应(例如:双击将缩放地图,拖动将平移地图) - 即使我在附加到
的处理程序中调用e.stopPropagation()

据我所知,调用stopPropagation()应该防止DOM事件到达地图本身。

为什么看起来stopPropagation()被忽略了?

如何渲染地图内部的

,而不让它的事件冒泡到地图本身?

这里是一个展示问题的示例代码

import { Map, TileLayer } from 'react-leaflet';

const MyMap = props => (
  <Map zoom={13} center={[51.505, -0.09]}>
    <TileLayer url={"http://{s}.tile.osm.org/{z}/{x}/{y}.png"} />

    {/* 
          HOW do I get this div to NOT pass it's events down to the map?!?! 
          Why does e.stopPropagation() appear to not work?
    */}
    <div 
      id="zone"
      onClick={e => e.stopPropagation()}
      onMouseDown={e => e.stopPropagation()}
      onMouseUp={e => e.stopPropagation()}
    >
      <p>Double-click or click and drag inside this square</p>
      <p>Why does the map zoom/pan?</p>
    </div>

  </Map>
);

ReactDOM.render(<MyMap />, document.getElementById('root'));
2个回答

9
对于 Leaflet 地图,请使用 L.DomEvent.disableClickPropagation,它会为元素的 'click''doubleclick''mousedown''touchstart' 事件添加 stopPropagation
示例:
function MyMap() {
  return (
    <div>
      <Map zoom={13} center={[51.505, -0.09]}>
        <TileLayer url={"http://{s}.tile.osm.org/{z}/{x}/{y}.png"} />
        <MyInfo />
      </Map>
    </div>
  );
}

where

function MyInfo() {
  const divRef = useRef(null);

  useEffect(() => {
    L.DomEvent.disableClickPropagation(divRef.current);
  });

  return (
    <div ref={divRef} id="zone">
      <p>Double-click or click and drag inside this square</p>
      <p>Why does the map zoom/pan?</p>
    </div>
  );
}

更新的 Codepen

备选方案

另一种阻止 div 元素传播到地图事件的选项是将 div 元素 放在 地图元素之外:

<div>
  <Map zoom={13} center={[51.505, -0.09]}>
    <TileLayer url={"http://{s}.tile.osm.org/{z}/{x}/{y}.png"} />
  </Map>
  <MyInfo />
</div>

在哪里

function MyInfo() {
  return (
    <div id="zone">
      <p>Double-click or click and drag inside this square</p>
      <p>Why does the map zoom/pan?</p>
    </div>
  );
}

我很想知道为什么在 div 上使用 e.stopPropagation() 不起作用。如果这些事件没有从 div 上传递,Leaflet 是如何接收这些事件的? - Alex McMillan
1
Leaflet注册事件监听器的方式内部实现时,为了为Leaflet控件(如ZoomIn控件)注册click事件处理程序执行了一些额外的步骤。仅为div元素注册stopPropagation并不能阻止Leaflet控件的点击事件触发(这就是地图缩放的原因)。 - Vadim Gremyachev
出现错误信息 L 未定义 - Tek Kshetri
3
@Tekson import L from 'leaflet'; 可以翻译为:“从'leaflet'导入L。” - teddybeard
我尝试了这种方法。它有效,但现在的问题是我无法点击地图内部div中的选择框(mui select)。 - Premshankar Tiwari
useEffect中,ref可能为null(因此会抛出诸如“无法读取null的属性('_leaflet_events')”之类的错误)。最好在分配时处理它,例如:ref={(ref) => {if (!ref) return; L.DomEvents.disableClickPropagation(ref); }}。我已用我的解决方案回答了这个问题。 - Fappaz

0

对于那些使用较新版本的react-leaflet(例如:^4.2.1)的人来说,我只能通过react-leaflet-custom-control使其正常工作。

{/* import Control from "react-leaflet-custom-control"; */}
<Control position="topright">
  <div
    ref={(ref) => {
      if (!ref) return;
      /** import L from "leaflet"; */
      L.DomEvent.disableClickPropagation(ref).disableScrollPropagation(ref);
    }}
  >
    <button onClick={() => console.log('Clicked')}>Click me</button>
  </div>
</Control>

Codesandbox

{{链接1:Codesandbox}}


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