Всплывающее окно всегда открыто в маркере

Есть ли способ, чтобы всплывающее окно всегда оставалось открытым? Нет необходимости нажимать на него, чтобы открыть.

Ожидаемое поведение

https://monosnap.com/file/mPkuSTmPAfwxTxY99YQVA5m96Zolow.png

Фактическое поведение

http://take.ms/cUej0

6 ответов

Решение

То, что вы можете сделать, это создать свой собственный класс Marker из маркера реагирования-листовки, а затем вызвать функцию листовки openPopup() для объекта листовки после его монтирования.

// Create your own class, extending from the Marker class.
class ExtendedMarker extends Marker {
    componentDidMount() {
        // Call the Marker class componentDidMount (to make sure everything behaves as normal)
        super.componentDidMount();

       // Access the marker element and open the popup.
      this.leafletElement.openPopup();
    }
}

Это сделает всплывающее окно открытым после монтирования компонента, а затем будет вести себя как обычное всплывающее окно, т.е. на закрытие / открытие.

Я собрал эту скрипку, которая показывает тот же код вместе с базовым примером.

С введением react-leaflet version 2 что приводит к серьезным изменениям в создании пользовательских компонентов, больше не поддерживается расширение компонентов с помощью наследования (см. эту ветку для более подробной информации)

На самом деле официальная документация React также рекомендует использовать композицию вместо наследования:

В Facebook мы используем React в тысячах компонентов, и мы не нашли ни одного случая использования, в котором мы бы рекомендовали создавать иерархии наследования компонентов.

Реквизит и композиция дают вам всю гибкость, необходимую для точной и безопасной настройки внешнего вида и поведения компонента. Помните, что компоненты могут принимать произвольные реквизиты, включая примитивные значения, элементы React или функции.

В следующем примере показано, как расширить компонент маркера, чтобы всплывающее окно оставалось открытым после отображения маркера:

const MyMarker = props => {

  const initMarker = ref => {
    if (ref) {
      ref.leafletElement.openPopup()
    }
  }

  return <Marker ref={initMarker} {...props}/>
}

Объяснение:

получить доступ к собственному объекту маркера листовки (leafletElement) и откройте всплывающее окно через Marker.openPopup метод

Вот демо

Вы можете использовать постоянные всплывающие подсказки, или React предоставляет ссылки для этого типа вещей... вы можете сделать это:

https://jsfiddle.net/jrcoq72t/121/

const React = window.React
const { Map, TileLayer, Marker, Popup } = window.ReactLeaflet

class SimpleExample extends React.Component {
  constructor () {
    super()
    this.state = {
      lat: 51.505,
      lng: -0.09,
      zoom: 13
    }
  }

  openPopup (marker) {
    if (marker && marker.leafletElement) {
      window.setTimeout(() => {
        marker.leafletElement.openPopup()
      })
    }
  }

  render () {
    const position = [this.state.lat, this.state.lng]
    return (
      <Map center={position} zoom={this.state.zoom}>
        <TileLayer attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="http://{s}.tile.osm.org/{z}/{x}/{y}.png" />
        <Marker position={position} ref={this.openPopup}>
          <Popup>
            <span>
              A pretty CSS3 popup. <br /> Easily customizable.
            </span>
          </Popup>
        </Marker>
      </Map>
    )
  }
}

window.ReactDOM.render(<SimpleExample />, document.getElementById('container'))

Рекомендации:

https://reactjs.org/docs/refs-and-the-dom.html

React.js - доступ к компонентным методам

Автоматическое открытие маркеров на всплывающей карте.

Вышеупомянутое больше не работает с реакцией-листовкой версии 3. В вашем пользовательском компоненте маркера, чтобы получить ссылку на элемент листовки, вы должны теперь использовать useRef() а затем откройте всплывающее окно в useEffect() после установки компонента.

      const MyMarker = (props) => {
  const leafletRef = useRef();
  useEffect(() => {
    leafletRef.current.openPopup();
  },[])
  return <Marker ref={leafletRef} {...props} />
}

Для нового реактивного листка v4 вам нужно будет внести некоторые изменения

         const CustomMarker = ({ isActive, data, map }) => {
                  const [refReady, setRefReady] = useState(false);
                  let popupRef = useRef();
                
                  useEffect(() => {
                    if (refReady && isActive) {
                      map.openPopup(popupRef);
                    }
                  }, [isActive, refReady, map]);
                
                  return (
                    <Marker position={data.position}>
                      <Popup
                        ref={(r) => {
                          popupRef = r;
                          setRefReady(true);
                        }}
                      >
                        {data.title}
                      </Popup>
                    </Marker>
                  );
                };

А затем используйте MapContainerкак это

      const MapComponent = () => {
  const [map, setMap] = useState(null);
  return (
    <div>
      <MapContainer
        ref={setMap}
        center={[45.34416, 15.49005]}
        zoom={15}
        scrollWheelZoom={true}
      >
        <CustomMarker
          isActive
          map={map}
          data={{
            position: [45.34416, 15.49005],
            title: "Text displayed in popup",
          }}
        />
      </MapContainer>
    </div>
  );
};

Отредактировано

Обратите внимание, что мое старое решение пыталось открыть всплывающее окно каждый раз, когда оно отображалось. Нашел другое решение, которое соответствовало моим потребностям, чтобы открыть его при изменении позиции. Обратите внимание, что я смотрю на position.lat, position.lng, поскольку они будут думать, что они всегда меняются, если вы передаете объект.

И да, это не идеальный машинописный текст, но это лучшее решение, которое я смог придумать.

      const CustomMarker: React.FC<CustomMarkerProps> = ({ position, children }) => {
  const map = useMap();

  const markerRef = useRef(null);

  useEffect(() => {
    try {
      // @ts-ignore
      if (markerRef.current !== null && !markerRef.current.isPopupOpen()) {
        // @ts-ignore
        markerRef.current.openPopup();
      }
    } catch (error) {}
  }, [position.lat, position.lng]);

  return (
    <Marker ref={markerRef} position={position}>
      <Popup>{children}</Popup>
    </Marker>
  );
};

export default CustomMarker;

Старое решение

Не удалось заставить его работать, используя useRefа также useEffect. Тем не менее, заставил его работать с вызовом openPopup()непосредственно из реф.

      import { LatLngLiteral, Marker as LMarker } from "leaflet";
import React from "react";
import { Marker } from "react-leaflet";

export interface CustomMarkerProps {
  position: LatLngLiteral;
  open?: boolean;
}
const CustomMarker: React.FC<CustomMarkerProps> = ({
  position,
  open = false,
  children,
}) => {
  const initMarker = (ref: LMarker<any> | null) => {
    if (ref && open) {
      ref.openPopup();
    }
  };

  return (
    <Marker ref={initMarker} position={position}>
      {children}
    </Marker>
  );
};

export default CustomMarker;
Другие вопросы по тегам