小程序定位地圖模塊全系列開發教學(超詳細)

前言:若是想最大化吸收本文經驗,須有小程序開發基礎,本文細節比較多(多看註釋的提醒內容),請耐心理解,多動手嘗試,收穫會更加豐富javascript

1.定位系統使用場景及概述

如美團外賣小程序
在這裏插入圖片描述
點定位
在這裏插入圖片描述
點搜索
在這裏插入圖片描述
顯而易見,隨便一個電商小程序都須要用到定位服務,那麼今天咱們作一個相似的定位模塊
定位模塊總覽
外部頁面
在這裏插入圖片描述
內部頁面(下文說的內外部頁面就是指這兩個)
在這裏插入圖片描述










java

好了接下來咱們開始動手git

2.定位外部模塊樣式

效果
在這裏插入圖片描述
代碼

小程序

//wxml
<view bindtap="getLocation" class="location">
  <image src="../../img/location.png"></image>
  <view>{ { location}}</view>
</view>
//wxss
.location{ 
  font-size: 17px;
  width: 100%;
  background:rgb(196, 228, 123);
  display: flex;
  /* 對於兩個塊元素 */
  /* 垂直居中 */
  align-items: center;
  /* 水平居中 */
  justify-content: center;
}
.location image{ 
  width: 23px;
  height: 23px;
}

先不用管上面的{ {location}},它是咱們以後要從全局變量傳過來的位置信息,定位符號是用image圖片放進去的,咱們用flex佈局讓圖片和文字在同一行居中顯示(見註釋)微信小程序

3.定位模塊內部樣式

效果
在這裏插入圖片描述
代碼(分五個小模塊,見註釋)

api

//wxml
//搜索模塊
<view class="header">
  <view class="search">
<image src="../../img/sousuo.png"></image>
  </view>
  <view class="input">
<input type="text" placeholder=" 請輸入你想要的內容" placeholder-class="placeholder" bindinput="bindInput" bindfocus="bindFocus" auto-focus="{ {autoFocus}}"></input>
  </view>
</view>
//定位模塊
<view class="dw">
<button size="mini" bindtap="getCity">
  <image src='../../img/location.png'></image>
  <text>定位</text>
 </button>
</view>
//當前位置模塊
<view >當前所在位置</view>
<button  size="mini" bindtap="nowCity" class='nowcity'>{ { city}}</button>
//熱門城市模塊
<view class="hotcity">熱門城市</view>
<view wx:for="{ {hotcity}}" wx:key='index' class="hotcity1">
  <!-- 用了view循環以後要把view設置爲inline元素,否則5個view會分紅5行顯示 -->
<button  size="mini" bindtap="hotCity" data-hotcityindex='{ {index}}'>{ { item.cityName}}</button>
</view>
//地圖模塊
<view class="map">
<map longitude="{ {longitude}}" latitude="{ {latitude}}" scale="14"></map>
</view>

因爲個人搜索框是用了自定義組件裏面的搜索組件,我是在組件的基礎上改出來的,原組件是這樣的在這裏插入圖片描述
咱們須要把搜索圖標隱藏,咱們直接設置它的透明度爲0,而後把咱們的定位文字跟圖標經過定位直接定位到搜索框的左邊,因此樣式的代碼以下(代碼太多很差找的話能夠Ctrl+F直接搜索)
數組

