前端利用百度開發文檔給的web服務接口實現對某個區域周邊配套的檢索

  最近項目須要實現地圖功能,以便於實現對房源周邊配套設施的檢索。內容以下css

 

  其實百度官方有對應的api,可是對於一個網站來講這樣的樣式不免有些難看html

 

  這樣的結果顯然不能知足當下的需求,因此我決定利用官方給的web服務接口加上覆蓋物實現對應的效果。前端

  因爲咱們用的vue框架,因此我採用了基於百度地圖封裝的插件:vue-baidu-map 實現,對應版本號是:0.21.18,項目安裝依賴以下:vue

npm install vue-baidu-map --save

而後在main.js中注入依賴便可:web

import BaiduMap from 'vue-baidu-map'
Vue.use(BaiduMap, {
  ak: '申請的百度祕鑰'
})

這裏的ak須要去官方申請祕鑰,地址在這裏須要注意的是,申請完成以後會給你兩個祕鑰,咱們須要給調起服務主機的ip加到白名單裏,否則會有訪問權限錯誤,因爲如今是開發環境,因此我設置的是通配符*,也就是全部的主機,可是正是環境就不推薦這麼作了,緣由是前端代碼容易泄露AK,被其餘網站非法調用。npm

打開控制檯,步驟以下:json

 

 

白名單設置好之後,就能開始調用web服務了;api

首先要注意一個問題,因爲同源策略,咱們直接調用百度官方的接口會出現跨域問題,關於什麼是跨域,這裏很少解釋。那麼前端處理跨域最理想的方案是jsonp,也就是利用script天生的優點(他能夠動態獲取src屬性),那麼vue項目不一樣於傳統html,因此這裏我用到了一個插件,也就是vue-jsonp,他是一個基於promise封裝的請求庫,使用方法也很簡單,具體以下:跨域

首先是安裝:數組

npm install vue-jsonp --save

安裝完成以後注入要vue實例中:

import jsonp from "vue-jsonp"
Vue.use(jsonp)

使用起來也很方便:

this.$jsonp('url',params).then(()=> {
   // 成功以後的回調    
}).catch(() => {
 // 失敗以後的回調    
})

下面就正是開始搭建地圖了,首先開始寫地圖容器,按照vue-baidu-map官方的方法構建便可,注意要開啓滾輪操做,還要設置地圖展開的深度zoom

<template>
    <div class="map-plus">
        <!-- 地圖容器 -->
        <baidu-map
            class="baidu-map"
            id="map"
            :double-click-zoom="false"
            :min-zoom="10"
            :max-zoom="18"
            :scroll-wheel-zoom="true"
            :center="center"
            :zoom="zoom"
            @ready="handler">
        </baidu-map>
    </div>
</template>
<script>
export default {
  methods: {
    // 地圖組件渲染完畢時觸發
    handler({ BMap, map }) {
      this.center.lng = 118.186882019043;
      this.center.lat = 39.63203811645508;
      this.zoom = 16;
    }
  }
};
</script>

<style lang="scss">
.map-plus {
  position: relative;
}
#map {
  width: 1100px;
  height: 508px;
  margin-top: 200px;
  margin-left: 50px;  
}

</style>

 

 

 

這裏我想主要說一下覆蓋物的封裝:

首先因爲左右是一個聯動的過程,這裏個人思路是按照索引,也就是設置一個激活的索引,若是和當前點擊的索引同樣的話實現激活效果,還有一點體驗性的問題,因爲我想點擊某個漂浮物的時候讓該漂浮物回到地圖中間,因此每次點擊我根據百度服務給的經緯度賦值給當前地圖的中心,覆蓋物的封裝以下:

<template>
  <bm-overlay
    ref="customOverlay"
    class="happy-layer"
    pane="labelPane"
    @draw="draw">
    <div class="content" 
         :class="{active: busActiveIndex == title+1}"
         @click="handleClick">
        {{title+1}}
    </div>
  </bm-overlay>
</template>

