In the whole network scarce, complete chain home map house search implementation (A) chapter, we have achieved the map in the map house search initialization, regional bubbles and regional boundary display and interaction, so in this paper we need to do is the map around the house source display and interaction.

The project has been online, I am experiencing ~

Display of surrounding properties

The display logic of surrounding houses is roughly as follows:

  • The user clicks a regional bubble, and the map zooming level increases (at this time, the map’s zoom is updated to the critical value ZOOMBOUNDARY of the disappearance of regional bubbles + 1, this.zoom = ZOOMBOUNDARY + 1). At this time, surrounding house bubbles and dataToast prompt appear, while regional bubbles and regional boundaries disappear

  • When the user enlarges the map, when the zoom level is greater than the critical value, the same as above; When the value is less than the critical value, regional bubbles appear, and the total number of surrounding houses and surrounding houses disappear

  • When the scale level of the map is greater than the critical value, the user drags the map and updates the surrounding houses after dragging (that is, send get request, parameters need to be well communicated with the students at the back end, here I query by the coordinates of the current center point of the map).

    After analyzing the scene displayed by the surrounding houses, we divided it into three steps to realize it step by step.

Step1 — The user clicks on a region bubble

AroundOverlay first we need to abstract a surrounding house component — aroundOverlay. This component is similar to the zoneOverlay, with a few changes in style and content.

<template>
  <bm-overlay
    ref="customOverlay"
    class="around"
    pane="labelPane"
    @draw="draw"> <div> <! - the contents of the div can adjust themselves - > < p > {{text. The title}} < / p > < p > {{math.h ceil (10000). The text initialPrice /}} m < / 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, 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 #bbbBackground - color: rgba (58126255,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>
Copy the code

And dataToast, a nearby listing notification component

<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, 7); color:#fff;
    font-size: 12px;
    line-height: 20px;
    box-sizing: border-box;
  }
</style>
Copy the code

AroundOverlay using aroundOverlay in the map container

<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>
Copy the code

The user clicks a regional bubble, which is the corresponding selZine event, at which time the regional bubble and regional boundary disappear, while the surrounding houses appear. Set the map zoom level ZOOM to the critical value ZOOMBOUNDARY plus 1, and set the longitude and latitude center of the central point of the map. Finally, send a request to obtain the data of surrounding houses.

selZone (item, index) {
  this.showZone = false
  this.$set(this.center, 'lng', item.lng)
  this.$set(this.center, 'lat', item.lat)
  this.zoneBoundary = ' '
  this.showBoundary = falseThis.zoom = ZOOMBOUNDARY + 1 // updateHouseList(item.lng, item.lat)}Copy the code

For the dataToast component, which I put outside the map container, I need to put the map-related part in a component (which I abstracted into the searchMap component) and put it in a container div with the rest of the content.

<div> <searchMap></searchMap> <! -- Store the zoom level in vuEX in the updateHouseList method above, disappear and display in sync with the surrounding house components, aroundCnt corresponds to the total number of surrounding houses --> <dataToast V-if ="this.$store.state.showAround > ZOOMBOUNDARY "> there are {{aroundCnt}} houses in the view, drag the map to see more ~ </dataToast> </div>Copy the code

SearchMap components

<div> <! <baidu-map></baidu-map> </div>Copy the code

Step2 — The user scales the map

In this process, we need to update the zoom level of the bidirectional binding map, and obtain the current longitude and latitude, and then compare zoom and critical ZOOMBOUNDARY to display and hide the bubbles of surrounding houses, and make the following modifications to @zoomend=”syncCenterAndZoom”

SyncCenterAndZoom (e) {this.zoom = e.targe.getzoom () // Update zoomif (this.zoom > ZOOMBOUNDARY) {
    this.showZone = falseConst {LNG, lat} = e.targe.getCenter () this.updateHouselist (LNG, lat)} const {LNG, lat} = e.targe.getCenter () this.updateHouselist (LNG, lat)}else {
    this.showZone = true}}Copy the code

Step3 — the user moves the map

This process requires bidirectional binding of the map’s current latitude and longitude and updating of surrounding properties based on the latitude and longitude

<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>
Copy the code

