Vue2如何实现嵌入百度地图

分类:效率专区 时间: 2025-08-22 11:05:36 浏览: 作者:效率牛-珂珂

前端如何嵌入百度地图

image.png

一、注册并创建百度地图开放平台应用

地址如下:https://lbsyun.baidu.com/apiconsole/center

1、首先创建一个浏览器端的应用,可自定义勾选的启用服务如下:

image.pngimage.png

2、开发一个服务端应用(用于后端通过经纬度获取地址,可自行决定是否创建)

image.png

这时回到我的应用里,就能看到刚刚申请的两个应用的信息了,访问应用AK就是待会调用地图的关键。

image.png

同时可以到额度管理中查看各项服务的免费配额

image.png

二、嵌入地图应用背景

image.png

如图所示,本地采用按钮跳转的形式,故而将基于实现背景展开具体实现。 

ui为"element-ui": "2.15.5"版本,上图的按钮代码为

<el-button slot="append" icon="el-icon-location-information" @click="choiceMap()" prop="longitude" readonly/>

至于地图,我则抽出为一个组件

<MapProp ref="map" :single-choice="true" @callData="mapChecked"  map_key="project-map"/>

并在components中进行导入

  components: {
    MapProp
  },

MapProp 组件代码稍候再贴出并详细讲解,所以这个组件可以在讲解后再进行引入;

先来看看choiceMap方法传入的内容:

choiceMap() {
  this.$refs.map.init({
    id : this.dataForm.id,
    projectAddress: this.dataForm.projectAddress,//详细地址
    longitude: this.dataForm.longitude,//经度
    latitude: this.dataForm.latitude//纬度
  });
},

主要用于保存地址信息及进入时默认定位为传入的经纬度,id可以自行判断是否需要传递;

再来看看地图的mapChecked回调方法:

mapChecked(data) {
  let province = data.province;//省
  let city = data.city;//市
  let district = data.district;//区、县
  let street = this.dataForm.projectAddress;//保存修改前的地址
  this.dataForm.projectAddress = data.address;//详细地址
  this.dataForm.longitude = data.addrPoint.lng;//经度
  this.dataForm.latitude = data.addrPoint.lat;//纬度
  let param = {
    province,
    city,
    district
  }
  // 根据省市地址获取省市对应的id填入工程地区字段,如果省市为空则表示没有做修改,不做处理
  if (street !== this.dataForm.projectAddress) {
    getCityIdByProvinceAndCity(param).then((res) => {
      this.dataForm.projectAreaids = '[' + res.data.toString() + ']';
      // 地址信息
      this.dataForm.projectAreaids = JSON.parse(this.dataForm.projectAreaids);
      this.isShowProjectAreaidsInfo = false;
      this.$nextTick(() => {
        this.isShowProjectAreaidsInfo = true;
      })
    })
  }
},

主要用于将选择的地址信息回传直父级页面进行保存及展示,可自行选择回传的字段信息

三、实现步骤

1、首先创建一个js文件,定义动态加载百度地图的api

export default function loadBMap() {
  let ak = 'xxxxxx';
  return new Promise(function(resolve, reject) {
    if (typeof window.BMap !== 'undefined') {
      resolve(window.BMap)
      return true
    }
    window.onBMapCallback = function() {
      resolve(window.BMap)
    }
    let script = document.createElement('script')
    script.type = 'text/javascript'
    script.src =
      'https://api.map.baidu.com/api?v=3.0&ak=' + ak + '&callback=onBMapCallback'
    script.onerror = reject
    document.head.appendChild(script)
  })
}

代码中的AK就是刚刚在百度开放平台中申请的浏览器端的AK,去复制过来填入即可


2、创建一个组件用于展示地图

也就是上文中提到的MapProp组件,全代码如下(注意:部分代码嵌套了第三方的css文件,需要自行删除,比如包含“DIAN-common-layout”、“DIAN-common-layout-center”的标签,需自行删除):

