全網稀缺,完整鏈家地圖找房的實現(一)

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

爲了增長緩動效果,後來我換用了css的hover僞類,取消鼠標事件,爲了讓你們看的清晰點,這裏我設置了1s的緩動時間,

// 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端)

寫得很差的地方請輕噴~感謝閱讀

相關文章
相關標籤/搜索