基于 React 封装的高德地图组件,帮助你轻松的接入地图到 React 项目中
source link: https://segmentfault.com/a/1190000025171025
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
react-amap 这是一个基于 React 封装的高德地图组件,帮助你轻松的接入地图到 React 项目中。除了必须引用的 Map/APILoader 组件外,我们目前提供了最常用的地图组件,能满足大部分简单的业务场景;如果你有更复杂的需求,或者觉得默认提供的组件功能不够,你完全可以自定义一个地图组件,然后根据高德原生 API 做高德允许你做的一切事情。
文档实例预览: Github Web | Gitee Web
特性
- :recycle: 自动加载高德地图 SDK(通过创建 Script 标签的形式加载),包括第三方 SDK。
- :books: 使用 Typescript 编写,集成高德地图 SDK @type 声明文件(包括中文注释)。
- ⚛️ 支持 React Hook 新增特性(需要 React 16.8+)。
- :gift_heart: 不依赖任何第三方组件。
安装
不依赖 uiw
组件库
npm install @uiw/react-amap --save
使用
<!--DemoStart,bgWhite,codePen-->
import { Map, APILoader } from '@uiw/react-amap'; const Demo = () => ( <div style={{ width: '100%', height: '300px' }}> <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Map /> </APILoader> </div> ); ReactDOM.render(<Demo />, _mount_);
<!--End-->
Map 组件
Map 组件是其他组件的基础,Map 组件会给所有的子组件注入两个属性 map
, container
和 AMap
,
:warning: 注意
- 组件
<Map>
必须包裹在<APILoader>
组件内,该组件作用是加载高德地图 SDK。 - 其他地图组件必须作为
<Map>
的子组件使用;
import { Map, APILoader } from '@uiw/react-amap';
基本用法
Map 的父组件必须具有宽度和高度;
<!--DemoStart,bgWhite-->
import React from 'react'; import { Map, APILoader } from '@uiw/react-amap'; const Demo = () => ( <div style={{ width: '100%', height: '300px' }}> <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Map /> </APILoader> </div> ); ReactDOM.render(<Demo />, _mount_);
<!--End-->
参数设置
<!--DemoStart,bgWhite-->
import React, { Fragment } from 'react'; import { Map, APILoader } from '@uiw/react-amap'; function Demo() { const [dragEnable, setDragEnable] = useState(true); const [display, setDisplay] = useState(true); const [zoom, setZoom] = useState(15); const [viewMode, setViewMode] = useState('3D'); return ( <Fragment> <button onClick={() => setDragEnable(!dragEnable)}>{dragEnable ? '禁用' : '启用'}拖拽</button> <button onClick={() => setDisplay(!display)}>{display ? '卸载' : '加载'}地图</button> <button onClick={() => setViewMode(viewMode === '3D' ? '2D' : '3D')}>{viewMode}地图</button> <button onClick={() => setZoom(zoom + 1)}>放大 +1 -> ({zoom})</button> <button onClick={() => setZoom(zoom - 1)}>缩小 -1 -> ({zoom})</button> <div style={{ width: '100%', height: 350 }}> {display && ( <Map dragEnable={dragEnable} zoom={zoom} viewMode={viewMode} pitch={viewMode === '2D' ? 0 : 70} /> )} </div> </Fragment> ); } ReactDOM.render(( <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Demo /> </APILoader> ), _mount_);
<!--End-->
Ref
获取地图实例对象。
<!--DemoStart,bgWhite-->
import React, { useEffect, useRef, Fragment } from 'react'; import { Map, APILoader } from '@uiw/react-amap'; function Demo() { const mapRef = useRef(); useEffect(() => { console.log('mapRef:', mapRef) }, []); return ( <div style={{ width: '100%', height: 330 }}> <Map layers={[new AMap.TileLayer.Satellite()]} ref={(instance) => { if (instance && instance.map) { const bounds = instance.map.getBounds(); console.log('instance', instance); } }} /> <Map layers={[new AMap.TileLayer.Satellite()]} ref={mapRef} /> </div> ); } ReactDOM.render(( <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Demo /> </APILoader> ), _mount_);
<!--End-->
事件触发
<!--DemoStart,bgWhite-->
import React from 'react'; import { Map, APILoader } from '@uiw/react-amap'; const Demo = () => ( <div style={{ width: '100%', height: '300px' }}> <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Map onComplete={(data, de) => { console.log('地图加载完成!', data, de); }} onClick={() => { console.log('点击事件!'); }} /> </APILoader> </div> ); ReactDOM.render(<Demo />, _mount_);
<!--End-->
APILoader
用于加载高德地图 SDK 依赖,加载完成,全局将会有 window.AMap
对象。
import { APILoader } from '@uiw/react-amap';
基本用法
Map 的父组件必须具有宽度和高度;
<!--DemoStart,bgWhite,codePen-->
import React from 'react'; import { Map, APILoader } from '@uiw/react-amap'; const Demo = () => ( <div style={{ width: '100%', height: '300px' }}> <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Map /> </APILoader> </div> ); ReactDOM.render(<Demo />, _mount_);
<!--End-->
多个地图
<!--DemoStart,bgWhite,codePen-->
import React from 'react'; import { Map, APILoader } from '@uiw/react-amap'; const Demo = () => ( <div style={{ width: '100%', height: 300 }}> <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Map style={{ height: 100, marginBottom: 10 }} /> <div style={{ border: '1px solid red' }}> <Map style={{ height: 100 }} /> </div> </APILoader> </div> ); ReactDOM.render(<Demo />, _mount_);
<!--End-->
Marker 点标记组件
点标记是用来标示某个位置点信息的一种地图要素,本章介绍如何在地图图面使用点标记。
import { Marker } from '@uiw/react-amap';
基本用法
<!--DemoStart,bgWhite,noScroll-->
import React, { useState, useRef } from 'react'; import { Map, APILoader, Marker } from '@uiw/react-amap'; const Example = () => { const [show, setShow] = useState(true); return ( <> <button onClick={() => setShow(!show)}> {show ? '隐藏' : '显示'} </button> <div style={{ width: '100%', height: '300px' }}> <Map zoom={4}> <Marker visiable={show} title="北京市" position={new AMap.LngLat(116.405285,39.904989)} /> <Marker visiable={show} title="天津市" position={new AMap.LngLat(117.190182,39.125596)} /> <Marker visiable={show} title="河北省" position={new AMap.LngLat(114.502461,38.045474)} /> <Marker visiable={show} title="山西省" position={new AMap.LngLat(112.549248,37.857014)} /> <Marker visiable={show} title="内蒙古自治区" position={new AMap.LngLat(111.670801,40.818311)} /> <Marker visiable={show} title="辽宁省" position={new AMap.LngLat(123.429096,41.796767)} /> <Marker visiable={show} title="吉林省" position={new AMap.LngLat(125.3245,43.886841)} /> <Marker visiable={show} title="黑龙江省" position={new AMap.LngLat(126.642464,45.756967)} /> <Marker visiable={show} title="上海市" position={new AMap.LngLat(121.472644,31.231706)} /> <Marker visiable={show} title="江苏省" position={new AMap.LngLat(118.767413,32.041544)} /> <Marker visiable={show} title="浙江省" position={new AMap.LngLat(120.153576,30.287459)} /> <Marker visiable={show} title="安徽省" position={new AMap.LngLat(117.283042,31.86119)} /> <Marker visiable={show} title="福建省" position={new AMap.LngLat(119.306239,26.075302)} /> <Marker visiable={show} title="江西省" position={new AMap.LngLat(115.892151,28.676493)} /> <Marker visiable={show} title="山东省" position={new AMap.LngLat(117.000923,36.675807)} /> <Marker visiable={show} title="河南省" position={new AMap.LngLat(113.665412,34.757975)} /> <Marker visiable={show} title="湖北省" position={new AMap.LngLat(114.298572,30.584355)} /> <Marker visiable={show} title="湖南省" position={new AMap.LngLat(112.982279,28.19409)} /> <Marker visiable={show} title="广东省" position={new AMap.LngLat(113.280637,23.125178)} /> <Marker visiable={show} title="广西壮族自治区" position={new AMap.LngLat(108.320004,22.82402)} /> <Marker visiable={show} title="海南省" position={new AMap.LngLat(110.33119,20.031971)} /> <Marker visiable={show} title="重庆市" position={new AMap.LngLat(106.504962,29.533155)} /> <Marker visiable={show} title="四川省" position={new AMap.LngLat(104.065735,30.659462)} /> <Marker visiable={show} title="贵州省" position={new AMap.LngLat(106.713478,26.578343)} /> <Marker visiable={show} title="云南省" position={new AMap.LngLat(102.712251,25.040609)} /> <Marker visiable={show} title="西藏自治区" position={new AMap.LngLat(91.132212,29.660361)} /> <Marker visiable={show} title="陕西省" position={new AMap.LngLat(108.948024,34.263161)} /> <Marker visiable={show} title="甘肃省" position={new AMap.LngLat(103.823557,36.058039)} /> <Marker visiable={show} title="青海省" position={new AMap.LngLat(101.778916,36.623178)} /> <Marker visiable={show} title="宁夏回族自治区" position={new AMap.LngLat(106.278179,38.46637)} /> <Marker visiable={show} title="新疆维吾尔自治区" position={new AMap.LngLat(87.617733,43.792818)} /> <Marker visiable={show} title="台湾省" position={new AMap.LngLat(121.509062,25.044332)} /> <Marker visiable={show} title="香港特別行政區" position={new AMap.LngLat(114.173355,22.320048)} /> <Marker visiable={show} title="澳門特別行政區" position={new AMap.LngLat(113.54909,22.198951)} /> </Map> </div> </> ); } ReactDOM.render(( <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Example /> </APILoader> ), _mount_);
<!--End-->
点标注的文本标签
<!--DemoStart,bgWhite,noScroll-->
import React, { useState, useRef } from 'react'; import { Map, APILoader, Marker } from '@uiw/react-amap'; const Example = () => { const [show, setShow] = useState(true); return ( <> <button onClick={() => setShow(!show)}> {show ? '隐藏' : '显示'} </button> <div style={{ width: '100%', height: '300px' }}> <Map zoom={12} center={[116.397428, 39.90923]}> <Marker visiable={show} title="北京市" offset={new AMap.Pixel(-13, -30)} label={{ // 设置文本标注偏移量 offset: new AMap.Pixel(20, 20), // 设置文本标注内容 content: "<div class='info'>我是 marker 的 label 标签</div>", // 设置文本标注方位 direction: 'right' }} position={new AMap.LngLat(116.405285,39.904989)} /> </Map> </div> </> ); } ReactDOM.render(( <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Example /> </APILoader> ), _mount_);
<!--End-->
自适应显示多个点标记
<!--DemoStart,bgWhite,noScroll-->
import React, { useState, useRef } from 'react'; import { Map, APILoader, Marker } from '@uiw/react-amap'; const Example = () => { const [show, setShow] = useState(true); const [map, setMap] = useState(); return ( <> <button onClick={() => setShow(!show)}> {show ? '隐藏' : '显示'} </button> <button onClick={() => { if (map) { map.setFitView(null, false, [150, 60, 100, 60]); } }}> 地图自适应显示到合适的范围 </button> <div style={{ width: '100%', height: '300px' }}> <Map zoom={13} center={[116.397428, 39.90923]} ref={(instance) => { if (instance && instance.map && !map) { setMap(instance.map); } }} > <Marker visiable={show} icon={new AMap.Icon({ imageSize: new AMap.Size(25, 34), image: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-1.png' })} offset={new AMap.Pixel(-13, -30)} position={new AMap.LngLat(116.205467, 39.907761)} /> <Marker visiable={show} icon={new AMap.Icon({ imageSize: new AMap.Size(25, 34), image: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-2.png' })} offset={new AMap.Pixel(-13, -30)} position={[116.368904, 39.913423]} /> <Marker visiable={show} icon={new AMap.Icon({ imageSize: new AMap.Size(25, 34), image: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-3.png' })} offset={new AMap.Pixel(-13, -30)} position={[116.305467, 39.807761]} /> </Map> </div> </> ); } ReactDOM.render(( <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Example /> </APILoader> ), _mount_);
<!--End-->
Polygon 多边形
构造多边形对象,通过 PolygonOptions 指定多边形样式
import { Polygon } from '@uiw/react-amap';
基本用法
<!--DemoStart,bgWhite,noScroll-->
import React, { useState, useRef } from 'react'; import { Map, APILoader, Polygon } from '@uiw/react-amap'; const Example = () => { const [show, setShow] = useState(true); // 多边形轮廓线的节点坐标数组 // const path = [ // new AMap.LngLat(116.368904,39.913423), // new AMap.LngLat(116.382122,39.901176), // new AMap.LngLat(116.387271,39.912501), // new AMap.LngLat(116.398258,39.904600) // ]; const path = [ [116.403322, 39.920255], [116.410703, 39.897555], [116.402292, 39.892353], [116.389846, 39.891365] ]; return ( <> <button onClick={() => setShow(!show)}> {show ? '隐藏' : '显示'} </button> <div style={{ width: '100%', height: '500px' }}> <Map zoom={14} center={[116.400274, 39.905812]}> {show && ( <Polygon // visiable={show} path={path} strokeColor="#FF33FF" strokeWeight={6} strokeOpacity={0.2} fillOpacity={0.4} fillColor="#1791fc" zIndex={50} /> )} </Map> </div> </> ); } ReactDOM.render(( <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Example /> </APILoader> ), _mount_);
<!--End-->
Polyline 折线组件
构造折线对象,支持 lineString
和 MultiLineString
。
import { Polyline } from '@uiw/react-amap';
基本用法
<!--DemoStart,bgWhite,noScroll-->
import React, { useState, useRef } from 'react'; import { Map, APILoader, Polyline, ToolBarControl } from '@uiw/react-amap'; const Example = () => { const [show, setShow] = useState(true); return ( <> <button onClick={() => setShow(!show)}> {show ? '关闭' : '开启'} </button> <div style={{ width: '100%', height: '300px' }}> <Map zoom={3}> <Polyline visiable={show} onHide={(obj) => { console.log('obj:', obj); }} onShow={(obj) => { console.log('obj:', obj); }} onClick={(obj) => { console.log('obj:', obj); }} strokeColor="black" strokeOpacity={1} path={[ [116.405289, 39.904987], [113.964458, 40.54664], [111.47836, 41.135964], [108.949297, 41.670904], [106.380111, 42.149509], [103.774185, 42.56996], [101.135432, 42.930601], [98.46826, 43.229964], [95.777529, 43.466798], [93.068486, 43.64009], [90.34669, 43.749086], [87.61792, 43.793308] ]} /> <Polyline visiable={show} strokeOpacity={1} path={[ [121.099109,31.222311], [118.528308,31.989555], [117.319812,31.803006], [114.353503,30.67583], [115.891589,28.979429], [112.947253,28.188361], ]} /> </Map> </div> </> ); } ReactDOM.render(( <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Example /> </APILoader> ), _mount_);
<!--End-->
受控组件
<!--DemoStart,bgWhite,noScroll-->
import React, { useState, useRef } from 'react'; import { Map, APILoader, Polyline, ToolBarControl } from '@uiw/react-amap'; const path1 = [ [121.099109,31.222311], [118.528308,31.989555], [117.319812,31.803006], [114.353503,30.67583], [115.891589,28.979429], [112.947253,28.188361], ]; const path2 = [ [116.405289, 39.904987], [113.964458, 40.54664], [111.47836, 41.135964], [108.949297, 41.670904], [106.380111, 42.149509], [103.774185, 42.56996], [101.135432, 42.930601], [98.46826, 43.229964], [95.777529, 43.466798], [93.068486, 43.64009], [90.34669, 43.749086], [87.61792, 43.793308], ]; const Example = () => { const [show, setShow] = useState(true); const [paths, setPaths] = useState(path1); return ( <> <button onClick={() => setShow(!show)}> {show ? '关闭' : '开启'} </button> {show && ( <button onClick={() => setPaths(paths.length === 6 ? path2 : path1)}> 切换路线 </button> )} <div style={{ width: '100%', height: '300px' }}> <Map zoom={3}> <Polyline visiable={show} strokeOpacity={1} path={paths} /> </Map> </div> </> ); } ReactDOM.render(( <APILoader akay="a7a90e05a37d3f6bf76d4a9032fc9129"> <Example /> </APILoader> ), _mount_);
<!--End-->
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK