react地图组件
最近项目中有此需求,react地图组件的开发:
1 输入地址可查询出对应地图位置并标记点
2 能返回经纬度,并提交服务端保存
3 在地图上点击某一点,也能返回对应经纬度和地址信息
4 国内,国外均可使用
经过调研决定,采用谷歌地图和高德地图来封装组件,当渲染地图组件时,先试图请求谷歌map的api,若能访问则使用谷歌地图,若不能访问,则调用国内高德地图。
框架环境:react+dva+antd+umiJs;其中需要用到prop-types,axios,scriptjs,对应npm安装即可。
具体组件如下:
import React from 'react'
import PropTypes from 'prop-types'
import { Spin } from 'antd';
import axios from 'axios';
import $script from 'scriptjs'
import styles from './AMap.less'
const googleMapSdk='https://maps.googleapis.com/maps/api/js?key=your key';
const gaodeMapSdk='https://webapi.amap.com/maps?v=1.4.2&key=your key';
let map = null;
let marker = null;
let geocoder = null;
let zoomLevel=15;
class AMapModule extends React.Component {
constructor(props){
super(props);
this.state = {
status:0
};
}
componentWillMount(){
if(!window.AMap&&!(window.google&&window.google.maps)){
axios.get(googleMapSdk,{timeout: 1000}).then(res => {
$script( [googleMapSdk],function(a,b){})
}).catch(function (error) {
$script( [gaodeMapSdk],function(a,b){})
});
}
}
componentDidMount(){
let _this=this;
function listenerStorage(){
if(window.AMap||(window.google && window.google.maps)){
if(window.AMap) {
const {lat, lng, getMapAddress} = _this.props;
const latlngxy=[(!lng||lng=='undefined'||lng=='0')?116.397428:lng,(!lat||lat=='undefined'||lat=='0')?39.90923:lat];//默认北京天安门
map = new window.AMap.Map('allmap', {
resizeEnable: true,
center: latlngxy,
zoom: zoomLevel
});
//高德设置语言 ['en', 'zh_en', 'zh_cn']
let mapLang;
if(window.localStorage.getItem('i18n') == 'en_US'){
mapLang = 'en';
}else{
mapLang = 'zh_cn';
}
map.setLang(mapLang);
// 在新中心点添加 marker
marker = new window.AMap.Marker({
map: map,
position: latlngxy
});
map.on('click',function(e){
marker.setPosition(e.lnglat);
window.AMap.service('AMap.Geocoder',function(){//回调函数
//实例化Geocoder
geocoder = new window.AMap.Geocoder({});
geocoder.getAddress(e.lnglat,function(status,result){
if(status === 'complete' && result.info === 'OK'){
const address=result.regeocode.formattedAddress
getMapAddress&&getMapAddress(address);
}
})
})
})
}
if(window.google && window.google.maps){
const {lat, lng, getMapAddress} = _this.props;
const latlngxy=[(!lng||lng=='undefined'||lng=='0')?116.397428:lng,(!lat||lat=='undefined'||lat=='0')?39.90923:lat];//默认北京天安门
var uluru = {lat: parseFloat(latlngxy[1]), lng: parseFloat(latlngxy[0])}; // google need number
initMap()
function initMap() {
map = new window.google.maps.Map(document.getElementById('allmap'), {
resizeEnable: true,
center: uluru,
zoom: zoomLevel
});
// 在新中心点添加 marker
marker = new window.google.maps.Marker({
map: map,
position: uluru
});
}
map.addListener('click',function(e){
let latlng=e.latLng;
marker.setPosition(latlng);
geocoder = new window.google.maps.Geocoder()
geocoder.geocode({'location': latlng}, function(results, status) {
if (status === 'OK') {
const address=results[0].formatted_address
getMapAddress&&getMapAddress(address.substring(0,address.indexOf(' ')));
} else {
console.log('Geocoder failed due to: ' + status);
}
});
})
}
_this.setState({
status:1
})
}else{
setTimeout(function(){
listenerStorage()
},800)
}
}
listenerStorage();
}
componentWillReceiveProps=(nextProps)=>{
const {getMapPoint}=this.props;
if(window.AMap && nextProps.address&&nextProps.address!=this.props.address) {
window.AMap.service('AMap.Geocoder',function(){//回调函数
//实例化Geocoder
geocoder = new window.AMap.Geocoder({});
geocoder.getLocation(nextProps.address, function (status, result) {
if (status === 'complete' && result.info === 'OK') {
let latlng = result.geocodes[0].location;
getMapPoint&&getMapPoint(latlng);
// 设置缩放级别和中心点
let latlngxy = [latlng['lng'],latlng['lat']];
const currentZoom=map.getZoom();
map.setZoomAndCenter(currentZoom!=zoomLevel?currentZoom:zoomLevel, latlngxy);
// 在新中心点添加 marker
marker.setPosition(latlng);
} else {
console.log('search "' + nextProps.address + '" no data')
}
});
});
}
if(window.google && window.google.maps && nextProps.address&&nextProps.address!=this.props.address){
geocoder = new window.google.maps.Geocoder()
geocoder.geocode({'address': nextProps.address}, function(results, status) {
if (status === 'OK') {
let latlng = results[0].geometry.location;
getMapPoint&&getMapPoint({lat:latlng.lat(),lng:latlng.lng()});
map.setCenter(latlng);
// 在新中心点添加 marker
marker.setPosition(latlng);
} else {
console.log('Geocode was not successful for the following reason: ' + status);
}
});
}
}
render(){
const { height } = this.props;
return(
<div className={styles.container} style={{height:height?height:300}}>
<Spin spinning={this.state.status==0?true:false} tip="Loading...">
<div id="allmap" className={styles.mapContainer} style={{height:height?height:300}} />
</Spin>
</div>
)
}
}
AMapModule.propTypes = {
lng: PropTypes.string,
lat: PropTypes.string,
className: PropTypes.string,
}
export default AMapModule
调用如下:
<div style={{width:'500px'}}>
<Form>
<FormItem
label={
<span>
地址
</span>
}>
{getFieldDecorator('position', {
initialValue: '北京'
})(
<Input placeholder={'请输入地址'} />
)}
</FormItem>
<FormItem
label={
<span>
经度
</span>
}>
{getFieldDecorator('longitude', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem label={
<span>
维度
</span>
}>
{getFieldDecorator('latitude', {
initialValue: ''
})(
<Input/>
)}
</FormItem>
<AMap
lng={''}
lat={''}
address={getFieldValue('position')}
getMapPoint={(point)=>{
setFieldsValue({
latitude: point.lat,
longitude: point.lng
});
}}
getMapAddress={(address)=>{
setFieldsValue({
position: address
});
}}
/>
</Form>
</div>