使用react的ant-design-pro框架写一个地图组件,可以搜索地图,可以点击地图获取点击的位置及经纬度

首先,先创建一个地图页面,用于显示地图组件,我是在pages文件中创建了一个mapSearch组件。
然后在routes.ts中注册页面。

 {
    path: '/mapSearch',
    name: 'mapSearch',
    icon: 'smile',
    component: './mapSearch',
  },

第三步就是使用高德地图来创建地图。
关键步骤:

1. 初始化状态和引用

  • 使用了 useRef 和 useState 钩子初始化了一些状态:
    • mapContainerRef: 引用地图容器,用于在页面中渲染地图。
    • mapRef: 引用地图实例和标记,用于在后续操作中修改地图或标记。
    • geocoder: 用于逆地理编码,转换坐标到实际地址。
    • mapLoaded: 用于标记地图是否加载完成。
    • placeSearchRef: 用于搜索地址的插件实例。
    • latitude 和 longitude: 存储当前地图中心的纬度和经度。
    • form: Ant Design 的表单实例,用于表单的操作和数据绑定。

2. 加载高德地图 API

  • 在 useEffect 中加载高德地图 API:
    • 通过判断 window.AMap 是否已加载,如果已经加载则直接初始化相关插件(AMap.PlaceSearch 和 AMap.Geocoder),并将它们存储在 placeSearchRef 和 geocoder 状态中。
    • 如果 window.AMap 未加载,动态加载地图脚本,并在脚本加载完成后初始化插件。

3. 地图初始化和点击事件

  • 在另一个 useEffect 中初始化地图:
    • new window.AMap.Map: 创建并渲染地图实例。
    • new window.AMap.Marker: 创建一个标记点,显示在地图上,标记当前的位置(默认位置为北京的经纬度)。
    • 监听地图的点击事件 (map.on('click')),用户点击地图时会更新标记位置和地图中心,同时更新表单中的坐标。
    • 使用 geocoder.getAddress 获取逆地理编码信息,填充地址到表单中。

4. 地址搜索功能

  • handleSearch:当用户在输入框中输入地址并点击搜索时,执行以下操作:
    • 获取用户输入的地址值。
    • 使用 placeSearchRef.search 进行地址搜索,返回结果后获取第一个地点(POI)的坐标。
    • 更新地图和标记的位置,并使用逆地理编码获取该地点的完整地址,更新到表单中。

5. 表单项

  • 在页面中渲染了一个表单:
    • 地址搜索框 (<Input.Search />):允许用户输入地址并点击搜索。
    • 经纬度输入框:用户可以直接输入经纬度来定位地图,输入后会更新地图的中心点和标记位置。

6. 地图渲染

  • mapContainerRef:用来显示地图的容器。地图会渲染在这里,容器的大小和样式由 style 属性控制。

代码如下:

