在使用的react版本如下:
已写的代码如下:
import React from 'react'
// 导入封装好的NavHeader组件
import NavHeader from '../../components/NavHeader'
// 导入 HouseItem 组件
import HouseItem from '../../components/HouseItem'
import { API } from '../../utils/api'
import { Link } from 'react-router-dom'
import { Toast } from 'antd-mobile'
import { BASE_URL } from '../../utils/url'
import styles from './style.module.css'
// 解决脚手架中全局访问变量的问题
const BMapGL = window.BMapGL
export default class Mymap extends React.Component {
state = {
// 小区下的房源列表
housesList: [],
// 表示是否展示房源列表
isShowList: false
}
// 初始化地图实例
componentDidMount() {
this.initMap()
}
initMap() {
// 获取当前定位城市
const {label, value} = JSON.parse(localStorage.getItem('hkzf_city'))
const map = new BMapGL.Map("container")
// 作用:能够在其他方法中通过this来获取地图对象
this.map = map
// 设置中心点坐标
// const point = new BMapGL.Point(116.404, 39.915)
//创建地址解析器实例
const myGeo = new BMapGL.Geocoder();
// 将地址解析结果显示在地图上,并调整地图视野
myGeo.getPoint(
label,
async point => {
if (point) {
// 初始化地图
map.centerAndZoom(point, 11);
// 添加控件
const scaleCtrl = new BMapGL.ScaleControl(); // 添加比例尺控件
map.addControl(scaleCtrl);
const zoomCtrl = new BMapGL.ZoomControl(); // 添加缩放控件
map.addControl(zoomCtrl);
const cityCtrl = new BMapGL.CityListControl(); // 添加城市列表控件
map.addControl(cityCtrl);
// 调用renderOverlays方法
this.renderOverlays(value)
}
},
label
)
// 给地图绑定移动事件
map.addEventListener('movestart', () => {
if (this.state.isShowList) {
this.setState({
isShowList: false
})
}
})
}
// 渲染覆盖物入口
async renderOverlays(id) {
try {
// 开启loading
Toast.show({
icon: 'loading',
content: '加载中…',
})
const res = await API.get(`/area/map?id=${id}`)
// 关闭 loading
Toast.clear()
const data = res.data.body
// 调用 getTypeAndZoom 方法获取级别和类型
const { nextZoom, type } = this.getTypeAndZoom()
data.forEach(item => {
// 创建覆盖物
this.createOverlays(item, nextZoom, type)
})
} catch (e) {
// 关闭 loading
Toast.clear()
}
}
// 计算要绘制的覆盖物类型和下一个缩放级别
// 区 -> 11 ,范围:>=10 <12
// 镇 -> 13 ,范围:>=12 <14
// 小区 -> 15 ,范围:>=14 <16
getTypeAndZoom() {
// 调用地图的 getZoom() 方法,来获取当前缩放级别
const zoom = this.map.getZoom()
let nextZoom, type
// console.log('当前地图缩放级别:', zoom)
if (zoom >= 10 && zoom < 12) {
// 区
// 下一个缩放级别
nextZoom = 13
// circle 表示绘制圆形覆盖物(区、镇)
type = 'circle'
} else if (zoom >= 12 && zoom < 14) {
// 镇
nextZoom = 15
type = 'circle'
} else if (zoom >= 14 && zoom < 16) {
// 小区
type = 'rect'
}
return {
nextZoom,
type
}
}
// 创建覆盖物
createOverlays(data, zoom, type) {
const {
coord: { longitude, latitude },
label: areaName,
count,
value
} = data
// 创建坐标对象
const areaPoint = new BMapGL.Point(longitude, latitude)
if (type === 'circle') {
// 区或镇
this.createCircle(areaPoint, areaName, count, value, zoom)
} else {
// 小区
this.createRect(areaPoint, areaName, count, value)
}
}
// 创建区、镇覆盖物
createCircle(point, name, count, id, zoom) {
// 创建覆盖物
const label = new BMapGL.Label('', {
position: point,
offset: new BMapGL.Size(-35, -35)
})
// 给 label 对象添加一个唯一标识
label.id = id
// 设置房源覆盖物内容
label.setContent(`
<div class="${styles.bubble}">
<p class="${styles.name}">${name}</p>
<p class="${styles.name}">${count}套</p>
</div>
`)
// 添加单击事件
label.addEventListener('click', () => {
// 调用 renderOverlays 方法,获取该区域下的房源数据
this.renderOverlays(id)
// 放大地图,以当前点击的覆盖物为中心放大地图
this.map.centerAndZoom(point, zoom)
// 解决清除覆盖物时,百度地图API的JS文件自身报错的问题
setTimeout(() => {
// 清除当前覆盖物信息
this.map.clearOverlays()
}, 0)
})
// 添加覆盖物到地图中
this.map.addOverlay(label)
}
// 创建小区覆盖物
createRect(point, name, count, id) {
// 创建覆盖物
const label = new BMapGL.Label('', {
position: point,
offset: new BMapGL.Size(-50, -28)
})
// 给 label 对象添加一个唯一标识
label.id = id
// 设置房源覆盖物内容
label.setContent(`
<div class="${styles.rect}">
<span class="${styles.housename}">${name}</span>
<span class="${styles.housenum}">${count}套</span>
<i class="${styles.arrow}"></i>
</div>
`)
// 添加单击事件
label.addEventListener('click', e => {
// 获取并渲染房源数据
this.getHousesList(id)
// 获取当前被点击项
const target = e.changedTouches[0]
this.map.panBy(
window.innerWidth / 2 - target.clientX,
(window.innerHeight - 330) / 2 - target.clientY
)
})
// 添加覆盖物到地图中
this.map.addOverlay(label)
}
// 获取小区房源数据
async getHousesList(id) {
try {
// 开启loading
Toast.show({
icon: 'loading',
content: '加载中…',
})
const res = await API.get(`/houses?cityId=${id}`)
// 关闭 loading
Toast.clear()
this.setState({
housesList: res.data.body.list,
// 展示房源列表
isShowList: true
})
} catch (e) {
// 关闭 loading
Toast.clear()
}
}
// 封装渲染房屋列表的方法
renderHousesList() {
return this.state.housesList.map(item => (
<HouseItem
onClick={() => this.props.history.push(`/detail/${item.houseCode}`)}
key={item.houseCode}
src={BASE_URL + item.houseImg}
title={item.title}
desc={item.desc}
tags={item.tags}
price={item.price}
/>
))
}
render() {
return <div className={styles.map}>
{/* 顶部导航栏组件 */}
<NavHeader>
地图找房
</NavHeader>
{/* 地图容器元素 */}
<div id='container' className={styles.container} style={{ height: window.innerHeight -45 }}/>
{/* 房源列表 */}
{/* 添加 styles.show 展示房屋列表 */}
<div
className={[
// styles.houseList,
styles.housesList,
this.state.isShowList ? styles.show : ''
].join(' ')}
>
<div className={styles.titleWrap}>
<h1 className={styles.listTitle}>房屋列表</h1>
<Link className={styles.titleMore} to="/home/list">
更多房源
</Link>
</div>
<div className={styles.houseItems}>
{/* 房屋结构 */}
{this.renderHousesList()}
</div>
</div>
</div>
}
}
希望实现如下效果:
1、进入此页面后,首先显示区级别的地图,同时显示区级别对应的覆盖物:
2、点击其中一个覆盖物后,地图放大到镇街级别,同时显示镇街级别对应的覆盖物:
3、点击其中一个覆盖物后,地图放大到小区级别的地图,同时显示小区级别对应的覆盖物:
4、点击其中一个覆盖物后,地图底部向上拉出一个房源基本信息框,同时让被点的房源移动到地图范围内的中央位置:
目前效果如下:
1、放大地图级别后,上一级别的比例尺仍继续显示并与新一级别的重叠显示:
2、区、镇街、小区对应不同的地图放大级别,地图处于不同放大级别时不会自动显示对应的区、镇街和小区数据:
3、点击小区级别的房源时,chrome浏览器报错:
请问代码出了什么问题?如何修改?