如何在React项目中使用高德地图插件并封装弹窗组件呢?

2,668 阅读6分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战

前言

在前端开发中,要求地图插件运用到项目中的需求还是很多的,主要由于地图插件能给我们提供很多便利,比如IP位置,规划路线,天气查询等。所以前端开发还是要具备在项目中掌握使用地图插件并实现产品需求的能力,毕竟现在的地图相关的业务需求很普遍,已不是前端开发的拔高技能了,所以这次跟着我了解如何在React项目中使用高德地图插件的吧。

需求背景

需求就是:在编辑的时候给项目在高德地图上选取地点,然后保存之后点击项目地点打开高德地图并定位到相应的地点。

微信截图_20220124194450.png

微信截图_20220124194850.png

需求很简单,就是要会使用并知道如何实现。请看下面方法,你就又会一技傍身。

开发

首先,既然选择高德地图,那肯定得去高德地图得官网申请地图key,在高德那里留个底,不然别人怎么知道你有没有拿别人东西去乱整呢,所以这一步是不能少的。

注册高德地图key

  1. 打开官网lbs.amap.com/
  2. 注册账号成为高德开放平台开发者,按着提示一步步进行信息填写
  3. 注册好之后登录,然后点击右上角头像进入应用管理
  4. 进入我的应用,创建新应用,应用类型根据自己业务选择

微信截图_20220124200850.png 5. 创建成功之后,点击添加按照下图填写信息

微信截图_20220124201349.png

6.提交之后就会获得应用得key,注册高德地图Key也就完成了。

微信截图_20220124201503.png

引用react-amap插件

react-amap 是一个基于 React 封装的高德地图组件;帮助你轻松的接入地图到 React 项目中。除了必须引用
的 Map 组件外,我们目前提供了最常用的 10 个地图组件,能满足大部分简单的业务场景;如果你有更复杂的需
求,或者觉得默认提供的组件功能不够,你完全可以自定义一个地图组件,然后根据高德原生 API 做高德允许你
做的一切事情。

安装:

npm install react-amap 或 yarn add react-amap

引用组件并使用:

<div id="app"></div>
#app { 
    width: 600px; 
    height: 400px; 
}
import React from 'react'; 
import ReactDOM from 'react-dom'; 
import { Map } from 'react-amap';

ReactDOM.render( 
    <Map amapkey={YOUR_AMAP_KEY} version={VERSION} />,
    document.querySelector('#app') 
)

封装地图组件弹窗

高德地图web服务API接口地址lbs.amap.com/api/webserv…, 我们可以从这个网址获得我们想要功能的接口地址,像我们需求中的下拉框数据来源就是通过输入提示API服务查询得到的。

微信截图_20220124203017.png

通过输入提示API服务查询到的数据结构为:

微信截图_20220124203852.png

万事俱备,开始撸代码:

import React, {useEffect, useRef, useState} from 'react';
import {Form, Input, Select, Modal} from 'antd';
import { Map, Marker } from 'react-amap';
import {request} from "../../../util/request";
import {AMap} from "../../../config/constant"

const {Option} = Select;

interface MapDialogProps {
    formData: any; // 外部传入弹窗的数据源
    visible: boolean; // Modal组件显示或隐藏标识
    onCancel: (bool: boolean) => void; // MapModal组件点击右上角按钮关闭弹窗事件
    onSubmit: (bool: boolean) => void; // MapModal组件传出选中的值
}


/**
 * 地图选择弹窗
 * @props
 * @constructor
 */
