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

难点:高德地图的使用

相关推荐
美狐美颜sdk3 小时前
跨平台直播美颜sdk集成攻略:Android、iOS与Web的统一方案
android·前端·ios
Airser3 小时前
npm启动Taro框架报错
前端·npm·taro
Anlici4 小时前
连载小说大学生课设 需求&架构
前端·javascript·后端
2501_938769995 小时前
React Server Components 进阶:数据预取与缓存
前端·react.js·缓存
蒜香拿铁6 小时前
Angular【基础语法】
前端·javascript·angular.js
xiaoxiao无脸男6 小时前
纯css:一个好玩的按钮边框动态动画
前端·css·css3
rookie_fly6 小时前
基于Vue的数字输入框指令
前端·vue.js·设计模式
元直数字电路验证6 小时前
ASP.NET Core Web APP(MVC)开发中无法全局配置 NuGet 包,该怎么解?
前端·javascript·ui·docker·asp.net·.net
rexling17 小时前
【Spring Boot】Spring Boot解决循环依赖
java·前端·spring boot
我有一棵树7 小时前
Vue 项目中全局样式的正确写法:不要把字体和主题写在 #app 上
前端·javascript·vue.js