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

全網稀缺,完整鏈家地圖找房的實現(一)章節中,咱們已經實現了地圖找房中地圖的初始化、區域氣泡和區域邊界的顯示及交互,那麼在本文中咱們要作的就是地圖周邊房源的顯示及交互。css

項目已上線,猛戳我體驗~html

周邊房源的顯示

對於周邊房源的顯示邏輯大體以下,vue

  • 用戶點擊某個區域氣泡,地圖縮放層級增大(此時地圖的 zoom 更新爲區域氣泡消失的臨界值 ZOOMBOUNDARY 加1,this.zoom = ZOOMBOUNDARY + 1),此時周邊房源氣泡和周邊房源總數提示(dataToast)出現,區域氣泡和區域邊界消失 vuex

    效果演示圖

  • 用戶放大地圖,當縮放層級大於臨界值的時候,同上;小於臨界值的時候區域氣泡出現,周邊房源和周邊房源總數提示消失 後端

    效果演示圖

  • 在地圖縮放層級大於臨界值時,用戶拖動地圖,拖動結束後更新周邊房源(也就是發送 get請求,參數須要和後端同窗溝通好,我這裏是經過地圖當前的中心點座標查詢) 數組

    效果演示圖
    在分析完周邊房源顯示的場景以後,咱們就分爲三步來逐步實現。

step1 -- 用戶點擊某個區域氣泡

首先咱們須要抽象一個周邊房源組件 -- 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>
複製代碼

step2 -- 用戶縮放地圖

在這個過程當中咱們須要雙向綁定地圖的縮放層級更新 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
  }
}
複製代碼

step3 -- 用戶移動地圖

這個過程須要雙向綁定地圖當前經緯度,並根據經緯度更新周邊房源

<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)
  }
}
複製代碼

周邊房源的交互

css :hover僞類

同區域氣泡同樣,當鼠標滑入某個周邊房源時,該氣泡高亮,鼠標滑出時,該氣泡恢復,因爲氣泡的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

咱們但願不只要在鼠標滑入某個周邊房源氣泡時,該氣泡高亮,並且但願鼠標點擊也一樣高亮,這裏就要用到 @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

最後就是房源詳情氣泡了,相似於一張卡片,展現房源的信息,抽象 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
  })
}
複製代碼

如今咱們已經實現了區域氣泡、區域邊界、周邊房源及其詳情、周邊房源數量提示的展現和交互,效果以下

最後就剩下畫圈找房還沒實現了,感謝閱讀,to be continued~
相關文章
相關標籤/搜索