<template>
  <el-dialog :title="title" :visible.sync="visible" class="DIAN-dialog DIAN-dialog_center" lock-scroll append-to-body :close-on-click-modal = "false"
             width="98%" @closed="destroyMap">
    <div>
      <div>
        <div>
          <el-form ref="form" :model="form" label-width="100px" @submit.native.prevent>
            <el-row>
              <el-col :span="24">
                <el-form-item label="当前地址:" prop="completeAddress">
                  <el-autocomplete
                    v-model="form.completeAddress"
                    style="width:100%;"
                    popper-class="autoAddressClass"
                    :fetch-suggestions="querySearchAsync"
                    :trigger-on-focus="false"
                    placeholder="详细地址"
                    clearable
                    @select="handleSelect"
                  >
                    <template slot-scope="{ item }">
                      <i class="el-icon-search fl mgr10"/>
                      <div style="overflow:hidden;">
                        <div>{{ item.title }}</div>
                        <span class="address ellipsis">{{ item.address }}</span>
                      </div>
                    </template>
                  </el-autocomplete>
                </el-form-item>
              </el-col>
<!--              <el-col :span="6">-->
<!--                <el-form-item label="位置经度">-->
<!--                  <el-input-->
<!--                    size="small"-->
<!--                    type="text"-->
<!--                    v-model="form.addrPoint.lng"-->
<!--                    readonly-->
<!--                  />-->
<!--                </el-form-item>-->
<!--              </el-col>-->
<!--              <el-col :span="6">-->
<!--                <el-form-item label="位置纬度">-->
<!--                  <el-input-->
<!--                    size="small"-->
<!--                    type="text"-->
<!--                    v-model="form.addrPoint.lat"-->
<!--                    readonly-->
<!--                  />-->
<!--                </el-form-item>-->
<!--              </el-col>-->
            </el-row>
            <el-form-item label="地图定位:">
              <div :id="map_key" style="width:100%;height:70vh;"/><!--395-->
              <!-- 遮罩层 -->
              <div style="position:absolute;bottom:0;left:0;right:0;height:20px;background-color:white;"></div>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="onSubmit">确定</el-button>
              <el-button @click="visible = false">{{ $t('common.cancelButton') }}</el-button>
              <!--              <el-button type="primary" @click="fixedPosition">定位当前位置</el-button>-->
            </el-form-item>
          </el-form>
        </div>
      </div>
    </div>
  </el-dialog>
</template>

<script>
import loadBMap from "@/api/loadBMap";
import {getNearbyProject} from "@/api/market/projectReport";
import $dian from "@/utils/dian";

