You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-Leaflet实现点击Marker动态改变地图中心位置

问题

我用Leaflet构建了一张地图,包含3个点位数据,每个点位都创建了带弹窗的Marker。当前地图中心是硬编码值,希望实现点击每个Marker时动态调整地图中心的功能,请问该如何实现?现有代码如下:

import L from "leaflet";
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import parse from "html-react-parser";

import logoFFB from "@/images/ffb.svg";

const Map = () => {
  const coordinates = [
    {
      id: 1,
      popup: `
        <div>
          <a href="#" target="_blank" class="cursor-pointer">
            <img class="max-w-[70px] my-5" src=${logoFFB} alt="Friends For Brands" />
          </a>
          <h4 class="font-bold text-lg text-red-500">Lorem Ipsum</h4>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean cursus ligula sapien, dignissim pretium nisl pharetra id.</p>
          <p>Maecenas venenatis blandit risus, eu faucibus lorem vehicula at. Aliquam finibus magna tellus, eu pharetra nibh vehicula sed.</p>
        </div>
      `,
      lat: 51.91662,
      lng: 4.4727,
    },
    {
      id: 2,
      popup: `
        <div>
          <a href="https://mediamarkt.nl" target="_blank" class="cursor-pointer">
            <img class="max-w-[100px] my-5" src="https://upload.wikimedia.org/wikipedia/commons/f/f0/Media_Markt_logo.svg" alt="Mediamarkt" />
          </a>
          <h4 class="font-bold text-lg text-red-500">Lorem Ipsum</h4>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean cursus ligula sapien, dignissim pretium nisl pharetra id.</p>
          <p>Maecenas venenatis blandit risus, eu faucibus lorem vehicula at. Aliquam finibus magna tellus, eu pharetra nibh vehicula sed.</p>
        </div>
      `,
      lat: 51.92019,
      lng: 4.48006,
    },
    {
      id: 3,
      popup: `
        <div>
          <a href="https://www.erasmusmc.nl" target="_blank" class="cursor-pointer">
            <img class="max-w-[120px] my-5" src="https://www.erasmusmc.nl/-/media/erasmusmc/images/_platform/logos/full-colour-svg-sophia-kinderziekenhuis-sub-brand-3.svg?la=nl-NL&hash=738FF636E5026AE3B56EE1D79492BB50" alt="MC Sophia" />
          </a>
          <h4 class="font-bold text-lg text-red-500">Lorem Ipsum</h4>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean cursus ligula sapien, dignissim pretium nisl pharetra id.</p>
          <p>Maecenas venenatis blandit risus, eu faucibus lorem vehicula at. Aliquam finibus magna tellus, eu pharetra nibh vehicula sed.</p>
        </div>
      `,
      lat: 51.911781,
      lng: 4.4696,
    },
  ];

  const CUSTOM_MARKER = `data:image/svg+xml;utf8,${encodeURIComponent(`<?xml version="1.0" encoding="iso-8859-1"?>
    <svg width="36px" height="36px" viewBox="-4 0 36 36" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <g id="Vivid.JS" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g id="Vivid-Icons" transform="translate(-125.000000, -643.000000)">
            <g id="Icons" transform="translate(37.000000, 169.000000)">
                <g id="map-marker" transform="translate(78.000000, 468.000000)">
                    <g transform="translate(10.000000, 6.000000)">
                        <path d="M14,0 C21.732,0 28,5.641 28,12.6 C28,23.963 14,36 14,36 C14,36 0,24.064 0,12.6 C0,5.641 6.268,0 14,0 Z" id="Shape" fill="#FF6E6E"></path>
                        <circle id="Oval" fill="#0C0058" fill-rule="nonzero" cx="14" cy="14" r="7"></circle>
                    </g>
                </g>
            </g>
        </g>
    </g>
  </svg>
  `)}`;

  return (
    <MapContainer
      id="map"
      center={[51.91662, 4.4727]}
      zoom={16}
      scrollWheelZoom={false}
    >
      <TileLayer
        attribution="&copy; Friends For Brands"
        url="https://tiles.stadiamaps.com/tiles/outdoors/{z}/{x}/{y}{r}.png"
      />

      {coordinates.map((coordinate) => (
        <Marker
          key={coordinate.id}
          position={[coordinate.lat, coordinate.lng]}
          icon={L.icon({
            iconUrl: CUSTOM_MARKER,
            iconSize: [35, 35],
            iconAnchor: [12, 12],
            popupAnchor: [0, 0],
          })}
        >
          <Popup className="text-md">{parse(coordinate.popup)}</Popup>
        </Marker>
      ))}
    </MapContainer>
  );
};

export default Map;

解决方案

