js(react)中使用百度地图

0 需求

依次点击区-镇-小区,展示当前位置的数据列表 ;移动地图(movestart事件),隐藏详情。

1 准备工作 

1.1 引入百度地图并配置ak

jspopularGL | 百度地图API SDK

1.2  根据IP定位获取当前定位

import axios from 'axios';

export const getCurrentCity = () => {
  const localCity=JSON.parse(localStorage.getItem('hkzf_city'))
  if (!localCity) {//localStorage 中是否有定位城市,没有,保存并返回
    return new Promise((resolve, reject) => {
      const curCity = new window.BMapGL.LocalCity();
      curCity.get(async res => {
        try {//成功
          const result = await axios.get(`http://localhost:8080/area/info?name=${res.name}`)
          localStorage.setItem('hkzf_city', JSON.stringify(result.body))
          resolve(res.body)//返回结果为promise:如果直接return,外层函数无法接收到
        } catch(e) {//失败
          reject(e)
        }
      })
    })
  }
  return Promise.resolve(localCity)//有,直接返回:此处的 Promise 不会失败
}

2 代码实现

index.jsx

import React from 'react'
import styles from './index.module.scss'
import NavHeader from '../../components/NavHeader'
import axios from 'axios'
import { Link } from 'react-router-dom'
import { Toast } from 'antd-mobile'

export default class Map extends React.Component {
  // 覆盖物样式
  labelStyle = {
    cursor: 'pointer',
    border: '0px solid rgb(255, 0, 0)',
    padding: '0px',
    whiteSpace: 'nowrap',
    fontSize: '12px',
    color: 'rgb(255, 255, 255)',
    textAlign: 'center'
  }
  state = {
    housesList: [],
    isShowList: false
  }
  componentDidMount () {
    this.initMap();
  }
  initMap () {
    // 1初始化地图实例
    const { label, value } = JSON.parse(localStorage.getItem('hkzf_city'));//当前城市name,id
    var map = new window.BMapGL.Map("container");//在 react 脚手架中全局对象需要使用 window 来访问,否则,会造成 ESLint 校验错误
    this.map = map;
    // 2将地址转换为坐标
    var myGeo = new window.BMapGL.Geocoder(); //创建地址解析器实例
    myGeo.getPoint(label, (point) => {// 将地址解析结果显示在地图上,并调整地图视野
      if (point) {
        // 2.1设置中心点
        map.centerAndZoom(point, 11);
        // 2.2添加地图控件
        map.enableScrollWheelZoom(true); // 开启鼠标滚轮缩放
        var scaleCtrl = new window.BMapGL.ScaleControl();// 添加比例尺控件
        map.addControl(scaleCtrl);
        var zoomCtrl = new window.BMapGL.ZoomControl();// 添加缩放控件
        map.addControl(zoomCtrl);
        // 2.3渲染覆盖物
        this.renderOverlays(value)
      } else {
        alert('您选择的地址没有解析到结果!');
      }
    }, label)
    // 给地图绑定移动事件
    map.addEventListener('movestart', () => {
      console.log('movestart')
      if (this.state.isShowList) {
        this.setState({
          isShowList: false
        })
      }
    })
  }

  // 渲染覆盖物
  async renderOverlays (id) {
    try {
      Toast.show({
        icon: 'loading',
        content: '加载中…',
        duration: 0,
      })
      // 获取数据
      const res = await axios.get(
        `http://localhost:8080/area/map?id=${id}`
      )
      Toast.clear()
      const data = res.data.body
      // 获取类型及缩放级别
      const { nextZoom, type } = this.getTypeAndZoom()
      // 渲染数据
      this.map.clearOverlays();
      data.forEach(item => {
        this.createOverlays(item, nextZoom, type)
      })
    } catch (e) {
      Toast.clear()
    }
  }

  // 计算要绘制的覆盖物类型和下一个缩放级别
  getTypeAndZoom () {
    const zoom = this.map.getZoom();
    let nextZoom, type
    if (zoom >= 10 && zoom < 12) {// 区
      nextZoom = 13
      type = 'circle'
    } else if (zoom >= 12 && zoom < 14) {// 镇
      nextZoom = 15
      type = 'circle'
    } else if (zoom >= 14 && zoom < 16) {// 小区
      type = 'rect'
    }
    return { nextZoom, type }
  }

  // 创建覆盖物
  createOverlays (item, nextZoom, type) {
    const {
      coord: { longitude, latitude },
      label: areaName,
      count, value
    } = item;
    // 将经纬度转化为坐标
    var pointArea = new window.BMapGL.Point(longitude, latitude);
    if (type === 'circle') {
      this.createCircle(pointArea, areaName, count, value, nextZoom)
    } else {
      this.createRect(pointArea, areaName, count, value)
    }
  }