const MapDialog = (props: MapDialogProps) => {
    const {
        formData, visible = false, onCancel = (bool: boolean) => {}, onSubmit = (bool: boolean) => {}
    } = props;
    // 地图查询得到的地址列表数据
    const [addressList, setAddressList] = useState<any[]>([]);
    // 地图插件数组
    const [mapPlugins, setMapPlugins] = useState<any[]>(['ToolBar']);
    // 地图标记
    const [mapMarker, setMapMarker] = useState<any>({longitude: 104.090089, latitude: 30.620206});
    // 父组件传入的form表单对象
    const [form] = Form.useForm();
    const { getFieldsValue, setFieldsValue, resetFields } = form;
    // 地图缩放比例
    const [zoom, setZoom] = useState<number>(15);
    let timer = useRef<any>(null);

    useEffect(() => {
        queryAddressList();
    }, []);


    useEffect(() => {
        const { longitude, latitude, location } = formData;
        setFieldsValue(formData);
        if (location) {
            queryAddressList(location);
            setMapMarker({longitude, latitude});
            setZoom(15);
        }
    }, [formData])

    /**
     * 查询地址信息列表
     */
    const queryAddressList = (keywords: string = '') => {
        let params: any = {
            key: AMap.key,
            keywords,
            datatype: 'all'
        }
        request(
            '/v3/assistant/inputtips',
            params,
            {
                method: 'get',
                baseURL: AMap.apiUrl,
                withToken: false
            }
        ).then(res => {
            if (res.status == '1') {
                setAddressList(res.tips);
            }
        });
    }


    /**
     *关闭编辑信息弹窗
     */
    const closeMapModalDialog = () => {
        onCancel(false);
    }

    /**
     *关闭问题明细弹窗之后的函数
     */
    const afterCloseMapModalDialog = () => {
        resetFields();
    }


    /**
     * 选择某一个项目
     * @param item
     */
    const selectItem = (value: string, option: any) => {
        const { label } = option;
        const target = addressList.filter((v: any) => v.location === value)[0];
        if (!target) {
            return;
        }
        const {adcode} = target;
        setMapMarker({longitude: value.split(',')[0], latitude: value.split(',')[1]});
        setZoom(15);
        setFieldsValue({name: label, cityCode: adcode});
    }


    /**
     * 点击确定按钮传出选中的位置信息
     */
    const getMapValue = () => {
        onSubmit(getFieldsValue());
        onCancel(false);
    }


    /**
     * 输入搜索事件
     */
    const onSearchHandel = (val: string) => {
        if (timer.current) {
            clearTimeout(timer.current);
        }
        timer.current = setTimeout(() => {
            queryAddressList(val);
        }, 600);
    }


    return (
        <Modal
            title="地图信息"
            visible={visible}
            className="bit-map-modal"
            maskClosable={false}
            onCancel={closeMapModalDialog}
            onOk={getMapValue}
            afterClose={afterCloseMapModalDialog}
        >
            <div className="w" style={{height: '400px'}}>
                <Form name="mapDialogForm" form={form}>
                    <Form.Item name="location" noStyle>
                        <Select
                            showSearch
                            filterOption={false}
                            className="w mb10"
                            placeholder="请选择"
                            onSearch={onSearchHandel}
                            onSelect={selectItem}>
                            {
                                addressList.map((item: any) =>
                                    <Option
                                        value={item.location}
                                        key={item.id}
                                        label={`${item.name}(${item.district})`}
                                    >{item.name}({item.district})</Option>
                                )
                            }
                        </Select>
                    </Form.Item>
                    <Form.Item name="name" hidden>
                        <Input type="hidden"/>
                    </Form.Item>
                    <Form.Item name="cityCode" hidden>
                        <Input type="hidden"/>
                    </Form.Item>
                </Form>
                <Map
                    amapkey={AMap.key}
                    plugins={mapPlugins}
                    center={mapMarker}
                    zoom={zoom}
                >
                    <Marker position={mapMarker} />
                </Map>
            </div>
        </Modal>
    )
}


export default MapDialog;

上述代码可以看到,我们通过关键字搜索得到数据,然后去选择某一个选项时通过比对拿到经纬度设置标记点位置,最后通过onSubmit方法将选取的地点信息传递给父组件处理逻辑。

而我们注册的高德地图Key则是配置到了一个常量文件中,这样做方便我们全局做统一更改;并且还做了一次ngix代理,毕竟我们是内网环境,需要配置一下其他城市的分公司访问时才不会报错。

微信截图_20220124204345.png

使用方法:

1)导入组件:
import MapDialog from "./MapDialog";

2)使用组件:
<MapDialog
    formData={dataSourceObj}
    visible={isMapModalVisible}
    onCancel={closeMapModalDialog}
    onSubmit={(values: any) => {
        const {name, location, cityCode} = values;
        setFieldsValue({
            longitude: location.split(',')[0],
            latitude: location.split(',')[1],
            location: name,
            cityCode
        });
    }}
/>

3)点击项目地点新开页面打开高德地图显示地点并标记
/**
 * 跳转到高德地图官方搜索页面
 */
const gotoAMapPage = () => {
    const {cityCode, location, longitude, latitude} = generalInfo;
    let geoobj: string = `${longitude}|${latitude}`;
    window.open(
        `https://www.amap.com/search?query=${location}&city=${cityCode}&geoobj=${geoobj}&zoom=15`,
        '_blank'
    );
}

到此,高德地图插件在React项目中的使用和封装就聊得差不多了,至于高德地图的其它功能需要小伙伴们根据自己的需求去引用相关的组件和API,这里我们就只介绍了输入提示的功能,所以道路且长,且行且珍惜。最后希望小伙伴们2022虎虎生威,保住各自的头发^_^

往期精彩文章

后语

伙伴们,如果觉得本文对你有些许帮助,点个👍或者➕个关注在走呗^_^ 。另外如果本文章有问题或有不理解的部分,欢迎大家在评论区评论指出,我们一起讨论共勉。