import React from 'react';
import { useEffect, useState, useRef } from 'react';
import { message, Input } from 'antd';
import { Form } from 'antd';
// 地图页面 搜索地图的组件
const mapSearch: React.FC = () => {
  const mapContainerRef = useRef<HTMLDivElement>(null);
  const mapRef = useRef<any>(null);
  const [geocoder, setGeocoder] = useState<any>(null);
  const [mapLoaded, setMapLoaded] = useState(false);
  const [placeSearchRef, setPlaceSearchRef] = useState<any>(null);
  const [latitude, setLatitude] = useState<number>(39.9042); // 默认纬度:北京
  const [longitude, setLongitude] = useState<number>(116.4074); // 默认经度:北京
  const [form] = Form.useForm();
  // 加载高德地图 API
  useEffect(() => {
    window._AMapSecurityConfig = { securityJsCode: '填写你的密钥' };
    if (window.AMap) {
      setMapLoaded(true);
      window.AMap.plugin(['AMap.PlaceSearch', 'AMap.Geocoder'], () => {
        setPlaceSearchRef(
          new window.AMap.PlaceSearch({
            pageSize: 5,
            city: '全国',
          }),
        );
        const geo = new window.AMap.Geocoder({
          radius: 1000, // 查询半径,单位:米
          extensions: 'all', // 返回更多详情
        });
        setGeocoder(geo);
      });
    } else {
      const script = document.createElement('script');
      script.src = 'https://webapi.amap.com/maps?v=1.4.15&key=填写你的key';
      script.async = true;
      script.onload = () => {
        setMapLoaded(true);
        window.AMap.plugin(['AMap.PlaceSearch', 'AMap.Geocoder'], () => {
          setPlaceSearchRef(
            new window.AMap.PlaceSearch({
              pageSize: 5,
              city: '全国',
            }),
          );
          const geo = new window.AMap.Geocoder({
            radius: 1000,
            extensions: 'all',
          });
          setGeocoder(geo);
        });
      };
      script.onerror = () => {
        message.error('高德地图 API 加载失败');
      };
      document.body.appendChild(script);
      return () => {
        document.body.removeChild(script);
      };
    }
  }, []);

  // 初始化或更新地图
  useEffect(() => {
    if (mapLoaded && mapContainerRef.current) {
      const map = new window.AMap.Map(mapContainerRef.current, {
        center: [longitude, latitude], // 定位到北京
        zoom: 15,
      });
      const marker = new window.AMap.Marker({
        map,
        position: [longitude, latitude],
      });
      // 在初始化地图的useEffect中修改点击事件处理
      map.on('click', (e: any) => {
        const { lat, lng } = e.lnglat;
        // 更新marker与中心
        marker.setPosition([lng, lat]);
        map.setCenter([lng, lat]);
        // 更新状态和表单
        setLatitude(lat);
        setLongitude(lng);
        // 逆地理编码获取地址
        if (geocoder) {
          geocoder.getAddress([lng, lat], (status: string, result: any) => {
            if (status === 'complete' && result.regeocode) {
              const addr = result.regeocode.formattedAddress;
              form.setFieldsValue({
                address: addr,
                lat: lat,
                lng: lng,
              });
            } else {
              form.setFieldsValue({
                lat: lat,
                lng: lng,
              });
              message.error('获取地址失败');
            }
          });
        } else {
          form.setFieldsValue({
            lat: lat,
            lng: lng,
          });
        }
      });

      mapRef.current = { map, marker };
    }
  }, [mapLoaded, longitude, latitude, geocoder]);

  // 地址搜索
  const handleSearch = () => {
    const address = form.getFieldValue('address');
    if (!address) {
      message.warning('请输入地址');
      return;
    }
    if (!placeSearchRef || !placeSearchRef.search) {
      message.error('搜索插件尚未初始化,请稍后再试');
      return;
    }
    placeSearchRef.search(address, (status: string, result: any) => {
      if (status === 'complete' && result.poiList.pois.length) {
        const selectedPoi = result.poiList.pois[0];
        const { lat, lng } = selectedPoi.location;
        setLatitude(lat);
        setLongitude(lng);
        // 使用逆地理编码获取完整地址
        geocoder.getAddress([lng, lat], (status: string, result: any) => {
          if (status === 'complete' && result.regeocode) {
            const addr = result.regeocode.formattedAddress;
            form.setFieldsValue({
              address: addr, // 使用完整地址而不是POI名称
              lat,
              lng,
            });

            if (mapRef.current) {
              mapRef.current.map.setCenter([lng, lat]);
              mapRef.current.marker.setPosition([lng, lat]);
            }
            message.success('定位成功');
          }
        });
      } else {
        message.error('未找到该地址');
      }
    });
  };
  return (
    <div>
      <Form form={form}>
        <div>
          <Form.Item name="address">
            <Input.Search
              placeholder="搜索地址"
              enterButton="搜索"
              style={{ width: 400 }}
              onSearch={handleSearch}
            />
          </Form.Item>
        </div>
        <div style={{ display: 'flex', gap: 16 }}>
          <Form.Item name="lng">
            <Input
              placeholder="经度"
              onChange={(e) => {
                const value = parseFloat(e.target.value);
                if (!isNaN(value)) {
                  setLongitude(value);
                  if (mapRef.current) {
                    mapRef.current.map.setCenter([value, latitude]);
                    mapRef.current.marker.setPosition([value, latitude]);
                  }
                }
              }}
              style={{ width: 180 }}
            />
          </Form.Item>
          <Form.Item name="lat">
            <Input
              placeholder="纬度"
              onChange={(e) => {
                const value = parseFloat(e.target.value);
                if (!isNaN(value)) {
                  setLatitude(value);
                  if (mapRef.current) {
                    mapRef.current.map.setCenter([longitude, value]);
                    mapRef.current.marker.setPosition([longitude, value]);
                  }
                }
              }}
              style={{ width: 180 }}
            />
          </Form.Item>
        </div>
      </Form>
      <div
        ref={mapContainerRef}
        style={{ height: 500, border: '1px solid #ddd', marginBottom: 16 }}
      ></div>
    </div>
  );
};

export default mapSearch;

关键步骤总结:

  1. 加载高德地图 API 和插件:确保地图和插件已正确加载。
  2. 初始化地图:创建地图实例,并为地图添加点击事件处理器。
  3. 处理地址搜索:用户输入地址后,进行搜索并更新地图位置。
  4. 更新经纬度输入框和标记:用户在输入框中修改经纬度时,地图和标记同步更新。

这些步骤协同工作,提供了一个动态的地图交互界面,用户可以通过搜索地址或直接输入经纬度来改变地图上的标记位置。

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值