export default {
  props: {
    title: {
      default: '选择地址'
    },
    map_key: {
      default: 'map-container'
    },
  },
  data() {
    return {
      visible: false,// 弹窗显示
      form: {
        id: '', //项目id
        completeAddress: '', //完整地址
        province: '', //省份
        city: '', // 市级
        district: '', // 区、县级
        address: '', // 详细地址
        addrPoint: { // 详细地址经纬度
          lng: '',// 经度
          lat: '',// 纬度
        }
      },
      map: '', // 地图实例
      mk: '', // Marker实例
    }
  },
  async mounted() {
    await loadBMap() // 加载引入BMap
    this.initMap()
  },
  methods: {
    async init(data) {
      this.visible = true;
      this.form.id = data.id;
      this.form.completeAddress = data.projectAddress;//完整地址
      this.form.address = data.projectAddress;//详细地址
      this.form.addrPoint.lng = data.longitude ? data.longitude : '116.2317';//详细地址经纬度
      this.form.addrPoint.lat = data.latitude ? data.latitude : '39.5427';//详细地址经纬度
    },
    // 初始化地图
    initMap() {
      let point;
      const that = this;
      // 1、挂载地图
      // this.map = new BMap.Map(this.map_key, {enableMapClick: false})// 创建地图实例
      // if (this.form.addrPoint.lng && this.form.addrPoint.lat) {// 如果有地址经纬度
      //   point = new BMap.Point(this.form.addrPoint.lng, this.form.addrPoint.lat);
      // } else {
        // that.fixedPosition() // 浏览器定位获取当前经纬度
        // 2、设置中心点坐标和地图级别
        // point = new BMap.Point(this.form.addrPoint.lng, this.form.addrPoint.lat);// 创建点坐标
      // }
      this.map = new BMap.Map(this.map_key, {enableMapClick: false})// 创建地图实例
      point = new BMap.Point(this.form.addrPoint.lng, this.form.addrPoint.lat);
      that.getAddrByPoint(point)
      this.map.centerAndZoom(point, 15)// 初始化地图,设置中心点坐标和地图级别
      //获取周边500米范围内的项目并标记出来
      if ($dian.hasPerBtnP('market:projectReport:showProject') && that.form.address) {// 判断是否有权限,以及是否为第二次打开弹窗
        this.getAroundProject();
      }
      // 3、设置图像标注并绑定拖拽标注结束后事件
      this.mk = new BMap.Marker(point, {enableDragging: true})// 创建标注
      this.map.addOverlay(this.mk)// 添加标注
      this.mk.addEventListener('dragend', function (e) {// 拖拽标注结束后事件
        that.getAddrByPoint(e.point)// 根据拖拽后的标注点获取详细地址
      })
      // 4、添加(右上角)平移缩放控件
      this.map.addControl(new BMap.NavigationControl({
        anchor: BMAP_ANCHOR_TOP_RIGHT,// 控件位置
        type: BMAP_NAVIGATION_CONTROL_SMALL// 控件类型
      }))
      this.map.enableScrollWheelZoom(true);     // 允许鼠标滑轮放大缩小

      // 5、添加(右下角)定位控件
      const geolocationControl = new BMap.GeolocationControl({
        anchor: BMAP_ANCHOR_BOTTOM_RIGHT,// 控件位置(右下角)BMAP_ANCHOR_TOP_LEFT\BMAP_ANCHOR_BOTTOM_RIGHT
        showAddressBar: true, //是否显示定位信息面板
        enableAutoLocation: true,  //首次是否进行自动定位
        offset: new BMap.Size(6, 22)//偏移距离
      });
      geolocationControl.addEventListener('locationSuccess', function (e) {// 定位成功事件
        that.getAddrByPoint(e.point)
        that.$message("地址获取成功")
      })
      geolocationControl.addEventListener('locationError', function (e) {// 定位失败事件
        that.$message.error("定位失败,请稍候再试");
      })
      this.map.addControl(geolocationControl)// 添加定位控件
      // 7、绑定点击地图任意点事件
      this.map.addEventListener('click', function (e) {
        that.getAddrByPoint(e.point)
      })
    },
    // 浏览器定位获取当前经纬度(不同浏览器的使用会出现问题,暂时弃用)
    fixedPosition() {
      const that = this;
      const geolocation = new BMap.Geolocation();
      geolocation.getCurrentPosition(function (r) {
        if (this.getStatus() == BMAP_STATUS_SUCCESS) {
          that.getAddrByPoint(r.point)
        } else {
          that.$message.error("定位失败,请手动搜索地址或稍候再试")
        }
      }, {enableHighAccuracy: true});//是否要求浏览器获取最佳效果,默认为false
    },
    // 2、逆地址解析函数
    getAddrByPoint(point) {
      var that = this
      var geco = new BMap.Geocoder()// 创建地址解析器实例
      geco.getLocation(point, function (res) {// 获取详细地址信息
        console.log("地址解析结果:", res)
        that.mk.setPosition(point)// 设置Marker位置,点击地图能够实时更新到标注地址
        that.map.panTo(point)// 定位到该点
        that.map.centerAndZoom(point, that.map.getZoom());//设置中心点坐标并获取当前缩放级别地图级别进行设置
        that.form.completeAddress = res.address + res.business + res.content.poi_desc;//设置完整地址
        that.form.province = res.addressComponents.province// 设置省份
        that.form.city = res.addressComponents.city// 设置市级
        that.form.district = res.addressComponents.district// 设置区、县级
        that.form.address = that.splitAddress(that.form.completeAddress);//详细地址
        that.form.addrPoint = point// 设置详细地址经纬度
      })
    },
    //获取周边500米范围内的项目并标记出来
    getAroundProject() {
      const that = this;
      // 根据返回的经纬度去查询数据库中五百米内项目并展示出来
      let param = {
        id: that.form.id,
        longitude: that.form.addrPoint.lng,
        latitude: that.form.addrPoint.lat,
      }
      var i = 0;
      //获取周边五百米内项目
      getNearbyProject(param).then((res) => {
        const mapPoints = res.data;
        //创建多个标注
        function markerFun(points) {
          // 创建自定义图标
          var icon = new BMap.Icon(
            require("../../../../../public/cdn/img/bule-marker.png"),
            new BMap.Size(100, 100), {
              anchor: new BMap.Size(13, 28),// 设置图片锚点
            });
          var markers = new BMap.Marker(points, {icon: icon});// 创建标注
          that.map.addOverlay(markers);// 添加标注
        }
        for (; i < mapPoints.length; i++) {
          var points = new BMap.Point(mapPoints[i].longitude, mapPoints[i].latitude);//创建坐标点
          markerFun(points);
        }
      })
    },
    // 8-1、地址搜索
    querySearchAsync(str, cb) {
      var options = {
        onSearchComplete: function (res) {
          var s = []
          if (local.getStatus() == BMAP_STATUS_SUCCESS) {
            for (var i = 0; i < res.getCurrentNumPois(); i++) {
              var poi = res.getPoi(i);
              if (!poi.province) {//如果没有省份信息,则使用搜索结果的省份信息
                poi.province = res.province
                poi.city = res.city
                poi.district = res.district
              }
              s.push(res.getPoi(i))
            }
            cb(s)
          } else {
            cb(s)
          }
        }
      }
      var local = new BMap.LocalSearch(this.map, options)// 创建地址搜索实例
      local.search(str)// 开始搜索
    },
    // 8-2、选择地址
    handleSelect(item) {
      console.log("选择地址结果",item)
      if (item.address === item.title) {
        this.form.completeAddress = item.address//完整地址
      }else {
        this.form.completeAddress = item.address + item.title//完整地址
      }
      this.form.province = item.province//省份
      this.form.city = item.city//市级
      this.form.district = item.district//区、县级
      this.form.address = this.splitAddress(this.form.completeAddress);//详细地址
      this.form.addrPoint = item.point//详细地址经纬度
      this.map.clearOverlays()// 清除标注
      this.mk = new BMap.Marker(item.point)
      this.map.addOverlay(this.mk)
      this.map.panTo(item.point)
    },
    //获取选择值
    onSubmit() {
      let form = this.form;
      this.visible = false;
      this.$emit('callData', form)
      this.destroyMap();
    },
    // 在对话框关闭时销毁地图实例
    destroyMap() {
      if (this.map) {
        this.map.removeOverlay(this.mk);
        this.map.close();// 关闭地图(浏览器会抛出错误,但不影响使用)
        this.map = null; // 销毁地图实例
      }
      if (this.mk) {
        this.mk = null; // 清除Marker实例
      }
      const mapContainer = document.getElementById(this.map_key);
      mapContainer.parentNode.removeChild(mapContainer);
    },
    // 修改地图初始化时机
    async handleDialogOpen() {
      await loadBMap();
      this.$nextTick(() => {
        this.initMap();
      });
    },
    // 地址去掉省、市、县或区级单位
    splitAddress(address) {
      address = address.replace(this.form.province, "");
      address = address.replace(this.form.city, "");
      address = address.replace(this.form.district, "");
      return address;
    },
  },
  // 监听visible变化,打开对话框时初始化地图
  watch: {
    visible(newValue) {
      if (newValue) {
        this.handleDialogOpen();
      }
    },
  },
  // 组件销毁时销毁地图实例
  beforeDestroy() {
    this.destroyMap();
  },
}
</script>