  // 创建区、镇覆盖物
  createCircle (pointArea, areaName, count, value, nextZoom) {
    // 1创建文本标注覆盖物实例
    var content = "文本覆盖物";
    var labelTXT = new window.BMapGL.Label(content, {
      position: pointArea,// 设置标注的地理位置
      offset: new window.BMapGL.Size(-35, -35)// 设置标注的偏移量
    })
    // 2设置结构
    labelTXT.setContent(`
      <div class="${styles.bubble}">
        <p class="${styles.name}">${areaName}</p>
        <p>${count}</p>
      </div>
    `)
    // 3设置样式
    labelTXT.setStyle(this.labelStyle)
    this.map.addOverlay(labelTXT);// 将标注添加到地图中
    // 4监听标注事件
    labelTXT.addEventListener('click', (e) => {
      this.renderOverlays(value)
      this.map.centerAndZoom(pointArea, nextZoom);
    });
  }

  // 创建小区覆盖物
  createRect (pointArea, areaName, count, value) {
    var content = "";
    var labelTXT = new window.BMapGL.Label(content, {
      position: pointArea,
      offset: new window.BMapGL.Size(-50, -28)
    })
    labelTXT.setContent(`
      <div class="${styles.rect}">
        <span class="${styles.housename}">${areaName}</span>
        <span class="${styles.housenum}">${count}套</span>
        <i class="${styles.arrow}"></i>
      </div>
    `)
    labelTXT.setStyle(this.labelStyle)
    this.map.addOverlay(labelTXT);
    labelTXT.addEventListener('click', (e) => {
      // 获取小区房源数据
      this.getHouseList(value);
      const { x, y, width, height } = e.target.domElement.getBoundingClientRect()
      console.log(x, y, width, height)
      // 将被点击的房源移动到中心位置
      this.map.panBy(
        window.innerWidth / 2 - x,
        (window.innerHeight - 330) / 2 - y
      )
    });
  }

  // 获取小区房源数据
  async getHouseList (id) {
    try {
      Toast.show({
        icon: 'loading',
        content: '加载中…',
        duration: 0,
      })
      const res = await axios.get(`http://localhost:8080/houses?cityId=${id}`)
      Toast.clear()
      this.setState({
        housesList: res.data.body.list,
        isShowList: true
      })
    } catch (e) {
      Toast.clear()
    }
  }

  // 渲染小区房源数据
  renderHousesList () {
    return this.state.housesList.map(item => (
      <div className={styles.house} key={item.houseCode}>
        <div className={styles.imgWrap}>
          <img
            className={styles.img}
            src={`http://localhost:8080${item.houseImg}`}
            alt=""
          />
        </div>
        <div className={styles.content}>
          <h3 className={styles.title}>{item.title}</h3>
          <div className={styles.desc}>{item.desc}</div>
          <div>
            {item.tags.map(tag => (
              <span
                className={[styles.tag, styles.tag1].join(' ')}
                key={tag}
              >
                {tag}
              </span>
            ))}
          </div>
          <div className={styles.price}>
            <span className={styles.priceNum}>{item.price}</span> 元/月
          </div>
        </div>
      </div>
    ))
  }
  render () {
    return (
      <div className={styles.map}>
        <NavHeader>地图找房</NavHeader>
        <div id="container" className={styles.container}></div>
        {/* 房源列表:动态类名显示 */}
        <div
          className={[
            styles.houseList,
            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>
    )
  }
}

index.module.scss 

/* 房源列表样式: */
.houseList {
  position: fixed;//固定定位
  bottom: 0;
  left: 0;
  width: 100%;
  height: 330px;
  transition: all 1s;//过渡效果
  transform: translate3d(0, 330px, 0);//向下移动列表的高度
  background: #fff;
  z-index: 5;
}
.show {
  transform: translate3d(0, 0, 0);//恢复原位置
}

.houseItems {
  padding: 0 10px;
  overflow-y: auto;//占满垂直方向剩余高度
  height: 100%;
  padding-bottom: 45px;
}

3 代码分析

3.1 封装流程

3.2 代码逻辑 

初始化渲染:创建map实例,以当前定位为中心点渲染地图(使用IP定位),并添加控件;

渲染覆盖物

        获取数据:接口需返回的数据信息包括:位置id,位置name,当前位置的经纬度;

        渲染数据:将经纬度转换为坐标;初始化当前类型和下一级缩放级别;创建文本标注实例,设置结构和样式后添加到地图上。

点击覆盖物

        圆形:放大地图;渲染下一级数据。

        矩形:移动地图;渲染列表数据。

        注意:事件对象中e的clientX=undefined,需要借助getBoundingClientRect()将数据移动到中心点位置。

3.3 中心点移动分析

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值