前一段时间我应公司的需求开发了相似链家地图找房的功能,然而我发现如今市面上,对于链家地图找房功能的完整实现相关的文章仍是比较稀缺的,亦或是功能还不够完善,出于这个方面,我以为把本身对于链家地图找房功能的完整实现分享出来仍是颇有必要的,包括其中的画圈找房,以及如何将整个地图找房拆分红一个个组件。css
目前项目已上线,猛戳这里体验~(仅支持pc端)html
vue全家桶 + vue-baidu-map + BMapLibvue
其中 vue-baidu-map 是第三方库,已经封装好了部分组件,直接用就行;BMapLib是百度开源库git
地图容器组件: <baidu-map></baidu-map>
github
区域气泡组件(自定义覆盖物): <zoneOverlay></zoneOverlay>
api
区域边界组件: <bm-boundary></bm-boundary>
数组
周边房源气泡组件(自定义覆盖物): <aroundOverlay></aroundOverlay>
bash
周边房源详情覆盖物组件(自定义覆盖物): <detailOverlay></detailOverlay>
app
画圈找房区域气泡组件: <bm-polygon><bm-polygon>
flex
画圈找房路径组件: <bm-polyline></bm-polyline>
画圈找房提示组件: <drawToast></drawToast>
周边房源总数提示组件: <dataToast></dataToast>
首先,咱们要作的就是地图初始化,这里用到的是 baidu-map 组件,
<div class="map-wrapper">
<baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" @ready="handler"></baidu-map>
</div>
复制代码
参数说明:
center 表示地图的中心点坐标,例如{ lng: 116.404, lat: 39.915 }
zoom 表示地图的缩放等级
scroll-wheel-zoom 表示是否开启滚轮缩放
ready事件表示地图加载完成后须要的操做,例如设置地图中心点坐标 center,或者是获取 BMap、map 类等等
handler ({ BMap, map }) {
// lng, lat 表示你要设置的经纬度
this.$set(this.center, 'lng', lng)
this.$set(this.center, 'lat', lat)
console.log(BMap) // just console.log(BMap)
console.log(map) // just console.log(map)
}
复制代码
在这里,我是先定位获取当前省份的经纬度,经过事件传递,而后设置 center
handler ({BMap, map}) {
this.initGeo()
},
initGeo () {
connect.$on('cityGeoOk', data => {
this.$set(this.center, 'lng', data[0])
this.$set(this.center, 'lat', data[1])
})
}
复制代码
至于 vue 跨组件的通讯就比如打电话同样,须要一个基站,因此新建一个js文件(这里我命名为 connect)
import Vue from 'vue'
export default new Vue()
复制代码
而后在组件中引入便可,经过 connect.$emit('event', data)
派发一个事件,而后经过 connect.$on('event', data => {})
侦听事件。
最后,还须要设置一下地图容器 baidu-map 的缩放等级(我设置的是12,具体可本身调整)和高度,否则是看不见效果的
.bm-view{
height: 100%; /* for example */
}
复制代码
效果以下:
在地图初始化以后,接下来就是如何将不一样的区域显示在地图上了,这里我用到的是 bm-overlay 组件,而且将其二次封装成 zoneOverlay 组件。
<div class="map-wrapper">
<baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" @ready="handler">
<div>
<zone-overlay
v-for="(item, index) in zoneGeoPoints" :key="index"
:position="{lng: item.lng, lat: item.lat}"
:text="item">
</zone-overlay>
</div>
</baidu-map>
</div>
复制代码
zoneGeoPoints 表示区域数组,从后台接口获取,元素为对象,属性包括区域的经纬度等信息。
// zoneOverlay.vue
<template>
<bm-overlay
ref="customOverlay"
class="zone"
pane="labelPane"
@draw="draw">
<div>
<p>{{text.name}}</p>
<p>{{text.houseCnt}}套</p>
</div>
</bm-overlay>
</template>
<script>
export default {
props: ['text', 'position', 'active'],
watch: {
position: {
handler () {
this.$refs.customOverlay.reload()
},
deep: true
}
},
methods: {
draw ({el, BMap, map}) {
const {lng, lat} = this.position
const pixel = map.pointToOverlayPixel(new BMap.Point(lng, lat))
el.style.left = pixel.x - 42 + 'px'
el.style.top = pixel.y - 42 + 'px'
}
}
}
</script>
<style lang="stylus" scoped>
.zone
transition: background-color .15s ease-in-out
display: flex
align-items: center
width: 84px
height: 84px
background-color: rgba(58,126,255,0.9)
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
color: #fff
font-size: 12px
text-align: center
padding: 10px
position: absolute
border-radius: 50%
box-shadow: 0 0 4px #999
box-sizing: border-box
&:hover
z-index: 1
background-color: rgba(240,65,52,.9)
color: #fff
div
display: flex
flex-wrap: wrap
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
justify-content: space-between
p
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
width: 100%
text-align: center
line-height: 16px
</style>
复制代码
el.style.left = pixel.x - 42 + 'px'
el.style.top = pixel.y - 42 + 'px'
是为了让气泡覆盖物正中心在其坐标点的位置,由于css的宽高均为84px,效果以下:
区域气泡显示以后,如今让咱们为他们增长点交互吧~ 就是鼠标滑入某个区域气泡的时候,该气泡高亮,滑出的时候恢复,一开始我用的是mouseover和mouseleave事件,让 zone-overlay 动态绑定class,可是我发现气泡背景色的变化没有缓动效果,
<zone-overlay
v-for="(item, index) in zoneGeoPoints" :key="index"
:position="{lng: item.lng, lat: item.lat}"
:text="item"
:class="zoneIndex === index ?'active':''"
@mouseover.native="selectZone(item, index)"
@mouseleave.native="cancelZone">
</zone-overlay>
<script>
export default {
data () {
return {
zoneIndex: ''
}
},
methods: {
selectZone (item, index) {
this.zoneIndex = index
},
cancelZone () {
this.zoneIndex = ''
}
}
}
</script>
复制代码
修饰符native是为了让组件变成普通html标签,否则不会触发mouseover和mouseleave事件,效果以下:
// zoneOverlay.vue
.zone
transition: background-color 1s ease-in-out
&:hover
z-index: 1
background-color: rgba(240,65,52,.9)
color: #fff
复制代码
效果以下:
咱们但愿当地图的缩放等级大于某一个值时,区域气泡消失,而小于该值时,区域气泡又出现,就像链家同样,在这个过程当中咱们就要实时获取地图当前的缩放等级 zoom,vue-baidu-map 给咱们提供了一个api syncCenterAndZoom,具体使用以下:
<div class="map-wrapper">
<baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" @ready="handler" @zoomend="syncCenterAndZoom">
<div v-if="showZone">
<zone-overlay
v-for="(item, index) in zoneGeoPoints" :key="index"
:position="{lng: item.lng, lat: item.lat}"
:text="item">
</zone-overlay>
</div>
</baidu-map>
</div>
复制代码
// 双向绑定 zoom
// ZOOMBOUNDARY 为常量,表示区域气泡消失或显示的 zoom 临界值
// const ZOOMBOUNDARY = 15
syncCenterAndZoom (e) {
this.zoom = e.target.getZoom()
this.showZone = this.zoom < ZOOMBOUNDARY
}
复制代码
效果以下:
区域边界用到的是 bm-boundary 组件,当鼠标划入某个区域气泡时,该区域的边界出现,而当鼠标滑出某个区域气泡时,该区域的边界消失,
<bm-boundary v-if="showBoundary" :name="zoneBoundary" :strokeWeight="2" strokeColor="blue" fillColor="skyblue" :fillOpacity="0.4"></bm-boundary>
复制代码
参数说明:
name 表示区域(行政区)的名字,例如上海市黄浦区,北京市朝阳区
strokeWeight 表示区域边界的边框宽度
strokeColor 表示区域边界的边框颜色
fillColor 表示区域边界的填充颜色
fillOpacity 表示区域边界的填充颜色透明度
<template>
<div class="map-wrapper">
<baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" @ready="handler" @zoomend="syncCenterAndZoom">
<bm-boundary v-if="showBoundary" :name="zoneBoundary" :strokeWeight="2" strokeColor="blue" fillColor="skyblue" :fillOpacity="0.4"></bm-boundary>
<div v-if="showZone">
<zone-overlay
v-for="(item, index) in zoneGeoPoints" :key="index"
:position="{lng: item.lng, lat: item.lat}"
:text="item"
@mouseover.native="selectZone(item, index)"
@mouseleave.native="cancelZone">
</zone-overlay>
</div>
</baidu-map>
</div>
</template>
<script>
export default {
data () {
return {
showBoundary: false
}
},
methods: {
selectZone (item, index) {
this.zoneBoundary = `${this.posCity}${item.name}` // 行政区名字,只供参考
this.showBoundary = true
},
cancelZone () {
this.zoneBoundary = ''
this.showBoundary = false
}
}
}
</script>
复制代码
效果以下:
因为地图找房的功能稍微复杂,因此我将其分为几个部分,这样也可以更清楚如何一步步实现此功能,至于后续部分还请你们慢慢等待啦~
最后在贴一次项目体验地址: 猛戳我体验~(仅支持pc端)
写得很差的地方请轻喷~感谢阅读