内容简介:在对于周边房源的显示逻辑大致如下,
在 全网稀缺,完整链家地图找房的实现(一) 章节中,我们已经实现了地图找房中地图的初始化、区域气泡和区域边界的显示及交互,那么在本文中我们要做的就是地图周边房源的显示及交互。
周边房源的显示
对于周边房源的显示逻辑大致如下,
-
用户点击某个区域气泡,地图缩放层级增大(此时地图的 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~
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 动态路由实现OSPF和RIP协议实现全网互连互通
- 看我如何在赛门铁克邮件安全网关上实现弱口令到RCE漏洞执行
- 全网最全 Dalvik 指令集解析 !
- 全网最全 | MySQL EXPLAIN 完全解读
- 全网最全Flutter常用工具类
- 全网最通透的 Java 8 版本特性讲解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML 编码/解码
HTML 编码/解码
XML 在线格式化
在线 XML 格式化压缩工具