<style scoped>
> > > .autoAddressClass {
  li {
    i.el-icon-search {
      margin-top: 11px;
    }

    .mgr10 {
      margin-right: 10px;
    }

    .title {
      text-overflow: ellipsis;
      overflow: hidden;
    }

    .address {
      line-height: 1;
      font-size: 12px;
      color: #b4b4b4;
      margin-bottom: 5px;
    }
  }
}
.DIAN-dialog {
  >>> .el-dialog__body {
    min-height: 90vh;
  }
}
</style>


展示结果则为最上面的效果图

image.png


3、部分代码讲解

(1)搜索框

<el-form-item label="当前地址:" prop="completeAddress">
 <el-autocomplete
   v-model="form.completeAddress"
   style="width:100%;"
   popper-class="autoAddressClass"
   :fetch-suggestions="querySearchAsync"
   :trigger-on-focus="false"
   placeholder="详细地址"
   clearable
   @select="handleSelect"
 >
   <template slot-scope="{ item }">
     <i class="el-icon-search fl mgr10"/>
     <div style="overflow:hidden;">
       <div class="title">{{ item.title }}</div>
       <span class="address ellipsis">{{ item.address }}</span>
     </div>
   </template>
 </el-autocomplete>
</el-form-item>

这段代码是上图中的搜索框,实现地址的搜索

image.png

(2)地图实例

