1. 程式人生 > 程式設計 >超詳細小程式定位地圖模組全系列開發教學

超詳細小程式定位地圖模組全系列開發教學

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

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

如美團外賣小程式

在這裡插入圖片描述

點定位

在這裡插入圖片描述

點搜尋

在這裡插入圖片描述

顯而易見,隨便一個電商小程式都需要用到定位服務,那麼今天我們做一個類似的定位模組
定位模組總覽
外部頁面

在這裡插入圖片描述

內部頁面(下文說的內外部頁面就是指這兩個)

在這裡插入圖片描述

好了接下來我們開始動手

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.定位模組內部樣式

效果

在這裡插入圖片描述

程式碼(分五個小模組,見註釋)

//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);
 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來減少不必要的程式碼量,提高程式碼整潔度
對整個模組重新構思,提高可拓展性和可複用性(由於筆者水平有限,暫時擱置)
模組從開發開始到開發完成需要不斷的演化和改進,這個過程才是讓開發者成長的關鍵

到此這篇關於超詳細小程式定位地圖模組全系列開發教學 的文章就介紹到這了,更多相關小程式定位地圖內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!