前一段時間我應公司的需求開發了相似鏈家地圖找房的功能,然而我發現如今市面上,對於鏈家地圖找房功能的完整實現相關的文章仍是比較稀缺的,亦或是功能還不夠完善,出於這個方面,我以爲把本身對於鏈家地圖找房功能的完整實現分享出來仍是頗有必要的,包括其中的畫圈找房,以及如何將整個地圖找房拆分紅一個個組件。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端)
寫得很差的地方請輕噴~感謝閱讀