Vue3 + 百度地图实现位置选择,获取地址经纬度

  • 需求:添加传感器时,需要选择传感器所在的省、市、区、详细地址、以及传感器的经纬度信息。
  • 解决方案:集成百度地图API,通过在地图上搜索或者点击获取传感器的具体位置信息。

百度地图选择地址效果

  • 具体效果如下图所示

集成百度地图的具体实现

  • 技术方案: Vue + ElementUI + 百度地图 JavaScript API v3.0
  • 申请成为百度地图开发者并获取秘钥
    • 参考文档:https://lbsyun.baidu.com/index.php?title=jspopular3.0/guide/getkey

第一步:引入百度地图 JavaScript API v3.0 文件

export function BMPGL(ak) {
  return new Promise(function (resolve, reject) {
    window.init = function () {
      // eslint-disable-next-line
      resolve(BMapGL);
    };
    const script = document.createElement("script");
    script.type = "text/javascript";
    script.src = `http://api.map.baidu.com/api?v=3.0&type=webgl&ak=${ak}&callback=init`;
    script.onerror = reject;
    document.head.appendChild(script);
  });
}

第二步:编写百度地图选择位置组件

<template>
  <div class="bmapgl">
    <p>搜索地址获取地址的经纬度</p>
    <el-button @click="show" style="margin-bottom: 20px">打开地图</el-button>
    <el-form label-width="80px">
      <el-row>
        <el-col :span="10">
          <el-form-item label="当前地点">
            <el-input
              size="small"
              type="text"
              readonly
              v-model="addressInfo.address"
            />
          </el-form-item>
        </el-col>
        <el-col :span="7">
          <el-form-item label="位置经度">
            <el-input
              size="small"
              type="text"
              v-model="addressInfo.longitude"
              readonly
            />
          </el-form-item>
        </el-col>
        <el-col :span="7">
          <el-form-item label="位置纬度">
            <el-input
              size="small"
              type="text"
              v-model="addressInfo.latitude"
              readonly
            />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <el-dialog
      v-model="openMap"
      title="位置选择"
      width="1000px"
      :close-on-click-modal="false"
      destroy-on-close
    >
      <el-form label-width="80px">
        <el-row>
          <el-col :span="10">
            <el-form-item label="当前地点">
              <el-input
                size="small"
                type="text"
                id="suggestId"
                v-model="addressInfo.address"
                placeholder="请输入地点"
              />
            </el-form-item>
          </el-col>
          <el-col :span="7">
            <el-form-item label="位置经度">
              <el-input
                size="small"
                type="text"
                v-model="addressInfo.longitude"
                readonly
              />
            </el-form-item>
          </el-col>
          <el-col :span="7">
            <el-form-item label="位置纬度">
              <el-input
                size="small"
                type="text"
                v-model="addressInfo.latitude"
                readonly
              />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div
        class="baidu"
        ref="mapRef"
        id="baidumap"
        style="width: 100%; height: 450px"
      ></div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="cancel">取 消</el-button>
          <el-button type="primary" @click="confirmSelect"> 确 定 </el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { BMPGL } from "@/utils/loadBmap.ts";
import { onMounted, watch, ref, reactive } from "vue";
import { ElMessage } from "element-plus";
const emit = defineEmits(["confirmMapAddress"]);

