需求描述:

在vue项目中,有时候,我们需要自定义百度地图的一些功能。譬如,现在的需求,就是需要自定义搜索内容和结果展示。

类似如下页面的功能:
在这里插入图片描述

首先在vue项目中,我们可以使用 vue-baidu-map 插件来替代直接引入百度地图js sdk。

npm install --save vue-baidu-map 

vue-baidu-map的具体使用文档参考官方文档:

https://dafrok.github.io/vue-baidu-map/#/zh/start/installation

解决方案一: 利益vue-baidu-map的BmAutoComplete 自动填充 功能。(很垃圾,不推荐)

在这里插入图片描述
我们可以实现类似的效果。但是,非常的不好用,也不建议,有z-index的问题,结果也不能自定义。

不过也贴一段参考代码:

<template>
  <div>

        <el-form ref="form" label-width="136px">
          <div class="mg-b16">
            <baidu-map class="bm-view" ak="你的百度ak" :center="mapCenter" :zoom="mapZoom" :scroll-wheel-zoom="true" @ready="handlerBMap"> </baidu-map>
          </div>
          <el-form-item label="详细地址:" prop="projectId" class="mg-b16 autocomplete-wrapper">
            <el-input v-model="mapLocation.address" type="text" :sugStyle="sugStyle" ref="suggestInput" style="width: 400px; "></el-input>
          </el-form-item>

          <el-form-item label="详细坐标:" prop="projectId" class="mg-b0">
            <el-input v-model="mapLocation.str" type="text" :readonly="true" style="width: 400px"></el-input>
          </el-form-item>
        </el-form>
        <div class="a-r">
          <el-button @click="flag = false">取消</el-button>
          <el-button type="primary" @click="confirmFn">确定</el-button>
        </div>
  </div>
</template>

<script>
import BaiduMap from 'vue-baidu-map/components/map/Map.vue'
let self
export default {
  name: 'mapLabel',
  props: ['mapObj'],
  data() {
    return {
      flag: false,
      mapZoom: 15,
      sugStyle: {
        zIndex: 999
      },
      mapCenter: { lng: 0, lat: 0 },
      mapLocation: {
        index: 0,
        address: '',
        str: '',
        city: '',
        point: {
          lng: 0,
          lat: 0
        }
      }
    }
  },
  watch: {
    mapObj: {
      deep: true,
      handler(val) {
        this.mapLocation.index = val.index
        this.mapLocation.address = val.fullAddr
        this.mapLocation.city = val.cityName
        this.mapLocation.point.lng = val.longitude
        this.mapLocation.point.lat = val.latitude
        if (val.latitude && val.latitude) {
          this.mapLocation.str = 'E' + val.longitude + '  N' + val.latitude
        }
      }
    }
  },
  components: { BaiduMap },
  created() {
    self = this
  },
  methods: {
    handlerBMap({ BMap, map }) {
      this.map = map
      this.input = this.$refs.suggestInput.$el.querySelector('input')
      this.ac = new BMap.Autocomplete({
        input: this.input,
        location: this.map,
        onSearchComplete: () => {
          // 手动添加z-inded
          const $sugs = document.querySelectorAll('.tangram-suggestion-main')
          for (const $sug of $sugs) {
            for (const name in this.sugStyle) {
              $sug.style[name] = this.sugStyle[name].toString()
            }
          }
        }
      })
      //手动设置input值
      self.mapLocation.address && this.ac.setInputValue(self.mapLocation.address)

      this.ac.addEventListener('onconfirm', function(e) {
        //鼠标点击下拉列表后的事件
        var _value = e.item.value
        self.mapLocation.address = _value.province + _value.city + _value.district + _value.street + _value.business
        map.clearOverlays() //清除地图上所有覆盖物
        function myFun() {
          if (local.getResults().getPoi(0)) {
            var pp = local.getResults().getPoi(0).point //获取第一个智能搜索的结果
            var str = 'E' + pp.lng + '  N' + pp.lat
            self.mapLocation.str = str
            self.mapLocation.point = pp
            map.centerAndZoom(pp, 15)
            map.addOverlay(new BMap.Marker(pp)) //添加标注
          } else {
            self.mapLocation.point = {}
          }
        }
        var local = new BMap.LocalSearch(map, {
          //智能搜索
          onSearchComplete: myFun
        })
        local.search(self.mapLocation.address)
      })
      if (self.mapLocation.point && self.mapLocation.point.lng) {
        this.mapCenter.lng = this.mapLocation.point.lng
        this.mapCenter.lat = this.mapLocation.point.lat
        this.mapZoom = 15
        map.addOverlay(new BMap.Marker(this.mapLocation.point))
      } else if (this.mapLocation.city) {
        this.map.centerAndZoom(this.mapLocation.city, 11)
      } else {
        this.map.centerAndZoom('深圳', 11)
      }
    },
    show() {
      this.flag = true
    },
    hide() {
      this.flag = false
    },
    confirmFn() {
      var obj = this.mapLocation
      if (!obj.point.lng) {
        this.$message.error('请先标注经纬度')
        return false
      }
      this.$emit('mapCallback', obj)
      this.hide()
    }
  }
}
</script>