<el-form-item label="地图定位:">
  <div :id="map_key" style="width:100%;height:70vh;"/><!--395-->
  <!-- 遮罩层 -->
  <div style="position:absolute;bottom:0;left:0;right:0;height:20px;background-color:white;"> </div>
</el-form-item>

这段代码则是实现了地图的渲染及百度地图水印的遮挡,因为百度地图默认是有展示水印的,这里不展示未遮罩前的效果,有兴趣看看的话注释第三行代码即可;

map_key则是渲染的关键,我们看到代码中的mounted钩子:

  async mounted() {
    await loadBMap() // 加载引入BMap
    this.initMap()
  },

loadBMap就是上文中创建的动态加载百度地图api的.js文件

在methods的init方法中:

this.visible = true;
this.form.id = data.id;
this.form.completeAddress = data.projectAddress;//完整地址
this.form.address = data.projectAddress;//详细地址
this.form.addrPoint.lng = data.longitude ? data.longitude : '116.2317';//详细地址经纬度
this.form.addrPoint.lat = data.latitude ? data.latitude : '39.5427';//详细地址经纬度


visible 属性用于将页面弹出打开

completeAddress 属性和 address 都是用于保存地址,区别在于一个为绝对路径一个为相对路径

addrPoint.lng和addrPoint.lat为进入地图时默认定位的地址,当传入的longitude和latitude 为空时则会定位到默认的经纬度中,上文默认定位的到北京天安门


再往后的代码后面都有注释,以大家的智商肯定是一看就明白了,重点说一下getAroundProject方法:

getAroundProject() {
  const that = this;
  // 根据返回的经纬度去查询数据库中五百米内项目并展示出来
  let param = {
    id: that.form.id,
    longitude: that.form.addrPoint.lng,
    latitude: that.form.addrPoint.lat,
  }
  var i = 0;
  //获取周边五百米内项目
  getNearbyProject(param).then((res) => {
    const mapPoints = res.data;
    //创建多个标注
    function markerFun(points) {
      // 创建自定义图标
      var icon = new BMap.Icon(
        require("../../../../../public/cdn/img/bule-marker.png"),
        new BMap.Size(100, 100), {
          anchor: new BMap.Size(13, 28),// 设置图片锚点
        });
      var markers = new BMap.Marker(points, {icon: icon});// 创建标注
      that.map.addOverlay(markers);// 添加标注
    }
    for (; i < mapPoints.length; i++) {
      var points = new BMap.Point(mapPoints[i].longitude, mapPoints[i].latitude);//创建坐标点
      markerFun(points);
    }
  })
},

这个方法主要用于渲染存在于传入的经纬度周边的标注,可自行选择是否删除,我的应用场景为当定位的地址周边五百米存在项目时就会进行展示,显示效果如下:

image.png

用不上的话将相关代码删除即可。

再往后就是地图销毁之类的代码,大部分无需修改,不过选择的具体返回地址信息可以在handleSelect方法中自行定义

handleSelect(item) {
  console.log("选择地址结果",item)
  if (item.address === item.title) {
    this.form.completeAddress = item.address//完整地址
  }else {
    this.form.completeAddress = item.address + item.title//完整地址
  }
  this.form.province = item.province//省份
  this.form.city = item.city//市级
  this.form.district = item.district//区、县级
  this.form.address = this.splitAddress(this.form.completeAddress);//详细地址
  this.form.addrPoint = item.point//详细地址经纬度
  this.map.clearOverlays()// 清除标注
  this.mk = new BMap.Marker(item.point)
  this.map.addOverlay(this.mk)
  this.map.panTo(item.point)
},

四,其他注意事项

目前发现部分浏览器会出现定位不准确的情况,也就是点击图中的定位会出现定位不准确的情况

image.png

因为情况是偶发性的,会因为浏览器的不同会出现有时会出现,有时不会出现的情况(本人使用谷歌浏览器会出现),因为定位是根据网络定位,实验多次后发现使用微信自带的浏览器是最准确的,具体原因不详,提前给大家提个醒。

1. 本站所有资源来源于用户上传或网络,仅作为参考研究使用,如有侵权请邮件联系站长!
2. 本站积分货币获取途径以及用途的解读,想在本站混的好,请务必认真阅读!
3. 本站强烈打击盗版/破解等有损他人权益和违法作为,请各位会员支持正版!
效率专区 >Vue2如何实现嵌入百度地图

用户评论

加载中~