let map = ref(null);
const mapZoom = ref(15);
const ak = ref("填百度地图密钥");
let openMap = ref(false);
let addressInfo = reactive({
  // 地址信息
  longitude: "", // 经度
  latitude: "", // 纬度
  province: "", // 省
  city: "", // 市
  district: "", // 区
  address: "", // 详细地址
});
watch(
  () => [openMap],
  () => {
    if (!openMap.value) {
      map.value && map.value.destroy();
    }
  },
  { deep: true }
);
onMounted(() => {
  initMap();
});
const initMap = () => {
  map.value = null;
  BMPGL(ak.value).then((BMapGL: any) => {
    map.value = new BMapGL.Map("baidumap");
    var ac = new BMapGL.Autocomplete({
      //建立一个自动完成的对象
      input: "suggestId",
      location: map.value,
    });
    var zoomCtrl = new BMapGL.ZoomControl(); // 添加缩放控件
    map.value.addControl(zoomCtrl);
    var cityCtrl = new BMapGL.CityListControl(); // 添加城市列表控件
    map.value.addControl(cityCtrl);
    var LocationControl = new BMapGL.LocationControl(); // 添加定位控件,用于获取定位
    map.value.addControl(LocationControl);
    var scaleCtrl = new BMapGL.ScaleControl(); // 添加比例尺控件
    map.value.addControl(scaleCtrl);
    map.value.setMapType(); // 设置地图类型为标准地图模式;
    var localcity = new BMapGL.LocalCity();
    localcity.get((e: { name: any }) => {
      map.value.centerAndZoom(e.name, mapZoom.value);
    });

    let point: any;

    //初始化的时候如果有经纬度,需要先在地图上添加点标记
    if (addressInfo.longitude && addressInfo.latitude) {
      point = new BMapGL.Point(addressInfo.longitude, addressInfo.latitude);
      map.value.centerAndZoom(point, mapZoom.value);
      var marker2 = new BMapGL.Marker(point);
      //在地图上添加点标记
      map.value.addOverlay(marker2);
    }

    map.value.enableScrollWheelZoom(true);
    map.value.setHeading(64.5);
    map.value.setTilt(73);

    //点击下拉框的值
    map.value.addEventListener(
      "click",
      function (e: { latlng: { lng: string; lat: string } }) {
        map.value.clearOverlays();
        var point1 = new BMapGL.Point(e.latlng.lng, e.latlng.lat);
        // 创建点标记
        var marker1 = new BMapGL.Marker(point1);
        // 在地图上添加点标记
        map.value.addOverlay(marker1);
        addressInfo.longitude = e.latlng.lng;
        addressInfo.latitude = e.latlng.lat;
        var geoc = new BMapGL.Geocoder(); // 创建地址解析器的实例
        geoc.getLocation(point1, (rs: { addressComponents: any }) => {
          let adr = rs.addressComponents;
          addressInfo.address =
            adr.province +
            adr.city +
            adr.district +
            adr.street +
            adr.streetNumber; // 省市区街道门牌号
        });
      }
    );
    ac.addEventListener("onconfirm", function (e: { item: { value: any } }) {
      //鼠标点击下拉列表后的事件
      var _value = e.item.value;
      addressInfo.address =
        _value.province +
        _value.city +
        _value.district +
        _value.street +
        _value.business;
      // 搜索
      map.value.clearOverlays(); //清除地图上所有覆盖物
      //智能搜索
      var local = new BMapGL.LocalSearch(map.value, {
        onSearchComplete: () => {
          //获取第一个智能搜索的结果
          const pp = local.getResults().getPoi(0).point;
          map.value.centerAndZoom(pp, mapZoom.value);
          map.value.addOverlay(new BMapGL.Marker(pp)); //添加标注
          addressInfo.longitude = pp.lng;
          addressInfo.latitude = pp.lat;
        },
      });
      local.search(addressInfo.address);
    });
  });
};
/** 打开地图选择 */
const show = () => {
  openMap.value = true;
  initMap();
};
/**
 * 确认选择
 */
const confirmSelect = () => {
  if (addressInfo.address == "") {
    ElMessage({
      message: "请选择位置",
      type: "error",
      center: true,
    });
    return;
  }
  emit("confirmMapAddress", addressInfo);
  openMap.value = false;
};
/**
 * 取消选择
 */
const cancel = () => {
  openMap.value = false;
};
</script>
<style>
.tangram-suggestion {
  z-index: 99999;
}
</style>
<style scoped lang="scss">
:deep(.BMap_cpyCtrl) {
  display: none !important;
}
:deep(.BMap_cpyCtrl) {
  display: none !important;
}

:deep(.el-dialog__header),
:deep(.el-dialog__footer) {
  padding: 15px 20px;
}

:deep(.el-dialog__body) {
  border-top: 1px solid #e8eaec;
  border-bottom: 1px solid #e8eaec;
  padding: 20px;
}
:deep(.el-dialog__headerbtn) {
  top: 0;
  font-size: 18px;
}
:deep(.el-dialog) {
  border-radius: 8px;
}
</style>

项目中需要使用到Bmap模糊地址查询的功能,但是发现搜索出的结果展示被遮挡。已经搜索到结果但是被dialog给遮挡住了。

解决方式:

需要修改autocomplete的样式,调整css z-index设置元素的堆叠顺序:

<style>
  .tangram-suggestion {
    z-index: 99999;
  }
</style>

注意不要踩坑的是:

要去掉style标签的 scoped,这样的话重写的css样式才能生效。

百度地图Web开发
JavaScript API v3.0 (2D地图 标准版)
API文档地址:https://lbsyun.baidu.com/index.php?title=jspopular3.0
示例地址:https://lbsyun.baidu.com/index.php?title=open/jsdemo3.0
JavaScript API v2.0 (没有维护了)
JavaScript API v1.0(没有维护了)
JavaScript API Lite v1.0 (2D地图 移动端H5版)
API文档地址:https://lbsyun.baidu.com/index.php?title=jspopularLiteV1
示例地址:https://lbsyun.baidu.com/index.php?title=open/jsdemoLite
JavaScript API GL v1.0 (3D地图 )
API文档地址:https://lbsyun.baidu.com/index.php?title=jspopularGL
示例地址:https://lbsyun.baidu.com/jsdemo.htm

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