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}
      />
    ));
  }
相关推荐
mldong7 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排8 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60618 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角9 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!10 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰10 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi11 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen12 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马13 小时前
AI源码分析:拆解模型底层实现逻辑
前端
IT_陈寒13 小时前
React子组件莫名其妙重渲染?你可能漏了这个Hook
前端·人工智能·后端