//wxss
.dw{ 
  color:rgb(0, 0, 0);
  position: absolute;
  top: 14px;
  left: -2px;
}
.dw button{ 
  background: white;
  padding-right: 0;
  display: flex;
  align-items: center;
  font-weight: 600 !important;
}
.nowcity{ 
  font-weight: normal;
}
.dw image{ 
  width: 23px;
  height: 23px;
}
page{ 
  padding: 10px;
}
.hotcity1 button{ 
  margin: 10px;
  margin-bottom: 0;
  font-weight: 500 !important;
    border-radius: 10px !important;
}
.hotcity{ 
  margin-top: 6px;
  
}
.map_container{ 
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
.header{ 
  display: flex;
}
.search{ 
flex:1;
height: 40px;
text-align: center;
background: #fff;
}
.input{ 
  flex:9;
  height: 40px;
  background: #fff;
}
.input input{ 
  background: #f1f1f1;
height: 30px;
margin-top: 5px;
margin-bottom: 5px;
margin-right: 8px;
border-radius: 10px;
}
.search image{ 
  width: 70%;
  height: 25px;
  padding-top: 9px;
  padding-left: 5px;
}
.placeholder{ 
  font-size: 14px;
}
.search image{ 
  opacity: 0;
}
.input{ 
  flex:4;
}
.input input{ 
position: relative;
right: 0px;
}
.hotcity1{ 
  display: inline;
}
.map{ 
  position: relative;
}
map{ 
  border:5px solid green;
  text-align: center;
  margin: 10px auto;
position: relative;
right: 10px;
 width: 90%;
 height: 150px;
}

而後咱們的搜索裏面點擊搜索還會跳轉到新的搜索頁面,效果以下
在這裏插入圖片描述
這裏咱們能夠直接複用上面的搜索組件,樣式代碼就再也不貼出來了,這個模塊要將搜索自動匹配的地點名稱用循環的方式顯示出來,代碼以下

緩存

//wxml
<import src="../templates/search/search" />
<template is="search"></template>
<view bindtouchstart="bindSearch" data-keywords="{ {i.name}}"
 class="text_box" wx:for="{ {tips}}" wx:for-item="i" wx:key='index'>
  { { i.name}}
</view>
//wxss
@import '../templates/search/search.wxss';
.text_box{ 
  margin: 10px 25px;
  border-bottom:1px solid #c3c3c3;
  padding-bottom:10px
}

4.外部跳轉

當咱們點擊外部的位置信息,就跳轉到內部的定位模塊,剛剛咱們在上面給外部的標籤設置了觸摸事件getLocation,接下來只要到js裏面設置點擊跳轉(navigateTo)就能夠了,但因爲咱們的位置信息是用全局變量賦值的,因此咱們要在app.js設置一個全局變量,代碼以下微信

//app.js
App({ 
  globalData: { 
    city:'暫未定位',
    userInfo:'無'
  },
  )}
//外部js
// 引入app.js
const app=getApp()
const appG=app.globalData
 data: { 
//這裏要初始化location,並將全局變量賦值給它
aboutList:'',
location:appG.city
  },
  Page({ 
  //定義觸摸事件
  getLocation(){ 
  wx.navigateTo({ 
  //跳轉到內部定位頁面
    url: '../location/location',
  })  
},
)}

5.點擊定位

作這個功能以前咱們須要先考慮用什麼地圖接口,經常使用的有百度地圖,騰訊地圖,高德地圖,本文選用高德地圖接口做爲演示,搜索https://lbs.amap.com/,註冊,進入控制檯,建立新應用,在這裏插入圖片描述架構

再添加key
在這裏插入圖片描述
這個key就像咱們小程序調用接口時的驗證碼,有了它咱們才能從高德調取位置的數據,而後咱們點擊key後面的設置,再點擊微信小程序SDK
在這裏插入圖片描述
進去以後點這兩個,下載amap-wx.js 文件,而後在你的小程序目錄裏面建立一個libs文件,把這個amap-wx.js扔進去
在這裏插入圖片描述
接下來咱們來到內部定位頁面的js文件,由於這裏要對全局變量進行修改來達到修改頁面數據的效果,因此也要引入app.js,並把全局變量初始化到data裏面,除此以外咱們要引入高德的文件來實現高德接口的調用,在data裏面咱們這裏順便把等會要用到的熱門城市等數據一併初始化了





const app=getApp()
const appG=app.globalData
//key裏面填高德控制檯裏面給你的key
const myAmapFun = new amapFile.AMapWX({ key:'xxxxxxxxxx'});
  data: { 
city:appG.city,
hotcity:[
  { 'cityName':'北京市',longitude:'116.395645038',latitude:'39.9299857781'},
  { 'cityName':'上海市',longitude:'121.487899486',latitude:'31.24916171'},
  { 'cityName':'廣州市',longitude:'113.307649675',latitude:'23.1200491021'},
  { 'cityName':'深圳市',longitude:'114.025973657',latitude:'22.5460535462'},
  { 'cityName':'武漢市',longitude:'114.316200103',latitude:'30.5810841269'},
],
tips: { },//搜索自動匹配的內容
longitude:'116.4',//經度(初始值在北京)
latitude:'39.9'//緯度(初始值在北京)
}

而後咱們給定位按鈕設置點擊事件getCity,這裏用到高德地圖裏面的獲取地址描述數據方法,教程能夠參考剛剛高德控制檯微信SDK裏面的教程(下面搜索自動匹配提示的教程也同樣)

在這裏插入圖片描述
此外咱們咱們還要在小程序後臺給高德的接口添加域名,操做步驟爲
登陸微信公衆平臺,「設置「–>"開發設置"設置request合法域名,將https://restapi.amap.com 中添加進去,這樣咱們才能請求到高德的數據

代碼

getCity(){ 
  myAmapFun.getRegeo({ 
    success: data=>{ 
      // that.setData({ 
      // city:data[0].desc.slice(0,2)
      // })
      appG.city=data[0].desc
      wx.getLocation({ 
        success:res=>{ 
this.setData({ 
   latitude:res.latitude,
   longitude:res.longitude
})
wx.setStorageSync('city', appG.city)
wx.setStorageSync('latitude', res.latitude)
wx.setStorageSync('longitude', res.longitude)
        }
      })
    },
    fail: function(info){ 
      //失敗回調
      console.log(info)
    }
  })
},

getRegeo方法的成功回調函數裏的參數包含了定位後的位置信息(能夠本身輸出一下),咱們把它賦值給全局變量,而後再用setData再次把全局變量appG.city賦值給data裏面的city(由於appG.city已經改變了,要從新賦值頁面纔會更新),除此以外咱們還要把獲取到的位置信息同步緩存起來,下次進入頁面的時候在onLoad裏面先判斷有沒有緩存的數據,若是有就直接使用緩存的數據,沒有就用默認值,代碼以下

onLoad: function (options) { 
    // 進頁面先看有無緩存數據,若是沒有再讀默認值,onLoad裏面能夠取到this.data
    const latitude=wx.getStorageSync('latitude')
    const longitude=wx.getStorageSync('longitude')
    const city=wx.getStorageSync('city')
    //用了三目運算符,不習慣也可使用if
    latitude&&longitude&&city?
    this.setData({ 
      latitude:latitude,
      longitude:longitude
    }):false
  },

6.未定位時彈出定位框

給當前位置標籤添加點擊事件,判斷當位置信息爲初始值暫未定位時,彈出是否認位的選擇框,當用戶點擊肯定時,執行一次getCity函數便可,效果以下
在這裏插入圖片描述
代碼

nowCity(){ 
  if(this.data.city!='暫未定位'){ 
    wx.switchTab({ 
      url: '../about/about',
    })
  }else{ 
    wx.showModal({ 
      title: '暫未定位',
      content: '如今要進行定位嗎',
      success: (res)=>{ 
        if (res.confirm) { 
          this.getCity()
        } else if (res.cancel) { 
          return false
        }
      }
    })
  }
},

7.熱門城市點擊跳轉,更新數據

在這裏插入圖片描述
當咱們點擊熱門城市裏面的按鈕時,跳轉到外部頁面,而且把對應熱門城市名稱更新到全局的city來傳到外部頁面顯示,同時還要更新全局中的經緯度數據,對於經緯度只要更新緩存便可,下一次進入內部定位頁面時再判斷緩存中有無定位數據,若是有就直接用,city數據是更新+緩存,代碼以下

hotCity(e){ 
  const index=e.currentTarget.dataset.hotcityindex
  //更新
  appG.city=this.data.hotcity[index].cityName
  //緩存
    wx.setStorageSync('city', appG.city)
  wx.setStorageSync('latitude', this.data.hotcity[index].latitude)
  wx.setStorageSync('longitude', this.data.hotcity[index].longitude)
  //跳轉
wx.reLaunch({ 
  url: '../about/about',
  success:()=>{ 
    // 不要把數據的更新寫在這裏,要在跳轉以前就寫好,由於這個回調函數是在跳轉的頁面全部函數
    // 執行完以後才執行的,會致使數據兩次跳轉次才更新
  }
})
},

上述代碼中注意要在熱門城市的循環標籤用data-hotcityindex="{ {index}}"把下標傳到js中,再在js中用e.currentTarget.dataset.hotcityindex去取出來用,這個下標用來對應熱門城市數組的每個對象,這樣咱們就能夠用this.data.hotcity[index].cityName來獲取被點擊的城市的名稱,再把它更新到appG.city中,注意跳轉的時候不能用wx.switchTab,由於從外部頁面進來的時候已經打開了外部頁面,那麼用wx.switchTab的時候只會執行外部頁面的onShow函數,而不會執行onLoad,會致使頁面數據沒法更新

8.搜索跳轉和輸入自動匹配地名

搜索跳轉新頁面(給內部定位頁面設置聚焦事件)

bindFocus(e){ 
  wx.navigateTo({ 
    url: '../locationSearch/locationSearch',
  })
},

注意內部頁面的搜索框不是自動聚焦的,而跳轉到新的搜索頁面的搜索框是會自動聚焦的,這一點咱們能夠經過在搜索組件的input標籤添加auto-focus="{ {autoFocus}}",再控制autoFocus的值來控制是否自動聚焦,代碼以下

<template is="search" data="{ {autoFocus}}"></template>

注意data="{ {xxx}}"是自定義組件特有的傳參方式,能夠把js裏面的值傳到組件中使用不過咱們得先在搜索頁面的js的data中給autoFocus賦值,這裏順便把保存自動匹配的地名的值tips也初始化了

data: { 
autoFocus:true,
tips:{ }
  },

接下來咱們寫輸入自動匹配地名,一樣在搜索頁面的js引入全局變量和高德js文件

const amapFile = require('../../libs/amap-wx.js');
const app=getApp()
const appG=app.globalData
const myAmapFun = new amapFile.AMapWX({ key:'0c2c8f2007702caa7e0498d6ad072f83'});

而後咱們來監聽用戶的輸入行爲,設置爲bindInput函數

<input type="text" placeholder=" 請輸入你想要的內容" placeholder-class="placeholder"
 bindinput="bindInput" bindfocus="bindFocus" auto-focus="{ {autoFocus}}"></input>

搜索頁面的js中定義bindInput

bindInput(e){ 
  myAmapFun.getInputtips({ 
    // keywords爲必填,否則沒法得到tips,也就不會進入success函數
    keywords:e.detail.value,
    success:data=>{ 
 this.setData({ 
   tips:data.tips
 })
    }
  })
},

上面的getInputtips就是咱們第5點中講到的微信小程序SDK中的獲取提示詞裏面的方法,能夠本身去看高德的教程,此處再也不贅述,上面的keywords的值就是用戶輸入的內容,接口會根據這個去尋找對應匹配的地名並返回在success函數的參數中,咱們只須要在成功回調函數中更新tips就能夠了,那麼此時假如咱們輸入武漢,效果以下
在這裏插入圖片描述
那麼當咱們點擊自動匹配的地名的時候,須要返回到外部頁面,而且更新數據,更新緩存,思路和上面的跳轉方法是同樣的,代碼以下

bindSearch(e){ 
  const location=this.data.tips[e.currentTarget.dataset.searchindex]
  wx.setStorageSync('city', location.name)
  if(location.location.length!=0){ 
    const longitude=location.location.split(',')[0]
    const latitude=location.location.split(',')[1]
  wx.setStorageSync('latitude', latitude)
  wx.setStorageSync('longitude', longitude)
  wx.reLaunch({ 
    url: '../about/about',
      success:()=>{ 
             appG.city=e.currentTarget.dataset.keywords    
    }
  })
  }else{ 
    wx.reLaunch({ 
      url: '../about/about',
        success:()=>{ 
               appG.city=e.currentTarget.dataset.keywords   
               setTimeout(()=>{ wx.showToast({ 
                 title: '暫無經緯度數據',
                // 提示延遲時間,不能用字符串
                 duration:2000,
                 icon:'none'
               })
              },500);
      }
    })
  }

因爲不是每個自動匹配的地點都有經緯度,因此咱們對沒有經緯度的地名作業務退步處理,僅提醒暫無經緯度的數據,(有時候業務退一小步,技術就有一大步的發揮空間–《大型網站技術架構》——李智慧),細心的大家確定注意到上面用了定時器,由於若是不使用定時器,這個彈框是不會顯示出來的,這個函數在頁面加載完成以前就已經執行了,因此咱們給他來一個定時器做爲異步函數延遲執行,纔能有彈框

9.對整個模塊的優化和思考

對上述代碼,筆者開發完以後發現了以下問題:
代碼冗餘嚴重,主要表如今屢次使用緩存的api,重複量的地方不少
整個模塊內部互相調用複雜,高耦合,低拓展
某些地方把簡單的邏輯複雜化了,代碼不夠整潔
對於上述問題,筆者有以下思考:
經過封裝緩存api來減小沒必要要的代碼量,提升代碼整潔度
對整個模塊從新構思,提升可拓展性和可複用性(因爲筆者水平有限,暫時擱置)
模塊從開發開始到開發完成須要不斷的演化和改進,這個過程纔是讓開發者成長的關鍵






本文爲筆者原創文章,轉載請註明出處

相關文章
相關標籤/搜索