要实现点击Marker时动态调整地图中心,只需通过React状态管理地图中心,并给Marker绑定点击事件更新状态即可,具体步骤:

  • 引入useState钩子,初始化地图中心状态为原硬编码值
  • 给每个Marker添加onClick事件,触发时将状态更新为当前Marker的坐标
  • 将MapContainer的center属性绑定到状态变量

修改后的完整代码:

import L from "leaflet";
import { useState } from "react";
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import parse from "html-react-parser";

import logoFFB from "@/images/ffb.svg";

const Map = () => {
  // 初始化地图中心状态
  const [mapCenter, setMapCenter] = useState([51.91662, 4.4727]);

  const coordinates = [
    {
      id: 1,
      popup: `
        <div>
          <a href="#" target="_blank" class="cursor-pointer">
            <img class="max-w-[70px] my-5" src=${logoFFB} alt="Friends For Brands" />
          </a>
          <h4 class="font-bold text-lg text-red-500">Lorem Ipsum</h4>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean cursus ligula sapien, dignissim pretium nisl pharetra id.</p>
          <p>Maecenas venenatis blandit risus, eu faucibus lorem vehicula at. Aliquam finibus magna tellus, eu pharetra nibh vehicula sed.</p>
        </div>
      `,
      lat: 51.91662,
      lng: 4.4727,
    },
    {
      id: 2,
      popup: `
        <div>
          <a href="https://mediamarkt.nl" target="_blank" class="cursor-pointer">
            <img class="max-w-[100px] my-5" src="https://upload.wikimedia.org/wikipedia/commons/f/f0/Media_Markt_logo.svg" alt="Mediamarkt" />
          </a>
          <h4 class="font-bold text-lg text-red-500">Lorem Ipsum</h4>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean cursus ligula sapien, dignissim pretium nisl pharetra id.</p>
          <p>Maecenas venenatis blandit risus, eu faucibus lorem vehicula at. Aliquam finibus magna tellus, eu pharetra nibh vehicula sed.</p>
        </div>
      `,
      lat: 51.92019,
      lng: 4.48006,
    },
    {
      id: 3,
      popup: `
        <div>
          <a href="https://www.erasmusmc.nl" target="_blank" class="cursor-pointer">
            <img class="max-w-[120px] my-5" src="https://www.erasmusmc.nl/-/media/erasmusmc/images/_platform/logos/full-colour-svg-sophia-kinderziekenhuis-sub-brand-3.svg?la=nl-NL&hash=738FF636E5026AE3B56EE1D79492BB50" alt="MC Sophia" />
          </a>
          <h4 class="font-bold text-lg text-red-500">Lorem Ipsum</h4>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean cursus ligula sapien, dignissim pretium nisl pharetra id.</p>
          <p>Maecenas venenatis blandit risus, eu faucibus lorem vehicula at. Aliquam finibus magna tellus, eu pharetra nibh vehicula sed.</p>
        </div>
      `,
      lat: 51.911781,
      lng: 4.4696,
    },
  ];

  const CUSTOM_MARKER = `data:image/svg+xml;utf8,${encodeURIComponent(`<?xml version="1.0" encoding="iso-8859-1"?>
    <svg width="36px" height="36px" viewBox="-4 0 36 36" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <g id="Vivid.JS" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g id="Vivid-Icons" transform="translate(-125.000000, -643.000000)">
            <g id="Icons" transform="translate(37.000000, 169.000000)">
                <g id="map-marker" transform="translate(78.000000, 468.000000)">
                    <g transform="translate(10.000000, 6.000000)">
                        <path d="M14,0 C21.732,0 28,5.641 28,12.6 C28,23.963 14,36 14,36 C14,36 0,24.064 0,12.6 C0,5.641 6.268,0 14,0 Z" id="Shape" fill="#FF6E6E"></path>
                        <circle id="Oval" fill="#0C0058" fill-rule="nonzero" cx="14" cy="14" r="7"></circle>
                    </g>
                </g>
            </g>
        </g>
    </g>
  </svg>
  `)}`;

  return (
    <MapContainer
      id="map"
      center={mapCenter}
      zoom={16}
      scrollWheelZoom={false}
    >
      <TileLayer
        attribution="&copy; Friends For Brands"
        url="https://tiles.stadiamaps.com/tiles/outdoors/{z}/{x}/{y}{r}.png"
      />

      {coordinates.map((coordinate) => (
        <Marker
          key={coordinate.id}
          position={[coordinate.lat, coordinate.lng]}
          icon={L.icon({
            iconUrl: CUSTOM_MARKER,
            iconSize: [35, 35],
            iconAnchor: [12, 12],
            popupAnchor: [0, 0],
          })}
          onClick={() => setMapCenter([coordinate.lat, coordinate.lng])}
        >
          <Popup className="text-md">{parse(coordinate.popup)}</Popup>
        </Marker>
      ))}
    </MapContainer>
  );
};

export default Map;

内容的提问来源于stack exchange,提问作者Galanthus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:20:35