1. 问题
我想使用百度地图自定义dom
覆盖物,但是我想渲染react
组件,这里记录一下遇到的问题。
(百度地图示例)[lbs.baidu.com/jsdemo.htm#…]
1.1. 解决
首先想到的就是使用renderToString
,这个方法可以将组件渲染成一个字符串,通常用在ssr
上,但是百度地图是直接插入的dom
元素,所以必须返回一个dom
对象,字符串是不行的。
// CustomOverlay定义
// 官方的缺少定义
declare namespace BMapGL {
class CustomOverlay<P = any> extends Overlay {
constructor(dom: (properties: P) => HTMLElement, opts: CustomOverlayOptions);
}
interface CustomOverlay<P = any> extends Overlay {
setProperties: (properties: P) => void;
getProperties: () => P;
setOptions: (option: Partial<CustomOverlayOptions<P>>) => void;
setPoint: (point: BMapGL.Point) => void;
}
interface CustomOverlayOptions<P = any> {
point: Point;
offsetX?: number;
offsetY?: number;
MinZoom?: number;
MaxZoom?: number;
properties?: P;
enableMassClear?: boolean;
enableDraggingMap?: boolean;
}
}
// 大概的使用方法
const createDOM = (props: p) => {
return document.createElement('div')
};
const layer = new BMapGL.CustomOverlay<p>(createDOM, {point: new BMapGL.Point(0, 0)});
map.addOverlay(layer);
解决问题方法就是重新调用render
函数渲染组件,不过会丢失context
,如果你需要就只能手动穿进去了。
const createDOM = (props: SelectedAsset) => {
// 这里创建的是react的根节点
const container = document.createElement('div');
container.setAttribute('style', 'width: 100%;height: 100%;');
// 这里阻止了一些事件的冒泡
// 在弹窗操作的时候地图也操作了
container.onwheel = (e) => e.stopPropagation();
container.ondblclick = (e) => e.stopPropagation();
container.oncontextmenu = (e) => e.stopPropagation();
// 使用react的createRoot创建一个新的渲染节点
infoWindowRoot.current = createRoot(container);
// 这里返回的是新的react的根节点
return container;
};
// 然后就在渲染节点上创建覆盖物
infoWidnow.current = new BMapGL.CustomOverlay<SelectedAsset>(createDOM, {
point: new BMapGL.Point(0, 0),
offsetY: -40,
});
infoWidnow.current.hide?.();
map.current?.addOverlay(infoWidnow.current);
// 使用的时候就只需要调用render
useEffect(() => {
infoWidnow.current.setPoint(selectedAsset.point);
// 外部数据变化的时候就render
// 只要是同一个root重复调用render只会更新节点,而不是完全重新渲染
infoWindowRoot.current.render(
<InfoWidnow
selectedAsset={selectedAsset}
dict={initialState?.dict}
onClose={() => infoWidnow.current?.hide?.()}
/>,
);
infoWidnow.current.show?.();
}, [selectedAsset]);