<script>
export default {
  props: [
    // 位置
    'position', 
    // 是否激活
    'active',
    // 內容
    'title',
    // 激活的索引
    'busActiveIndex'
  ],
  watch: {
    position: {
      handler () {
        this.$refs.customOverlay.reload()
      },
      deep: true
    }
  },
  methods: {
    handleClick () {
      this.$emit('change',this.title)
    },
    draw ({el, BMap, map}) {
      const {lng, lat} = this.position
      const pixel = map.pointToOverlayPixel(new BMap.Point(lng, lat))
      el.style.left = pixel.x - 60 + 'px'
      el.style.top = pixel.y - 20 + 'px'
    }
  }
}
</script>

<style lang="scss">
.happy-layer {
    position: absolute;
    z-index: 99;
    &:hover {
        z-index: 999;
    }
}
    .content {
        padding: 10px 15px;
        font-size: 14px;
        color: #fff;
        background-color: #00c170;
        cursor: pointer;
        border-radius: 5px;
        &:hover {
            background-color: red;
        }
    }
.active {
    background-color: red;
}
</style>

調用他就比較簡單了,只要把從服務端拿到的結果遍歷一下綁定到組件上就好了

 <happy-layer v-for="(item,index) in layerList" :key=index
                     :position="{lng: item.location.lng , lat: item.location.lat}"
                     :title=index
                     :busActiveIndex="busActiveIndex"
                     @change="overLayClick"></happy-layer>

 

關於獲取周邊配套,我用到兩個方法,一個負責接收參數調用服務,另外一個負責獲取數據

 // 獲取周邊接口
    getRound: function (key) {
        let ak = "F7XhtYsBvOZeQUbrmCCuy0KGNVCZApB8";
        return this.$jsonp(`http://api.map.baidu.com/place/v2/search?query=${key}&location=39.63203811645508,118.186882019043&radius=2000&output=json&ak=${ak}`)
    },
    // 獲取周邊信息
    getMsg: function(a) {
      this.getRound(a).then(res => {
        this.layerList = []
        res.results.forEach(el => el.location && this.layerList.push(el));
      });
    },

最後就剩下列表的搭建了,這個就不說了,直接上源碼吧:

 

地圖容器父組件:

<template>
    <div class="map-plus">
        <!-- 地圖容器 -->
        <baidu-map
            class="baidu-map"
            id="map"
            :double-click-zoom="false"
            :min-zoom="10"
            :max-zoom="18"
            :scroll-wheel-zoom="true"
            :center="center"
            :zoom="zoom"
            @ready="handler">
            <!-- 覆蓋物組件 -->
            <happy-layer v-for="(item,index) in layerList" :key=index
                     :position="{lng: item.location.lng , lat: item.location.lat}"
                     :title=index
                     :busActiveIndex="busActiveIndex"
                     @change="overLayClick"></happy-layer>
        </baidu-map>
        <!-- 右側搜索 -->
        <div class="search-wrap">
            <!-- 標籤 -->
            <div class="tags">
                <div class="tag_item"
                     :class="{'tag-active': activeIndex == index}"
                     v-for="(item,index) in tagsArr"
                     :key="index"
                     @click="tagsClick(index,item)">{{item.name}}</div>
            </div>
            <!-- 列表 -->
            <div class="list">
                <div class="list-top" 
                        v-for="(bus,indexs) in layerList" 
                        :key="indexs"  
                        @click="chooseListItem(bus,indexs)">
                    <div class="title"
                            :class="{'active-bus': busActiveIndex == indexs+1}">
                        <span class="indexs">{{indexs+1}}</span>
                        <span>{{bus.name}}</span>
                    </div>
                    <div class="bus-num">
                        {{bus.address}}
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
  data() {
    return {
        active: false,
      // 左邊中心
      center: { lng: 0, lat: 0 },
      // 深度
      zoom: 3,
    //   標籤激活索引
      activeIndex: 0,
    //   漂浮物激活索引
      busActiveIndex:1,
    //   數據結果
      layerList: [],
    //   標籤數組
      tagsArr: [
        {
          name: "公交"
        },
        {
          name: "教育"
        },
        {
          name: "醫療"
        },
        {
          name: "購物"
        },
        {
          name: "生活"
        },
        {
          name: "娛樂"
        }
      ]
    };
  },
  mounted() {
      this.getMsg('公交');
    
  },
  methods: {
    // 地圖組件渲染完畢時觸發
    handler({ BMap, map }) {
      this.center.lng = 118.186882019043;
      this.center.lat = 39.63203811645508;
      this.zoom = 16;
    },
    // 標籤激活
    tagsClick: function(index, item) {
      this.activeIndex = index
      this.getMsg(item.name)
    },
    // 獲取周邊接口
    getRound: function (key) {
        let ak = 你申請的祕鑰;
        return this.$jsonp(`http://api.map.baidu.com/place/v2/search?query=${key}&location=39.63203811645508,118.186882019043&radius=2000&output=json&ak=${ak}`)
    },
    // 獲取周邊信息
    getMsg: function(a) {
      this.getRound(a).then(res => {
        this.layerList = []
        res.results.forEach(el => el.location && this.layerList.push(el));
      });
    },
    // 覆蓋物點擊激活
    overLayClick: function (num) {
        this.busActiveIndex = num + 1

    },
    // 選擇列表某一項
    chooseListItem: function (bus,indexs) {
        this.busActiveIndex = indexs+1
        this.center = bus.location
    }
  }
};
</script>

