React实现地图找房

业务:使用百度地图API实现地图找房

功能:

  • 展示当前定位城市
  • 展示该城市所有区的房源数据
  • 展示某区下所有镇的房源数据
  • 展示某镇下所有小区的房源数据
  • 展示某小区下的房源数据列表

代码如下:

javascript 复制代码
import React from "react";
import AMapLoader from "@amap/amap-jsapi-loader";
import NavHeader from "../../components/NavHeader/index";

import request from "../../request/index";

import { getCurrenCity } from "../../utils/index";

import "./index.scss";
import axios from "axios";

import { Toast } from "antd-mobile";

export default function Map() {
  // 当前城市的信息
  let map = null;
  let AMap = null;
  let locationId = "";
  let coverList = [];
  let type = "city"; // 市,镇 标记是圆形;区标记是矩形;
  let zoomNumber = 11; // 市 11;镇 13;小区 15
  const [houseList, setHouseList] = React.useState([]);
  const [showFlg, setShowFlg] = React.useState(false);
  const urlBase = "http://localhost:8080";

  React.useEffect(() => {
    loadInit();
  }, []);

  const loadInit = () => {
    // 利用高德地图API,逆地理位置转换 经纬度
    getCurrenCity().then((data) => {
      // console.log("当前地址=》", data);

      locationId = data.value;
      const params = {
        key: "6aae8eb1ea15d5e7ca50af4b079c7687",
        address: `${data.label}`,
      };
      axios
        .get("https://restapi.amap.com/v3/geocode/geo", { params })
        .then((res) => {
          // console.log("地理位置", res);
          const position = res.data.geocodes[0].location.split(",");
          // 初始化地图
          loadMap(position);

          // 获取房源数据
          renderOverlays(locationId);
        });
    });
  };

  const loadMap = (position) => {
    // 加载高德地图API
    AMapLoader.load({
      key: "21c7cb07194d66a059387fb531bd7e43", // 替换为你的高德地图API Key
      version: "2.0",
      plugins: [],
    })
      .then((res) => {
        AMap = res;
        // 初始化地图
        map = new AMap.Map("container", {
          zoom: 11,
          center: position,
        });

        //异步加载控件
        AMap.plugin("AMap.ToolBar", function () {
          const toolbar = new AMap.ToolBar(); //缩放工具条实例化
          map.addControl(toolbar); //添加控件
        });
        AMap.plugin("AMap.Scale", function () {
          const scale = new AMap.Scale(); // 比例尺控件
          map.addControl(scale);
        });

        // 监听地图平移
        map.on("movestart", () => {
          console.log("地图平移开始", showFlg);
          setShowFlg(false);
        });
      })
      .catch((e) => {
        console.error(e);
      });
  };

  // 获取房源数据
  const renderOverlays = (locationId) => {
    try {
      Toast.show({
        icon: "loading",
        content: "加载中...",
        duration: 0,
      });
      request.get("/area/map", { params: { id: locationId } }).then((res) => {
        if (res.body.length > 0) {
          coverList = [];
          // 创建覆盖物
          res.body.forEach((item) => {
            getTypeAndZoom(item);
          });
          // 将 marker 添加到地图
          map.add(coverList);
          Toast.clear();
        }
      });
    } catch (error) {
      alert("获取数据失败");
      Toast.clear();
    }
  };

  // 创建覆盖物
  const getTypeAndZoom = (Object) => {
    const {
      coord: { longitude, latitude },
      value,
      count,
      label,
    } = Object;
    // 点标记显示内容,HTML要素字符串
    const markerContent =
      "" +
      '<div class="custom-content-marker flex_col">' +
      `<span>${label}</span>` +
      `<span>${count}套</span>` +
      "</div>";

    const communityContent =
      "" +
      '<div class="community-content-marker">' +
      `<span>${label}</span>` +
      `<span>${count}套</span>` +
      "</div>";

    const marker = new AMap.Marker({
      position: [longitude, latitude],
      // 将 html 传给 content
      content:
        type === "city" || type === "town" ? markerContent : communityContent,
      offset: new AMap.Pixel(-50, -28),
    });

    marker.id = value;
    marker.typeMarker = type;

    marker.on("click", (e) => {
      const {
        target: { id, typeMarker },
        pixel,
      } = e;
      // console.log("点击了marker", e);

      // 切换typeModel类型
      if (typeMarker === "city") {
        type = "town";
        zoomNumber = 13;
      } else if (typeMarker === "town") {
        type = "area";
        zoomNumber = 15;
      }

      if (typeMarker !== "area") {
        // 清除地图上所有添加的覆盖物
        map.clearMap();

        // 以当前点击的覆盖物为中心放大地图
        map.setZoomAndCenter(zoomNumber, [longitude, latitude]);

        // 传入点击的 id 获取房源
        renderOverlays(id);
      } else {
        renderHouseList(id);

        /* 
        调用地图 panBy() 方法,移动地图到中间为止
        公式:
          垂直位移:(window.innerHeight - 330) / 2 - target.clientY
          水平位移:window.innerWidth / 2 - target.clientX
        */
        const clientX = pixel.getX();
        const clientY = pixel.getY();
        map.panBy(
          window.innerWidth / 2 - clientX,
          (window.innerHeight - 330) / 2 - clientY
        );
      }
    });

    coverList.push(marker);
  };

  // 获取小区的房源数据
  const renderHouseList = (id) => {
    try {
      Toast.show({
        icon: "loading",
        content: "加载中...",
        duration: 0,
      });

      request.get("/houses", { params: { cityId: id } }).then((res) => {
        console.log("小区房源", res);
        if (res.status === 200) {
          const { list } = res.body;
          setHouseList(list);
          setShowFlg(true);
          Toast.clear();
        }
      });
    } catch (error) {
      alert("获取数据失败");
      Toast.clear();
    }
  };

  return (
    <div className="map">
      <NavHeader title="地图找房" />
      {/* 地图容器元素 */}
      <div id="container"></div>
      {/* 小区的房源数据 */}

      <div
        className="house-list"
        style={{ display: showFlg ? "block" : "none" }}
      >
        <div className="header flex flex_r_b ">
          <span className="title">房屋列表</span>
          <span className="more">更多房源</span>
        </div>
        <div
          style={{ overflowY: "auto", overflowX: "hidden", height: "330px" }}
        >
          {houseList.map((item) => (
            <div key={item.houseCode} className=" content flex">
              <img src={urlBase + item.houseImg} alt="" />
              <div className="info flex flex_c_b">
                <div className="span1">{item.title}</div>
                <div className="span2">{item.desc}</div>

                <div className="tag-list flex">
                  {item.tags.map((tag, index) => (
                    <div className="span3" key={index}>
                      {tag}
                    </div>
                  ))}
                </div>

                <div className="span4">
                  {item.price}
                  <span style={{ fontSize: "12px" }}>元/月</span>
                </div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

相关视频:https://www.bilibili.com/video/BV1gh411U7JD?spm_id_from=333.788.videopod.episodes\&vd_source=2f48f471bbeafdcd207f29dadcc97a5d\&p=153

gitee地址:https://gitee.com/abcdfdewrw/react_hkzf

高德地图API:https://lbs.amap.com/api/javascript-api-v2/guide/map/map-layer

UI组件库:https://ant-design-mobile.antgroup.com/zh/components/nav-bar

难点:高德地图的使用

相关推荐
anyup_前端梦工厂2 小时前
了解几个 HTML 标签属性,实现优化页面加载性能
前端·html
前端御书房2 小时前
前端PDF转图片技术调研实战指南:从踩坑到高可用方案的深度解析
前端·javascript
2301_789169542 小时前
angular中使用animation.css实现翻转展示卡片正反两面效果
前端·css·angular.js
风口上的猪20153 小时前
thingboard告警信息格式美化
java·服务器·前端
程序员黄同学3 小时前
请谈谈 Vue 中的响应式原理,如何实现?
前端·javascript·vue.js
爱编程的小庄4 小时前
web网络安全:SQL 注入攻击
前端·sql·web安全
宁波阿成5 小时前
vue3里组件的v-model:value与v-model的区别
前端·javascript·vue.js
柯腾啊5 小时前
VSCode 中使用 Snippets 设置常用代码块
开发语言·前端·javascript·ide·vscode·编辑器·代码片段
weixin_535854225 小时前
oppo,汤臣倍健,康冠科技,高途教育25届春招内推
c语言·前端·嵌入式硬件·硬件工程·求职招聘
扣丁梦想家5 小时前
设计模式教程:装饰器模式(Decorator Pattern)
java·前端·装饰器模式