全网稀缺,完整链家地图找房的实现(二)

栏目: CSS · 发布时间: 6年前

内容简介:在对于周边房源的显示逻辑大致如下,

全网稀缺,完整链家地图找房的实现(一) 章节中,我们已经实现了地图找房中地图的初始化、区域气泡和区域边界的显示及交互,那么在本文中我们要做的就是地图周边房源的显示及交互。

项目已上线,猛戳我体验~

周边房源的显示

对于周边房源的显示逻辑大致如下,

  • 用户点击某个区域气泡,地图缩放层级增大(此时地图的 zoom 更新为区域气泡消失的临界值 ZOOMBOUNDARY 加1,this.zoom = ZOOMBOUNDARY + 1),此时周边房源气泡和周边房源总数提示(dataToast)出现,区域气泡和区域边界消失

    全网稀缺,完整链家地图找房的实现(二)
  • 用户放大地图,当缩放层级大于临界值的时候,同上;小于临界值的时候区域气泡出现,周边房源和周边房源总数提示消失

    全网稀缺,完整链家地图找房的实现(二)
  • 在地图缩放层级大于临界值时,用户拖动地图,拖动结束后更新周边房源(也就是发送 get请求,参数需要和后端同学沟通好,我这里是通过地图当前的中心点坐标查询)

    全网稀缺,完整链家地图找房的实现(二)

    在分析完周边房源显示的场景之后,我们就分为三步来逐步实现。

step1 -- 用户点击某个区域气泡

首先我们需要抽象一个周边房源组件 -- aroundOverlay,该组件和区域气泡组件(zoneOverlay)差不多,样式和内容稍作修改即可,

<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>
复制代码

以及周边房源提示组件 -- dataToast

<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 组件,

<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,最后发送请求获取周边房源数据,

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~


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Design Accessible Web Sites

Design Accessible Web Sites

Jeremy Sydik / Pragmatic Bookshelf / 2007-11-05 / USD 34.95

It's not a one-browser web anymore. You need to reach audiences that use cell phones, PDAs, game consoles, or other "alternative" browsers, as well as users with disabilities. Legal requirements for a......一起来看看 《Design Accessible Web Sites》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

MD5 加密
MD5 加密

MD5 加密工具

SHA 加密
SHA 加密

SHA 加密工具