<style lang="scss">
.map-plus {
  position: relative;
}
#map {
  width: 1100px;
  height: 508px;
  margin-top: 200px;
  margin-left: 50px;
}
.search-wrap {
  width: 393px;
  height: 460px;
  border: 1px solid #eee;
  background-color: #fff;
  position: absolute;
  left: 736px;
  top: 220px;
  box-shadow: 0 0 10px #ccc;
  border-top: 3px solid #1fb19e;

  .list {
      height: 400px;
      overflow-y: scroll;

      .list-top {
          color: #333;
          padding: 20px 20px 10px 20px;
          cursor: pointer;

          .indexs {
              padding: 2px 6px;
              font-size: 12px;
              border-radius: 50%;
              background-color: #00c170;
              color: #fff;
          }

          &:hover {
              color: #00c170;
          }
          .bus-num {
            font-size: 14px;
            margin: 5px 0 0 24px;
            color: #9c9fa1;
            line-height: 18px;
        }
      }
      
  }
  .active-bus {
          color: #00c170;
      }

  .tags {
    line-height: 45px;
    height: 45px;
    background-color: #f1f1f1;
    display: flex;
    justify-content: space-between;

    .tag_item {
      width: 66px;
      text-align: center;
      cursor: pointer;
    }
    .tag-active {
      background-color: #fff;
    }
  }
}

</style>

 

覆蓋物子組件:

<template>
  <bm-overlay
    ref="customOverlay"
    class="happy-layer"
    pane="labelPane"
    @draw="draw">
    <div class="content" 
         :class="{active: busActiveIndex == title+1}"
         @click="handleClick">
        {{title+1}}
    </div>
  </bm-overlay>
</template>

<script>
export default {
  props: [
    // 位置
    'position', 
    // 是否激活
    'active',
    // 內容
    'title',
    // 激活的索引
    'busActiveIndex'
  ],
  watch: {
    position: {
      handler () {
        this.$refs.customOverlay.reload()
      },
      deep: true
    }
  },
  methods: {
    handleClick () {
      this.$emit('change',this.title)
    },
    draw ({el, BMap, map}) {
      const {lng, lat} = this.position
      const pixel = map.pointToOverlayPixel(new BMap.Point(lng, lat))
      el.style.left = pixel.x - 60 + 'px'
      el.style.top = pixel.y - 20 + 'px'
    }
  }
}
</script>

<style lang="scss">
.happy-layer {
    position: absolute;
    z-index: 99;
    &:hover {
        z-index: 999;
    }
}
    .content {
        padding: 10px 15px;
        font-size: 14px;
        color: #fff;
        background-color: #00c170;
        cursor: pointer;
        border-radius: 5px;
        &:hover {
            background-color: red;
        }
    }
.active {
    background-color: red;
}
</style>
相關文章
相關標籤/搜索