React Leaflet - 标记图像无法加载

React Leaflet - Marker image fails to load

问题

我在我的 React 项目中使用 leaflet v1.7.1react-leaflet v3.0.5

当我尝试React Router's "Setup" documentation page中的设置示例时,标记图标变成了损坏的图像,如下图红色圆圈所示:

根据 React Router 的文档,标记应该是这样的:

经检查,保存标记图像的 <img> 标签的 src 属性应为 https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png。但是,经过检查,我的 <img>src 属性原来是 gibberish-looking:

复制

我创建了一个包含我的代码的新沙箱:

或者,按照以下步骤重现该问题:

  1. npx create-react-app leaflet-test

  2. cd leaflet-test/

  3. npm i leaflet react-leaflet

  4. 在代码编辑器中打开项目。转到 App.js 并使用以下代码:

    import React from "react";
    import "./App.css";
    import "leaflet/dist/leaflet.css";
    import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
    
    const styles = {
      mapRoot: {
        height: 400,
      },
    };
    
    export default function App() {
      return (
        <MapContainer
          style={styles.mapRoot}
          center={[51.505, -0.09]}
          zoom={13}
          scrollWheelZoom={false}
        >
          <TileLayer
            attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          />
          <Marker position={[51.505, -0.09]}>
            <Popup>
              A pretty CSS3 popup. <br /> Easily customizable.
            </Popup>
          </Marker>
        </MapContainer>
      );
    }
    
  5. npm start

我不确定我是否在 React 中错误地 set-up Leaflet 或者它是来自 Leaflet 或 React Leaflet 的错误。提前致谢!

感谢FoundingBox的评论,原来这是React Leaflet的一个bug。

已经有GitHub issue thread regarding this bug and this comment建议了以下解决方案:

OK. It turns out that the problem was caused by including the leaflet CSS in the component's imports.

I've now just included a link to the CDN hosted leaflet.css file and it's working OK, but it would be good if this could be patched to work with create-react-app webpack config.

换句话说,这是分步指南:

  1. App.js 中删除 import "leaflet/dist/leaflet.css";。不要从任何 JS 文件中的节点模块导入 Leaflet CSS。

  2. 转到 public/index.html 并通过将以下代码粘贴到 HTML 文件的 <head> 部分来包含托管 leaflet.css 的 CDN:

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
      integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
      crossorigin=""/>
    

    (注意:link使用Leaflet v1.7.1。访问Leaflet's documentation找到link最新版Leaflet的代码)

作为参考,这是由于 webpack 重写了 CSS 中的 URL,而 Leaflet 使用它来检测其图标图像的路径。

详见Leaflet issue #4968

通过 CDN 使用 Leaflet 时,Leaflet CSS 没有被篡改,因此它可以正常工作。

您仍然可以通过 webpack 使用它,但是您应该只使用自定义图标,或者明确告诉 Leaflet 在哪里可以找到其默认图标的图像:

import L from 'leaflet';
delete L.Icon.Default.prototype._getIconUrl;

L.Icon.Default.mergeOptions({
  iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
  iconUrl: require('leaflet/dist/images/marker-icon.png'),
  shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});

我还专门为这种情况做了一个插件:leaflet-defaulticon-compatibility

Retrieve all Leaflet Default Icon options from CSS, in particular all icon images URL's, to improve compatibility with bundlers and frameworks that modify URL's in CSS.

import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css'; // Re-uses images from ~leaflet package
import * as L from 'leaflet';
import 'leaflet-defaulticon-compatibility';

我遇到了同样的问题,但最近发现了这个解决方案,我们需要做的就是将图标道具传递给标记组件。

import marker from '../../Assets/icons/Location.svg';
import { Icon } from 'leaflet'
const myIcon = new Icon({
 iconUrl: marker,
 iconSize: [32,32]
})

<MapContainer center={value} zoom={13} scrollWheelZoom={false}>
      <TileLayer
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      <Marker position={value} icon={myIcon}>
        <Popup>
        Location :{data}
        </Popup>
      </Marker>
    </MapContainer>

Check My Solution on CodeSandBox!