vue项目中使用百度地图api完成自定义搜索功能(包含搜索详细地理位置)
需求描述:在vue项目中,有时候,我们需要自定义百度地图的一些功能。譬如,现在的需求,就是需要自定义搜索内容和结果展示。类似如下页面的功能:首先在vue项目中,我们可以使用 vue-baidu-map 插件来替代直接引入百度地图js sdk。npm install --save vue-baidu-mapvue-baidu-map的具体使用文档参考官方文档:https://dafrok.githu
·
需求描述:
在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地址:
更多推荐
已为社区贡献28条内容
所有评论(0)