react 地图找房模块

封装流程

界面

js 复制代码
render() {
    return (
      <div className={styles.map}>
        {/* 地图容器 */}
        <NavHeader>地图找房</NavHeader>
        <div id="container" className={styles.container} />

        {/* 房源列表 */}
        {/* 添加 styles.show 展示房屋列表 */}
        <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>
    );
  }

初始化地图

JS 复制代码
initMap() {
    const { label, value } = JSON.parse(localStorage.getItem("hkzf_city"));
    // 创建地图实例
    const map = new BMap.Map("container");
    this.map = map;
    // 创建地址解析器实例
    var myGeo = new BMap.Geocoder();
    // 将地址解析结果显示在地图上,并调整地图视野
    myGeo.getPoint(
      label,
      async (point) => {
        if (point) {
          // 初始化地图,同时设置展示级别
          map.centerAndZoom(point, 11);
          // 添加标注
          // map.addOverlay(new BMap.Marker(point));

          // 添加常见控件
          map.addControl(new BMap.NavigationControl());
          map.addControl(new BMap.ScaleControl());

          // 渲染覆盖物
          this.renderOverlays(value);
        }
      },
      label,
    );

    // 给地图绑定移动事件
    map.addEventListener("movestart", () => {
      // console.log('地图正在移动')
      if (this.state.isShowList) {
        // 隐藏列表
        this.setState({
          isShowList: false,
        });
      }
    });
  }

渲染覆盖物入口

js 复制代码
/**
   * 渲染覆盖物入口
   * @param {*} id
   */
  async renderOverlays(id) {
    try {
      Toast.loading("加载中...", 0, null, false);

      const res = await API.get(`/area/map?id=${id}`);
      Toast.hide();
      const data = res.data.body;

      // 调用 getTypeAndZoom 方法获取级别和类型
      const { type, nextZoom } = this.getTypeAndZoom();

      data.forEach((item) => {
        this.createOverlays(item, nextZoom, type);
      });
    } catch (error) {
      Toast.hide();
    }
  }

计算要绘制的覆盖物类型和下一个缩放级别

js 复制代码
// 计算要绘制的覆盖物类型和下一个缩放级别
  // 区   -> 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,
    };
  }

创建覆盖物

js 复制代码
/**
   * 创建覆盖物
   * @param {*} item
   */
  createOverlays(data, zoom, type) {
    // 为每一条数据创建覆盖物
    const {
      coord: { longitude, latitude },
      label: areaName,
      count,
      value,
    } = data;
    // 创建覆盖物
    const areaPoint = new BMap.Point(longitude, latitude);
    if (type === "circle") {
      this.createCircle(areaPoint, areaName, count, value, zoom);
    } else {
      this.createRect(areaPoint, areaName, count, value);
    }
  }

创建小区覆盖物

复制代码
// 创建小区覆盖物
  createRect(point, name, count, id) {
    const label = new BMap.Label("", {
      position: point,
      offset: new BMap.Size(-50, -28),
    });

    // 为label对象添加一个唯一标识
    label.id = id;

    // 创建标签对象
    label.setContent(`
            <div class="${styles.rect}">
              <p class="${styles.housename}">${name}</p>
              <p class="${styles.housenum}">${count}套</p>
              <span class="${styles.arrow}"></span>
            </div>
            `);
    label.setStyle(labelStyle);
    label.addEventListener("click", (e) => {
      console.log("小区被点击了");
      this.getHouseList(id);
      // 获取当前被点击项
      const target = e.changedTouches[0];
      // panBy() 方法,移动地图到中间位置
      this.map.panBy(
        window.innerWidth / 2 - target.clientX,
        (window.innerHeight - 330) / 2 - target.clientY,
      );
    });
    // 添加覆盖物到地图
    this.map.addOverlay(label);
  }

创建区域覆盖物

js 复制代码
// 创建区域覆盖物
  createCircle(point, name, count, id, zoom) {
    const label = new BMap.Label("", {
      position: point,
      offset: new BMap.Size(-35, -35),
    });

    // 为label对象添加一个唯一标识
    label.id = id;

    // 设置房源覆盖物内容
    label.setContent(`
            <div class="${styles.bubble}">
              <p class="${styles.name}">${name}</p>
              <p>${count}套</p>
            </div>
            `);
    // 设置样式
    label.setStyle(labelStyle);

    // 添加单击事件
    label.addEventListener("click", () => {
      this.renderOverlays(id);
      console.log("点击了覆盖物", label.id);
      this.map.centerAndZoom(point, zoom);

      // 清除当前覆盖物信息
      this.map.clearOverlays();
    });

    // 解决清除覆盖物时,百度地图API的JS文件自身报错的问题
    setTimeout(() => {
      // 添加覆盖物到地图
      this.map.addOverlay(label);
    }, 0);
  }

获取小区下的房源列表

js 复制代码
// 获取小区下的房源列表
  async getHouseList(id) {
    try {
      // 开启loading
      Toast.loading("加载中...", 0, null, false);

      const res = await API.get(`/houses?cityId=${id}`);
      // 关闭 loading
      Toast.hide();

      this.setState({
        housesList: res.data.body.list,
        // 展示房源列表
        isShowList: true,
      });
    } catch (e) {
      // 关闭 loading
      Toast.hide();
    }
  }

封装渲染房屋列表的方法

js 复制代码
// 封装渲染房屋列表的方法
  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}
      />
    ));
  }
相关推荐
NaMM CHIN2 小时前
Spring boot整合quartz方法
java·前端·spring boot
低保和光头哪个先来2 小时前
Axios 近期安全版本
开发语言·前端·javascript·前端框架
han_2 小时前
JavaScript设计模式(八):命令模式实现与应用
前端·javascript·设计模式
AlunYegeer2 小时前
黑马头条踩坑总结:频道状态筛选前端联调失效问题
java·前端
蜡台2 小时前
浙政钉(浙里办小程序) H5 二次回退问题修复方案
前端·小程序·浙政钉·浙里办
踩着两条虫2 小时前
揭秘VTJ.PRO前端架构:一套代码,多端运行的低代码引擎
前端·vue.js·低代码
fzil0012 小时前
用 React 写 CLI 是什么体验?—— Ink 框架深度解析与实战
前端·react.js·前端框架
长相思9792 小时前
text-overflow: ellipsis和display:flex互斥
前端·css·html
不像程序员的程序媛2 小时前
es查询是否存在某个字段
java·前端·elasticsearch