@moveEnd =”syncCenterAndZoom_” means that syncCenterAndZoom_ is triggered at the end of the map move. In this method, we bidirectional the current binding latitude and longitude

syncCenterAndZoom_ (e) {
  const zoom = e.target.getZoom()
  if(zoom > ZOOMBOUNDARY) {const {LNG, lat} = e.target.getCenter() this.updateHouselist (LNG, Lat)}}Copy the code

Interaction of surrounding houses

CSS: hover pseudo class

As with the area bubble, the bubble highlights when the mouse slides into a nearby house and recovers when the mouse slides out. Since the bubble’s OnMouseover and Onmouseleave have no easing effect, change the HOVER artifact with CSS to modify the Stylus with aroundOverlay

.around
    transition: background-color .15s ease-in-out /* 缓动效果,可自己调整 */
    overflow: hidden
    width: 122px
    height: 36px
    padding: 5px
    box-shadow: 0 0 1px #bbbBackground - color: rgba (58126255,0.9) color:#ffftext-align: center position: absolute font-size: 12px line-height: 13px border-radius: 5px box-sizing: Hover z-index: 1; border-box &:hover z-index: 1; background-color: rgba(240,655,52,.9) color:#fffdiv 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: */.around. Active z-index: 1 background-color: rgba(240,65,52,.9) color: rgba(240,65,52,.9)#fff
Copy the code

Bubble hover z-index is 1 in order to make the highlighted bubble will not be covered by other bubbles, because of the reason of the cascading context, so just set z-index to 1, if you do not know the cascading context, you can go to see Zhang Xinxu teacher’s in-depth understanding of CSS cascading context and cascading order

Mouse click event @click.native

We want a nearby property bubble to be highlighted not only when the mouse slides over it, but also when the mouse clicks on it, using @click.native (native is a modifier that makes a component look like a normal HTML tag) to dynamically bind a class name and make the following changes

<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
}
Copy the code

So I’ve got a little bit of a loophole here, because I started by dynamically binding the class name to index,

:class="curAround === index? 'active':''"

selAround (item, index) {
  this.curAround = index
}
Copy the code

AroundGeoPoints: aroundGeoPoints: aroundGeoPoints: aroundGeoPoints: aroundGeoPoints: aroundGeoPoints: aroundGeoPoints: aroundGeoPoints: aroundGeoPoints: aroundGeoPoints: aroundGeoPoints Because its subscript is changed to 8, the class name is bound to the element ID (fetched from behind the scenes) instead, because the element ID is unique.

Listing Detail bubble — detailOverlay

Finally, there is the Listing Detail bubble, which acts like a card that presents the listing information, the abstract detailOverlay component

<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>
Copy the code

Used in Bidu-map

<baidu-map>
    <div v-if="toggleDetail">
        <detail-overlay
          :detailGeo="detailGeo"
          :position="{lng: detailGeo.lng, lat: detailGeo.lat}"> <! -- Info-wrapper contents need to be replaced by themselves, just for reference --> <div class="info-wrapper" v-if="toggleDetail">
            <div class="img">
              <img :src="detailGeo.pic_url" alt="Housing Picture">
            </div>
            <div class="info">
              <h4 class="title">{{detailGeo.title}}</h4>
              <div class="price"> < div > < p > the current price < / p > < p > {{parseInt (detailGeo. CurrentPrice / 100) / 100}} m < / p > < / div > < div > < p > court evaluating price < / p > <p>{{parseInt(detailGeo. ConsultPrice / 100) / 100}} 0000 </p> </div> <div> <p> Market appraisal </p> <p>{{parseInt(detailGeo. MarketPrice / 100) / 100}} < / p > < / div > < / div > < / div > < / div > < / detail - overlay > < / div > < / baidu - map >Copy the code

AroundOverlay add onMouseOver and OnMouseleave to the aroundOverlay component, the details bubble will appear when mouse is in the house bubble and disappear when mouse is out

<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> // now I do an overlay, deBounce is a function 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})}Copy the code

Now we have realized the display and interaction of regional bubbles, regional boundaries, surrounding houses and their details, and hints of the number of surrounding houses. The results are as follows