<style lang="scss">
.bm-view {
  width: 100%;
  height: 300px;
}
</style>

解决方案二:利用vue-baidu-map的BmLocalSearch组件实现 (推荐)

最后实现的效果如下:
在这里插入图片描述
代码如下:


<!--
 * @Description: 地图标记
 * @Autor: bolingsun
 * @Date: 2022-02-23 13:38:59
-->
<template>
  <div class="map-maker-wrapper">
    <Header title="选择地址">
      <template v-slot:right>
        <div class="btn-confrim" @click="handleSubmit">确定</div>
      </template>
    </Header>
    <baidu-map
      class="bm-view"
      ak="你的百度ak"
      :center="mapCenter"
      :zoom="mapZoom"
      :scroll-wheel-zoom="true"
      @ready="onReady"
    >
      <bm-local-search
        :keyword="keyword"
        @searchcomplete="onSearchComplete"
        :auto-viewport="true"
        :panel="false"
      ></bm-local-search>
    </baidu-map>

    <div class="search-wrap">
      <div class="search">
        <img class="search-img" src="@/assets/images/icon_nav_search_18_black@2x.png" />
        <input class="search-input" type="text" v-model="keyword" />
        <span class="search-btn" @click="handleSearch">搜索</span>
      </div>

      <!-- 检索结果 -->
      <div v-show="showResultFlag" class="search-result">
        <div v-for="(item, index) in searchResult" class="item" :key="index" @click="handleSelect(item)">
          <p class="title">{{ item.title }}</p>
          <p class="address">{{ item.address }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { Toast } from 'vant'
import Header from '@/components/Header'
import BaiduMap from 'vue-baidu-map/components/map/Map.vue'
import { BmLocalSearch } from 'vue-baidu-map'
const defaultInfo = {
  lng: 0,
  lat: 0,
  addressStr: '',
  title: '',
  province: '', // 省
  city: '', // 市
  district: '' // 区
}
export default {
  name: 'MapMaker',
  components: {
    Header,
    BaiduMap,
    BmLocalSearch
  },
  data() {
    return {
      BMap: null,
      map: null,
      mapZoom: 15,
      mapCenter: { lng: 116.404, lat: 39.915 },
      keyword: '',
      searchResult: [], // 检索结果列表
      showResultFlag: true,
      selectInfo: Object.assign({}, defaultInfo)
    }
  },
  methods: {
    // 地图初始化回调
    onReady({ BMap, map }) {
      this.BMap = BMap
      this.map = map
      // console.log('BMap', BMap)
    },
    handleSearch() {
    },
   
    handleSubmit() {
      console.log('this.selectInfo', this.selectInfo)
    },
    // 搜索回调
    onSearchComplete(res) {
      console.log('res', res)
      if (res && res.Kr) {
        this.searchResult = [...res.Kr]
        if (this.onceFlag) {
          this.onceFlag = false
        } else {
          this.showResultFlag = true
        }
      }
    },
    handleSelect(item) {
      let self = this
      console.log('item', item)
      let title = item.title
      let { lng, lat } = item.marker.point
      console.log('lng,lat', lng, lat)
      // 以下代码是为了根据经纬度去转换出 省、市、区的信息出来。如果,不需要,可以自行修改。
      let point = new this.BMap.Point(lng, lat)
      let geoc = new this.BMap.Geocoder()
      geoc.getLocation(point, function (res) {
        // console.log('res111', res)
        let addString =
          res.addressComponents.province + res.addressComponents.city + res.addressComponents.district + title
        console.log('addString', addString)
        self.onceFlag = true
        self.showResultFlag = false
        self.keyword = addString
        self.map.clearOverlays() //清除地图上所有覆盖物
        self.map.addOverlay(new self.BMap.Marker({ lng, lat }))
        self.mapCenter.lng = lng
        self.mapCenter.lat = lat
        self.mapZoom = 15
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.map-maker-wrapper {
  position: relative;
}
.btn-confrim {
  width: 120px;
  height: 56px;
  line-height: 56px;
  background-color: #5ac9d4;
  border-radius: 8px;
  color: #ffffff;
  text-align: center;
}
.bm-view {
  width: 100%;
  height: calc(100vh - 88px);
}
.search-wrap {
  position: absolute;
  top: 120px;
  left: 0;
  width: 100vw;
  box-sizing: border-box;
  padding: 0 32px;
  // background-color: red;
  .search {
    background-color: #fff;
    padding: 28px 32px;
    border-radius: 24px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
    .search-img {
      width: 48px;
      height: 48px;
    }
    .search-input {
      flex: 1;
      outline: none;
      border: none;
      background: none;
      font-size: 28px;
      color: #313233;
    }
    .search-btn {
      font-size: 28px;
      font-weight: 600;
      color: #313233;
    }
  }
  .search-result {
    background-color: #fff;
    padding: 0 32px;
    border-radius: 24px;
    max-height: 720px;
    overflow: scroll;
    .item {
      border-bottom: 1px solid #ebeef2;
      padding: 32px 0;
      &:last-child {
        border-bottom: none;
      }
      .title {
        font-size: 28px;
        font-weight: 600;
        color: #313233;
      }
      .address {
        font-size: 24px;
        font-weight: 400;
        color: #9ca5b3;
        margin-top: 8px;
      }
    }
  }
}
</style>

备注:
参考了以下代码,,实现根据已知的经纬度 =》 得出省、市、区的信息数据。

var x = 115.792111;
var y = 33.877972;
var point = new BMap.Point(x,y);
var geoc = new BMap.Geocoder();
geoc.getLocation(point, function(rs){
var addComp = rs.addressComponents;
$('p').html(addComp.city+addComp.district+addComp.street+addComp.streetNumber);
}); 

解决方案三:使用BMap.LocalSearch来实现自定义搜索功能 (强烈推荐)

<!--
 * @Description: 地图标记
 * @Autor: bolingsun
 * @Date: 2022-02-23 13:38:59
-->
<template>
  <div class="map-maker-wrapper">
    <Header title="选择地址">
      <template v-slot:right>
        <div class="btn-confrim" @click="handleSubmit">确定</div>
      </template>
    </Header>
    <baidu-map
      class="bm-view"
      ak="你的百度ak"
      :center="mapCenter"
      :zoom="mapZoom"
      :scroll-wheel-zoom="true"
      @ready="onReady"
    >
    </baidu-map>

    <div class="search-wrap">
      <div class="search">
        <img class="search-img" src="@/assets/images/icon_nav_search_18_black@2x.png" />
        <input class="search-input" type="text" v-model="keyword" />
        <span class="search-btn" @click="handleSearch">搜索</span>
      </div>

      <!-- 检索结果 -->
      <div v-show="showResultFlag" class="search-result">
        <div v-for="(item, index) in searchResult" class="item" :key="index" @click="handleSelect(item)">
          <p class="title">{{ item.title }}</p>
          <p class="address">{{ item.address }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { Toast } from 'vant'
import Header from '@/components/Header'
import BaiduMap from 'vue-baidu-map/components/map/Map.vue'
// import { BmLocalSearch } from 'vue-baidu-map'
const defaultInfo = {
  lng: 0,
  lat: 0,
  addressStr: '',
  title: '',
  province: '', // 省
  city: '', // 市
  district: '' // 区
}
export default {
  name: 'MapMaker',
  components: {
    Header,
    BaiduMap
  },
  data() {
    return {
      BMap: null,
      map: null,
      mapZoom: 15,
      mapCenter: { lng: 116.404, lat: 39.915 },
      keyword: '',
      searchResult: [], // 检索结果列表
      showResultFlag: true,
      selectInfo: Object.assign({}, defaultInfo)
    }
  },
  methods: {
    // 地图初始化回调
    onReady({ BMap, map }) {
      this.BMap = BMap
      this.map = map
      // console.log('BMap', BMap)
    },
    handleSearch() {
      let self = this
      self.showResultFlag = true
      console.log('111111111', defaultInfo)
      self.selectInfo = Object.assign({}, defaultInfo)
      let local = new this.BMap.LocalSearch(this.map, {
        renderOptions: {
          map: this.map,
          selectFirstResult: false
        },
        onSearchComplete: function (res) {
          // console.log('results', res)
          if (res && res.Kr) {
            self.searchResult = [...res.Kr]
          }
        }
      })
      local.search(this.keyword)
    },
    handleSelect(item) {
      let self = this
      console.log('item', item)
      let title = item.title
      let { lng, lat } = item.marker.point
      console.log('lng,lat', lng, lat)
      let point = new this.BMap.Point(lng, lat)
      let geoc = new this.BMap.Geocoder()
      geoc.getLocation(point, function (res) {
        // console.log('res111', res)
        let addString =
          res.addressComponents.province + res.addressComponents.city + res.addressComponents.district + title
        console.log('addString', addString)
        self.showResultFlag = false
        self.keyword = addString
        self.map.clearOverlays() //清除地图上所有覆盖物
        self.map.addOverlay(new self.BMap.Marker({ lng, lat }))
        self.mapCenter.lng = lng
        self.mapCenter.lat = lat
        self.mapZoom = 15
        self.selectInfo = {
          lng,
          lat,
          addressStr: addString,
          title: title,
          province: res.addressComponents.province,
          city: res.addressComponents.city,
          district: res.addressComponents.district
        }
      })
    },
    handleSubmit() {
      console.log('this.selectInfo', this.selectInfo)
    }
  }
}
</script>

<style lang="scss" scoped>
.map-maker-wrapper {
  position: relative;
}
.btn-confrim {
  width: 120px;
  height: 56px;
  line-height: 56px;
  background-color: #5ac9d4;
  border-radius: 8px;
  color: #ffffff;
  text-align: center;
}
.bm-view {
  width: 100%;
  height: calc(100vh - 88px);
}
.search-wrap {
  position: absolute;
  top: 120px;
  left: 0;
  width: 100vw;
  box-sizing: border-box;
  padding: 0 32px;
  // background-color: red;
  .search {
    background-color: #fff;
    padding: 28px 32px;
    border-radius: 24px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
    .search-img {
      width: 48px;
      height: 48px;
    }
    .search-input {
      flex: 1;
      outline: none;
      border: none;
      background: none;
      font-size: 28px;
      color: #313233;
    }
    .search-btn {
      font-size: 28px;
      font-weight: 600;
      color: #313233;
    }
  }
  .search-result {
    background-color: #fff;
    padding: 0 32px;
    border-radius: 24px;
    max-height: 720px;
    overflow: scroll;
    .item {
      border-bottom: 1px solid #ebeef2;
      padding: 32px 0;
      &:last-child {
        border-bottom: none;
      }
      .title {
        font-size: 28px;
        font-weight: 600;
        color: #313233;
      }
      .address {
        font-size: 24px;
        font-weight: 400;
        color: #9ca5b3;
        margin-top: 8px;
      }
    }
  }
}
</style>

原理,也很简单,就是使用百度本身的搜索功能。

对应的百度地图demo地址:

https://lbsyun.baidu.com/jsdemo.htm#localSearchKey

Logo

前往低代码交流专区

更多推荐