使用 react-leaflet 在标记内实现动态 JSX 元素
Posted
技术标签:
【中文标题】使用 react-leaflet 在标记内实现动态 JSX 元素【英文标题】:Implementing a dynamic JSX element within a marker, using react-leaflet 【发布时间】:2018-04-11 14:48:05 【问题描述】:我有一个 React 应用程序,我在其中使用 Leaflet 到 react-leaflet,这两个库都非常有用。
在这个应用程序中,我有一组坐标需要渲染如下:
缩小时,将坐标聚集到标记簇中,如下所示
放大时,每个Marker都需要有
-
它下面有一个动态倒数计时器
一个动态的 SVG 倒计时时钟,就像这样
对于集群,我使用react-leaflet-markercluster 插件,它非常适合显示静态内容。
但是当我需要在每个标记中显示任何动态内容时,我没有发送JSX
的选项,只能提供静态html,从可用的示例here 可以看出。
// Template for getting popup html MarkerClusterGroup
// IMPORTANT: that function returns string, not JSX
function getStringPopup(name)
return (`
<div>
<b>Hello world!</b>
<p>I am a $name popup.</p>
</div>
`);
// that function returns Leaflet.Popup
function getLeafletPopup(name)
return L.popup( minWidth: 200, closeButton: false )
.setContent(`
<div>
<b>Hello world!</b>
<p>I am a $name popup.</p>
</div>
`);
有没有办法处理这种情况?如何制作 JSX 标记而不是静态 HTML 标记?
PS:我已经尝试过使用 ReactDOM.renderToString
already,但这是一个丑陋的 hack,并且每次都需要重新渲染标记。
TIA!!
这里有一个示例WebpackBin,如果您有解决方案,可以尝试一下
【问题讨论】:
似乎是重复的***.com/questions/37079847/… @Vlad 实际上,我并没有考虑使用renderToString
作为解决方案。我希望在这里使用 JSX,而不是静态 HTML
那么为什么不将 jsx 渲染为隐藏的(使用 css)html 并将其作为 .innerHTML
传递呢?
@Vlad 您能否更新提供的 bin 以显示您的意思?我不太明白
哦,我的意思是回答我在上面发布链接的问题
【参考方案1】:
我现在想出了一些将自定义 JSX 渲染为标记的工作代码。
这是https://jahed.io/2018/03/20/react-portals-and-leaflet/ 95% 的副本和https://github.com/PaulLeCam/react-leaflet/blob/master/src/Marker.js 的5% 灵感
我相信有些东西可以进一步优化。
import * as React from 'react';
import createPortal from "react-dom";
import DivIcon, marker from "leaflet";
import * as RL from "react-leaflet";
import MapLayer from "react-leaflet";
import difference from "lodash";
const CustomMarker = (RL as any).withLeaflet(class extends MapLayer<any>
leafletElement: any;
contextValue: any;
createLeafletElement(props: any)
const map, layerContainer, position, ...rest = props;
// when not providing className, the element's background is a white square
// when not providing iconSize, the element will be 12x12 pixels
const icon = new DivIcon( ...rest, className: '', iconSize: undefined );
const el = marker(position, icon: icon, ...rest );
this.contextValue = ...props.leaflet, popupContainer: el ;
return el;
updateLeafletElement(fromProps: any, toProps: any)
const position: fromPosition, zIndexOffset: fromZIndexOffset, opacity: fromOpacity, draggable: fromDraggable, className: fromClassName = fromProps;
const position: toPosition, zIndexOffset: toZIndexOffset, toOpacity, draggable: toDraggable, className: toClassName = toProps;
if(toPosition !== fromPosition)
this.leafletElement.setLatLng(toPosition);
if(toZIndexOffset !== fromZIndexOffset)
this.leafletElement.setZIndexOffset(toZIndexOffset);
if(toOpacity !== fromOpacity)
this.leafletElement.setOpacity(toOpacity);
if(toDraggable !== fromDraggable)
if(toDraggable)
this.leafletElement.dragging.enable();
else
this.leafletElement.dragging.disable();
if(toClassName !== fromClassName)
const fromClasses = fromClassName.split(" ");
const toClasses = toClassName.split(" ");
this.leafletElement._icon.classList.remove(
...difference(fromClasses, toClasses)
);
this.leafletElement._icon.classList.add(
...difference(toClasses, fromClasses)
);
componentWillMount()
if(super.componentWillMount)
super.componentWillMount();
this.leafletElement = this.createLeafletElement(this.props);
this.leafletElement.on("add", () => this.forceUpdate());
componentDidUpdate(fromProps: any)
this.updateLeafletElement(fromProps, this.props);
render()
const children = this.props;
const container = this.leafletElement._icon;
if(!container)
return null;
const portal = createPortal(children, container);
const LeafletProvider = (RL as any).LeafletProvider;
return children == null || portal == null || this.contextValue == null ? null : (
<LeafletProvider value=this.contextValue>portal</LeafletProvider>
)
);
然后像这样在你的组件中使用它:
<Map ...>
<CustomMarker position=[50, 10]>
<Tooltip>
tooltip
</Tooltip>
<Popup>
popup
</Popup>
<div style= backgroundColor: 'red' onClick=() => console.log("CLICK")>
CUSTOM MARKER CONTENT
</div>
MORE CONTENT
</CustomMarker>
</Map>
如果你不使用 TypeScript。只需删除 as any
和 : any
的东西。
编辑:某些东西会自动设置 width: 12px;
和 height: 12px;
。我还不确定,如何防止这种情况。其他一切似乎都运行良好!
EDIT2:修复它!使用iconSize: undefined
EDIT3:还有这个:https://github.com/OpenGov/react-leaflet-marker-layer 没测试过,但是示例代码看起来不错。
【讨论】:
以上是关于使用 react-leaflet 在标记内实现动态 JSX 元素的主要内容,如果未能解决你的问题,请参考以下文章