vue项目中使用百度地图api完成自定义搜索功能(包含搜索详细地理位置)

89 篇文章 7 订阅
2 篇文章 0 订阅

需求描述:

在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

  • 7
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
Vue是一种流行的前端框架,可以用于构建交互式的Web应用程序。百度地图是一种常用的地图服务,可以提供丰富的地理信息和功能。当我们结合Vue百度地图时,可以使用起终点坐标来模拟小车的实时运动。 首先,我们需要在Vue项目引入百度地图API。可以通过在index.html文件添加百度地图的script标签或者在main.js文件使用import语句引入。 接下来,我们需要创建一个地图实例,可以在Vue组件的生命周期钩子函数created进行。使用百度地图API的`BMap.Map()`方法可以创建一个地图实例。 然后,我们可以通过输入起终点的经纬度坐标来计算两点之间的距离和方位角。使用百度地图API的`BMap.Point()`方法可以创建一个点的实例。然后,使用百度地图API的`BMaplib.DistanceTool()`方法可以计算两点之间的距离。再使用百度地图API的`BMaplib.RichMarker()`方法可以创建一个自定义标记点。 最后,我们可以使用定时器方法setInterval来定时更新小车的位置。可以在Vue的data属性定义一个变量来保存小车的当前位置,然后在定时器更新这个位置,使用百度地图API的`BMap.Marker()`方法可以创建一个标记点,将小车的位置传给它来更新标记点的位置。同时,可以使用百度地图API的`BMap.Symbol()`方法来设置标记点的图标,如设置为一个小车的图标。 通过以上步骤,我们就可以使用Vue百度地图来模拟小车的实时运动了。当起终点坐标发生变化时,小车的位置也会相应改变,并在地图上实时更新。这样,我们可以实现一个基于Vue百度地图的小车实时运动模拟效果。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值