如何阻止Ionic React中Leaflet弹窗内的复制函数在地图渲染时自动触发
问题原因
- 你当前的写法在拼接弹窗HTML字符串时直接执行了
writeToClipboard(part, id),函数会在图层渲染遍历的阶段就批量触发,不是点击按钮时才执行,这是直接导致崩溃的核心原因。 - Leaflet的
bindPopup方法接收的是原生HTML字符串,内嵌的onclick事件只能访问全局作用域下的方法,无法直接调用React组件内部定义的函数,所以常规的React箭头函数包装写法不生效。
解决方案
步骤1:将复制方法挂载到全局作用域
用useEffect在组件挂载时把复制方法挂到window上,卸载时清理避免内存泄漏。
步骤2:修正弹窗HTML的事件绑定写法
用模板字符串拼接弹窗内容,把参数以字符串形式传入全局方法的调用语句中,不要直接执行函数。
额外优化
你当前给两个GeoJSON图层绑定了同一个ref,后挂载的图层会覆盖前一个的ref引用,调用resetStyle时只会作用到最后一个图层,建议要么把两个图层数据合并成一个GeoJSON,要么分开定义两个ref。
修改后完整代码
import { useState, useRef, useMemo, useEffect } from 'react'; import { MapContainer, LayersControl, TileLayer, GeoJSON } from 'react-leaflet'; import { Clipboard } from '@capacitor/clipboard'; // 请自行补充position、zoom、PL、WWD等缺失的变量定义 function LeafletMap() { const [map, setMap] = useState(null) const geoJsonRefPL = useRef(); const geoJsonRefWWD = useRef(); useEffect(() => { // 挂载全局复制方法 window.writeToClipboard = async (part, id) => { const copyText = JSON.stringify(part.concat(id)); await Clipboard.write({ string: copyText }); }; // 卸载时清理 return () => { delete window.writeToClipboard; }; }, []); const onEachClick = (info, layer) => { const part = info.properties.Objekt_ID const id = info.properties.FID_ // 修正弹窗拼接逻辑,用模板字符串拼接函数调用语句 layer.bindPopup( `Objekt ID: <b>${part}</b><br>Abschnitt ID: <b>${id}</b><br><button onclick="window.writeToClipboard('${part}', '${id}')">Copy to Clipboard</button>` ); layer.on({ click: handleFeatureClick }); }; const handleFeatureClick = (e) => { // 两个图层都重置样式 geoJsonRefPL.current?.resetStyle(); geoJsonRefWWD.current?.resetStyle(); const layer = e.target; layer.setStyle({ color: "red" }); }; const displayMap = useMemo( () => ( <MapContainer center={position} zoom={zoom} scrollWheelZoom={false} whenCreated={setMap}> <LayersControl position="topright"> <LayersControl.BaseLayer checked name="OpenStreetMap - Karte"> <TileLayer attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png" /> </LayersControl.BaseLayer> <LayersControl.BaseLayer name="Esri - Satellit"> <TileLayer attribution='Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' url="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}" /> </LayersControl.BaseLayer> </LayersControl> <GeoJSON data={PL.features} onEachFeature={onEachClick} ref={geoJsonRefPL}/> <GeoJSON data={WWD.features} onEachFeature={onEachClick} ref={geoJsonRefWWD}/> </MapContainer> ), [], ) window.dispatchEvent(new Event('resize')); return ( <div> {displayMap} </div> ) } export { LeafletMap }
内容的提问来源于stack exchange,提问作者jonsken
相关产品推荐
相关产品推荐

