在全網稀缺,完整鏈家地圖找房的實現(一)章節中,咱們已經實現了地圖找房中地圖的初始化、區域氣泡和區域邊界的顯示及交互,那麼在本文中咱們要作的就是地圖周邊房源的顯示及交互。css
項目已上線,猛戳我體驗~html
對於周邊房源的顯示邏輯大體以下,vue
用戶點擊某個區域氣泡,地圖縮放層級增大(此時地圖的 zoom 更新爲區域氣泡消失的臨界值 ZOOMBOUNDARY 加1,this.zoom = ZOOMBOUNDARY + 1),此時周邊房源氣泡和周邊房源總數提示(dataToast)出現,區域氣泡和區域邊界消失 vuex
用戶放大地圖,當縮放層級大於臨界值的時候,同上;小於臨界值的時候區域氣泡出現,周邊房源和周邊房源總數提示消失 後端
在地圖縮放層級大於臨界值時,用戶拖動地圖,拖動結束後更新周邊房源(也就是發送 get請求,參數須要和後端同窗溝通好,我這裏是經過地圖當前的中心點座標查詢) 數組
首先咱們須要抽象一個周邊房源組件 -- aroundOverlay,該組件和區域氣泡組件(zoneOverlay)差很少,樣式和內容稍做修改便可,bash
<template>
<bm-overlay
ref="customOverlay"
class="around"
pane="labelPane"
@draw="draw">
<div>
<!-- div中的內容可本身調整 -->
<p>{{text.title}}</p>
<p>{{Math.ceil(text.initialPrice / 10000)}}萬</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 - 61 + 'px'
el.style.top = pixel.y - 18 + 'px'
}
}
}
</script>
<style lang="stylus" scoped>
.around
overflow: hidden
width: 122px
height: 36px
padding: 5px
box-shadow: 0 0 1px #bbb
background-color: rgba(58,126,255,0.9)
color: #fff
text-align: center
position: absolute
font-size: 12px
line-height: 13px
border-radius: 5px
box-sizing: border-box
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
</style>
複製代碼
以及周邊房源提示組件 -- dataToastapp
<template>
<div class="toast">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'dataToast'
}
</script>
<style lang="scss" scoped>
.toast{
position: fixed;
left: 0;
right: 0;
bottom: 20px;
width: 340px;
height: 26px;
margin: auto;
padding: 3px 10px;
background-color: rgba(0,0,0,.7);
color: #fff;
font-size: 12px;
line-height: 20px;
box-sizing: border-box;
}
</style>
複製代碼
在地圖容器中使用 aroundOverlay 組件,ide
<baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" :inertial-dragging="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"
@click.native="selZone(item, index)">
</zone-overlay>
</div>
<div v-if="!showZone">
<around-overlay
v-for="(item, index) in aroundGeoPoints" :key="index"
:position="{lng: item.lng, lat: item.lat}"
:text="item">
</around-overlay>
</div>
</baidu-map>
複製代碼
用戶點擊某個區域氣泡,也就是對應的selZine事件,此時區域氣泡和區域邊界消失,而周邊房源出現,設置地圖縮放層級 zoom爲臨界值ZOOMBOUNDARY加1,而且設置地圖中心點的經緯度 center,最後發送請求獲取周邊房源數據,wordpress
selZone (item, index) {
this.showZone = false
this.$set(this.center, 'lng', item.lng)
this.$set(this.center, 'lat', item.lat)
this.zoneBoundary = ''
this.showBoundary = false
this.zoom = ZOOMBOUNDARY + 1
// updateHouseList 獲取周邊房源,使用vuex存儲部分數據,這裏須要本身設計
this.updateHouseList(item.lng, item.lat)
},
複製代碼
對於 dataToast 組件,我是放在地圖容器外面,這裏須要把和地圖相關的部分放在一個組件裏(我抽象成了 searchMap 組件),而後和其餘的內容放在一個容器div裏面,
<div>
<searchMap></searchMap>
<!-- 在上面的updateHouseList方法中將縮放層級存儲在vuex中,消失和顯示與周邊房源組件同步,aroundCnt對應周邊房源總數 -->
<dataToast v-if="this.$store.state.showAround > ZOOMBOUNDARY ">視野內共有{{aroundCnt}}個房源,拖動地圖查看更多~</dataToast>
</div>
複製代碼
searchMap 組件
<div>
<!-- 把以前的baidu-map搬過來就好了,下面是簡寫 -->
<baidu-map></baidu-map>
</div>
複製代碼
在這個過程當中咱們須要雙向綁定地圖的縮放層級更新 zoom,而且獲取當前經緯度,再比較 zoom 和臨界值 ZOOMBOUNDARY 顯示和隱藏周邊房源氣泡,對 @zoomend="syncCenterAndZoom" 做以下修改
syncCenterAndZoom (e) {
this.zoom = e.target.getZoom() // 更新 zoom
if (this.zoom > ZOOMBOUNDARY) {
this.showZone = false
// 獲取周邊房源數據,僅供參考
const {lng, lat} = e.target.getCenter()
this.updateHouseList(lng, lat)
} else {
this.showZone = true
}
}
複製代碼
這個過程須要雙向綁定地圖當前經緯度,並根據經緯度更新周邊房源
<baidu-map id="bm-view" class="bm-view" :center="center" :zoom="zoom" :scroll-wheel-zoom="true" :inertial-dragging="true" @ready="handler" @zoomend="syncCenterAndZoom" @moveend="syncCenterAndZoom_"></baidu-map>
複製代碼
@moveend="syncCenterAndZoom_" 表示在地圖移動結束時觸發 syncCenterAndZoom_,咱們在此方法中雙向當前的綁定經緯度
syncCenterAndZoom_ (e) {
const zoom = e.target.getZoom()
if (zoom > ZOOMBOUNDARY) {
// 更新周邊房源數據,僅供參考
const {lng, lat} = e.target.getCenter()
this.updateHouseList(lng, lat)
}
}
複製代碼
同區域氣泡同樣,當鼠標滑入某個周邊房源時,該氣泡高亮,鼠標滑出時,該氣泡恢復,因爲氣泡的onmouseover 和 onmouseleave 沒有緩動效果,因此換用css的hover僞類,修改 aroundOverlay 的stylus
.around
transition: background-color .15s ease-in-out /* 緩動效果,可本身調整 */
overflow: hidden
width: 122px
height: 36px
padding: 5px
box-shadow: 0 0 1px #bbb
background-color: rgba(58,126,255,0.9)
color: #fff
text-align: center
position: absolute
font-size: 12px
line-height: 13px
border-radius: 5px
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
/* .active是動態的類名,在後面的鼠標點擊事件會用到,主要用於高亮顯示 */
.around.active
z-index: 1
background-color: rgba(240,65,52,.9)
color: #fff
複製代碼
氣泡 hover 時 z-index 爲1是爲了讓高亮的氣泡不會被其餘氣泡遮蓋住,由於層疊上下文的緣由,因此只需設置 z-index 爲1便可,若是還不知道層疊上下文的話,能夠去看張鑫旭老師的深刻理解CSS中的層疊上下文和層疊順序
咱們但願不只要在鼠標滑入某個周邊房源氣泡時,該氣泡高亮,並且但願鼠標點擊也一樣高亮,這裏就要用到 @click.native (native是修飾符,會把組件當成普通的html標籤),動態綁定一個類名,做以下修改
<div v-if="!showZone && this.$store.state.toggleAround">
<around-overlay
v-for="(item, index) in aroundGeoPoints" :key="index"
v-show="!item.isShow"
:class="curAround === item.id?'active':''"
:position="{lng: item.lng, lat: item.lat}"
:text="item"
@click.native="selAround(item, index)">
</around-overlay>
</div>
selAround (item, index) {
this.curAround = item.id
}
複製代碼
這裏我踩了一個坑,一開始我是根據 index 來動態綁定類名,
:class="curAround === index?'active':''"
selAround (item, index) {
this.curAround = index
}
複製代碼
這樣是不行的,由於數組 aroundGeoPoints 更新以後(拖動地圖結束後發送請求更新周邊房源),會出現原來在 aroundGeoPoints 下標爲5的元素下標變成了8,原來下標爲5的元素是高亮的,數組更新以後就不高亮了,由於他的下標變成了8,所以換成了根據元素的 id(從後臺獲取) 來綁定類名,由於元素的 id 是惟一的。
最後就是房源詳情氣泡了,相似於一張卡片,展現房源的信息,抽象 detailOverlay 組件
<template>
<bm-overlay
ref="customOverlay"
class="detail"
pane="labelPane"
@draw="draw">
<slot></slot>
</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 - 200 + 'px'
el.style.top = pixel.y - 180 + 'px' // 詳情氣泡底端距房源氣泡頂端的距離,可本身調整
}
}
}
</script>
<style lang="stylus" scoped>
.detail
z-index: 9
transition: background-color .15s ease-in-out
width: 400px
height: 140px
padding: 20px
box-shadow: 0 0 10px #bbb
background-color: #fff
color: #fff
text-align: center
position: absolute
font-size: 12px
line-height: 13px
border-radius: 5px
box-sizing: border-box
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
&:after
content: ''
display: block
position: absolute
left: 50%
bottom: -20px
width: 0
height: 0
margin-left: -10px
border: 10px solid transparent
border-top-color: #fff
</style>
複製代碼
在 baidu-map 中使用
<baidu-map>
<div v-if="toggleDetail">
<detail-overlay
:detailGeo="detailGeo"
:position="{lng: detailGeo.lng, lat: detailGeo.lat}">
<!-- info-wrapper 中的內容須要本身替換,僅供參考 -->
<div class="info-wrapper" v-if="toggleDetail">
<div class="img">
<img :src="detailGeo.pic_url" alt="房源圖片">
</div>
<div class="info">
<h4 class="title">{{detailGeo.title}}</h4>
<div class="price">
<div>
<p>當前價</p>
<p>{{parseInt(detailGeo.currentPrice / 100) / 100}}萬</p>
</div>
<div>
<p>法院評估價</p>
<p>{{parseInt(detailGeo.consultPrice / 100) / 100}}萬</p>
</div>
<div>
<p>市場評估價</p>
<p>{{parseInt(detailGeo.marketPrice / 100) / 100}}萬</p>
</div>
</div>
</div>
</div>
</detail-overlay>
</div>
</baidu-map>
複製代碼
當鼠標滑入房源氣泡時,詳情氣泡出現,鼠標滑出時,詳情氣泡消失,因此在 aroundOverlay 組件加上 onmouseover 和 onmouseleave
<around-overlay
v-for="(item, index) in aroundGeoPoints" :key="index"
v-show="!item.isShow"
:class="curAround === item.id?'active':''"
:position="{lng: item.lng, lat: item.lat}"
:text="item"
@click.native="selAround(item, index)"
@mouseover.native="showCurInfo(item, index)"
@mouseleave.native="hideCurInfo">
</around-overlay>
// 下面我作了防抖處理, deBounce 是引入的防抖函數
showCurInfo (item, index) {
this.infoPromise = new Promise(resolve => {
deBounce(() => {
this.detailGeo = item
this.toggleDetail = true
resolve()
})
})
return this.infoPromise
},
hideCurInfo () {
this.infoPromise.then(() => {
this.toggleDetail = false
})
}
複製代碼
如今咱們已經實現了區域氣泡、區域邊界、周邊房源及其詳情、周邊房源數量提示的展現和交互,效果以下