弹出窗口始终在标记中打开
Popup always open in the marker
有什么方法可以让弹窗始终保持打开状态,而不需要点击它来打开?
你可以做的是用react-leaflet marker制作你自己的Markerclass,然后在leaflet对象挂载后调用leaflet函数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();
}
}
这将使弹出窗口在安装组件后打开,之后也将像普通弹出窗口一样运行,即。在 close/open.
我将显示相同代码的 fiddle 与基本示例放在一起。
你可以使用永久 ,或者 React 为这种类型的东西提供 refs...你可以这样做:
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='© <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 - access to component methods
随着 react-leaflet version 2
的引入,它带来了 creating custom components, it is no longer supported to extend components via inheritance (refer this thread 方面的重大变化以获取更多详细信息)
其实React official documentation也推荐使用组合代替继承:
At Facebook, we use React in thousands of components, and we haven’t
found any use cases where we would recommend creating component
inheritance hierarchies.
Props and composition give you all the flexibility you need to
customize a component’s look and behavior in an explicit and safe way.
Remember that components may accept arbitrary props, including
primitive values, React elements, or functions.
以下示例演示了如何扩展标记组件以便在显示标记后保持弹出窗口打开:
const MyMarker = props => {
const initMarker = ref => {
if (ref) {
ref.leafletElement.openPopup()
}
}
return <Marker ref={initMarker} {...props}/>
}
解释:
获取本机传单标记对象 (leafletElement
) 并通过 Marker.openPopup
method 打开弹出窗口
以上不再适用于 react-leaflet 版本 3。在您的自定义标记组件中,要获取对传单元素的引用,您现在应该使用 useRef()
然后在 [=12] 中打开弹出窗口=] 安装组件后。
const MyMarker = (props) => {
const leafletRef = useRef();
useEffect(() => {
leafletRef.current.openPopup();
},[])
return <Marker ref={leafletRef} {...props} />
}
已编辑
请注意,我的旧解决方案每次呈现时都会尝试打开弹出窗口。
找到了另一个适合我需要的解决方案,当位置改变时打开它。请注意,我查看了 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
使其工作。但是,它可以直接从 ref.
调用 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;
对于新的 react-leaflet 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>
);
};
有什么方法可以让弹窗始终保持打开状态,而不需要点击它来打开?
你可以做的是用react-leaflet marker制作你自己的Markerclass,然后在leaflet对象挂载后调用leaflet函数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();
}
}
这将使弹出窗口在安装组件后打开,之后也将像普通弹出窗口一样运行,即。在 close/open.
我将显示相同代码的 fiddle 与基本示例放在一起。
你可以使用永久
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='© <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 - access to component methods
随着 react-leaflet version 2
的引入,它带来了 creating custom components, it is no longer supported to extend components via inheritance (refer this thread 方面的重大变化以获取更多详细信息)
其实React official documentation也推荐使用组合代替继承:
At Facebook, we use React in thousands of components, and we haven’t found any use cases where we would recommend creating component inheritance hierarchies.
Props and composition give you all the flexibility you need to customize a component’s look and behavior in an explicit and safe way. Remember that components may accept arbitrary props, including primitive values, React elements, or functions.
以下示例演示了如何扩展标记组件以便在显示标记后保持弹出窗口打开:
const MyMarker = props => {
const initMarker = ref => {
if (ref) {
ref.leafletElement.openPopup()
}
}
return <Marker ref={initMarker} {...props}/>
}
解释:
获取本机传单标记对象 (leafletElement
) 并通过 Marker.openPopup
method 打开弹出窗口
以上不再适用于 react-leaflet 版本 3。在您的自定义标记组件中,要获取对传单元素的引用,您现在应该使用 useRef()
然后在 [=12] 中打开弹出窗口=] 安装组件后。
const MyMarker = (props) => {
const leafletRef = useRef();
useEffect(() => {
leafletRef.current.openPopup();
},[])
return <Marker ref={leafletRef} {...props} />
}
已编辑
请注意,我的旧解决方案每次呈现时都会尝试打开弹出窗口。 找到了另一个适合我需要的解决方案,当位置改变时打开它。请注意,我查看了 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
使其工作。但是,它可以直接从 ref.
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;
对于新的 react-leaflet 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>
);
};