首先你要去百度地图开放平台注册并获取一个appkey(AK码)百度地图开放平台
找到控制台/应用管理/我的应用
创建ak秘钥成功后copy一下
最后在我们脚手架中public目录/index.html文件中引入链接,并注入AK码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>React App</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=此处粘贴你刚刚copy的AK码"></script>
</body>
</html>
这样准备工作就完成了,接下来的活就是在组件中完成了
import React, { Component } from 'react'
import { NavBar, Toast, Popup } from 'antd-mobile' //从组件库中引入
import axios from 'axios'
class Index extends Component {
state = { //弹框 和弹框内数据
visible: false,
maskData: []
}
mapContainer = React.createRef() //创建节点容器
map = null //全局挂载变量
cirStyle = {// 圆形覆盖物的样式
color: 'white',
borderRadius: '50%',
borderColor: 'white',
backgroundColor: '#22BA77',
fontSize: '16px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '85px',
height: '85px',
fontFamily: '微软雅黑',
zIndex: 9999
}
rectStyle = { // 矩形覆盖物的样式
color: white;
borderColor: white;
background: #22BA77;
fontSize: 14px;
display: flex;
justifyContent: space-around;
alignItems: center;
width: 150px;
height: 40px;
fontFamily: '微软雅黑';
zIndex: 9999;
}
isCurCity() {//判断本地存储是否有城市
const city = JSON.parse(localStorage.getItem('hyzf_city') as any) || ''
if (city) { //如果有的话直接异步返回城市
return Promise.resolve(city)
} else { //如果本地没有城市
return new Promise((resolve) => { //需要借助百度地图提供的API实现本地定位
const myCurCity = new window['BMap'].LocalCity() //定位
myCurCity.get(async (result) => {
const res = await axios.get('https://api-haoke-web.itheima.net/area/info', {
params: { //调接口传参 (这是线上接口)
name: result.name
}
})
const { label, value } = res.data.body //返回城市名,及城市ID
localStorage.setItem('hyzf_city', JSON.stringify({ label, value })) //存本地
resolve({ label, value }) //成功抛出
})
})
}
}
async initMap() {//初始化地图
const { label, value } = await this.isCurCity() //调用方法返回城市名和城市ID
this.map = new window['BMap'].Map(this.mapContainer.current) //创建地图实例,作用于mapContainer容器
const myGeo = new window['BMap'].Geocoder() //创建地址解析器实例
myGeo.getPoint(label, async (point) => { //第一个参数详细地址、第二个参数回调、第三个参数城市
this.map.centerAndZoom(point, 12) //创建中心点、视图展示层级
this.map.addControl(new window['BMap'].NavigationControl()); //添加导航空间
this.map.addControl(new window['BMap'].ScaleControl()); //添加比例标尺空间
this.renderOverlays(value) //调用渲染覆盖物方法、传入城市ID
}, label)
}
async renderOverlays(id) {//渲染覆盖物
Toast.show({ //借用组件库实现加载loading功能 (蒙层)
icon: 'loading',
content: '加载中...',
})
const res = await axios.get('https://api-haoke-web.itheima.net/area/map', { params: { id } })
//调用线上接口,传入参数城市ID
Toast.clear()//接口响应完毕、关闭loading蒙层
const { type, nextLevel } = this.getTypeAndZoom() //调用方法获取类型及地图展示层级 (1-19)
res.data.body.forEach(item => { //将拿到的数据遍历 循环调用创建覆盖物的方法,传入类型(圆形/矩形)、地图展示层级、数据的每一项
this.createOverlays(type, nextLevel, item)
})
}
getTypeAndZoom() {//获取类型及地图展示层级
const curZoom = this.map.getZoom() //获取当前地图缩放层级
let type, nextLevel;//声明两变量 类型,层级
if (curZoom >= 10 && curZoom <= 12) { //根据获取的层级更改应用到实际视图的类型/层级
type = 'circle' //圆形
nextLevel = 13
} else if (curZoom >= 12 && curZoom < 14) {
type = 'circle'
nextLevel = 16
} else {
type = 'rect' //矩形
nextLevel = 19
}
return { type, nextLevel }//抛出
}
createOverlays(type, nextLevel, item) {//创建覆盖物 (类型,层级,数据)
const { label, value, coord: { latitude, longitude }, count } = item //解构传递过来的每一项数据
var point = new window['BMap'].Point(longitude, latitude); //将经纬度转换为地理位置
if (type === 'rect') { //如果类型是矩形的话就调用创建矩形覆盖物的方法
this.createRect(point, label, count, value)
} else { //否则调用创建圆形覆盖物的方法
this.createCircle(point, label, count, value, nextLevel)
}
}
createRect(point, areaName, count, id) {//创建矩形覆盖物方法 (最底层的覆盖物)
const that = this //标记全局this
const opts = { //创建含有位置/偏移中心点位置的对象
position: point,
offset: new window['BMap'].Size(-50, -28)
}
const label = new window['BMap'].Label('', opts) //在定位到的地图位置上添加盒子覆盖物
label.setContent(`
<div class='rect-container'>
<p class='area'>${areaName}</p>
<p>${count} 套</p>
</div>
`)
//更改内容为覆盖物节点 添加动态内容
label.setStyle(this.rectStyle)
//更改覆盖物样式
label.addEventListener('click', (e) => { //给渲染出来的每一个覆盖物绑定点击事件
const { clientX, clientY } = e.changedTouches[0]; //获取节点距离视口左侧距离、顶部距离
const x = (window.innerWidth) / 2 - clientX; //定义坐标变量
const y = (window.innerHeight) / 2 - clientY;
that.map.panBy(x, y); //位移
that.getHouseDetail(id) //获取最底层的房源数据方法
})
this.map.addOverlay(label) //最后在地图中添加覆盖物 传入label
}
createCircle(point, areaName, count, id, level) {//创建圆形覆盖物方法(非最底层覆盖物)
const that = this // 标记全局this
const opts = { //创建含有位置/偏移中心点位置的对象
position: point,
offset: new window['BMap'].Size(-35, -35)
}
const label = new window['BMap'].Label('', opts)//在定位到的地图位置上添加盒子覆盖物
label.setContent(`
<div>
<p>${areaName}</p>
<p>${count} 套</p>
</div>
`)
//更改内容为覆盖物节点 添加动态内容
label.setStyle(this.cirStyle)
//更改覆盖物样式
label.addEventListener('click', () => {//给渲染出来的每一个覆盖物绑定点击事件
that.renderOverlays(id) //点击圆形覆盖物时调用渲染覆盖物方法传入城市ID
that.map.centerAndZoom(point, level) //设置地图中心及缩放层级
setTimeout(() => { //异步清除当前覆盖物
that.map.clearOverlays()
}, 0)
})
this.map.addOverlay(label) //最后在地图中添加覆盖物 传入label
}
async getHouseDetail(id) { //获取房源数据方法 (城市ID)
let res = await axios.get('https://api-haoke-web.itheima.net/houses', { params: { cityId: id } })
//传入城市ID调用线上接口
if (res.data.status === 200) { //修改弹框内数据后,及时打开弹框,看到房源渲染效果
this.setState({ maskData: res.data.body.list }, () => {
this.setState({ visible: true })
})
}
}
componentDidMount() { //在组件挂载结束钩子里调用初始化地图方法
this.initMap()
}
render() {
return (
<div className='map-container'>
<NavBar className='header-bar' onBack={() => this.props.history.goBack()}>地图找房</NavBar>
<div ref={this.mapContainer} className='map-container'>
</div>
<Popup
visible={this.state.visible}
onMaskClick={() => {
this.setState({ visible: false })
}}
bodyStyle={{ height: '50vh', overflowY: 'scroll' }}
>
<div className="mask-container">
<h2 className="mask-title">
房屋列表
<span>更多房源</span>
</h2>
<div className="mask-content">
{this.state.maskData.map((item) => {
return (<div className='mask-item' key={item.houseCode}>
<img src={require('../../assest/images/house.jpg')} />
<div className='right-item'>
<h3>
{item.title}
</h3>
<p>{item.desc}</p>
<div>
{item.tags.map((item, index) => {
return (<span className='mask-tags' key={index}>{item}</span>)
})}
</div>
<h4>{item.price}<b>元/月</b></h4>
</div>
</div>)
})}
</div>
</div>
</Popup>
</div>
)
}
}
export default Index
这样基本上就可以做一个不错的地图小demo,主要还是要会用百度地图JSAPI,看文档写代码
效果:
1、首先看到上海全部区的房源信息
2、在看到区中全部城镇的房源信息
3、最后最底层就是城镇中全部的小区房源
4、点击矩形覆盖物实现弹框渲染房源
本文就带来了百度地图在项目中开发的冰山一角,希望能对您能有所帮助