超詳細(xì)小程序定位地圖模塊全系列開發(fā)教學(xué)
前言:如果想最大化吸取本文經(jīng)驗(yàn),須有小程序開發(fā)基礎(chǔ),本文細(xì)節(jié)比較多(多看注釋的提醒內(nèi)容),請耐心理解,多動手嘗試,收獲會更加豐富
1.定位系統(tǒng)使用場景及概述
如美團(tuán)外賣小程序
點(diǎn)定位
點(diǎn)搜索
顯而易見,隨便一個電商小程序都需要用到定位服務(wù),那么今天我們做一個類似的定位模塊
定位模塊總覽
外部頁面
內(nèi)部頁面(下文說的內(nèi)外部頁面就是指這兩個)
好了接下來我們開始動手
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圖片放進(jìn)去的,我們用flex布局讓圖片和文字在同一行居中顯示(見注釋)
3.定位模塊內(nèi)部樣式
效果
代碼(分五個小模塊,見注釋)
//wxml //搜索模塊 <view class="header"> <view class="search"> <image src="../../img/sousuo.png"></image> </view> <view class="input"> <input type="text" placeholder=" 請輸入你想要的內(nèi)容" 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> //當(dāng)前位置模塊 <view >當(dāng)前所在位置</view> <button size="mini" bindtap="nowCity" class='nowcity'>{{city}}</button> //熱門城市模塊 <view class="hotcity">熱門城市</view> <view wx:for="{{hotcity}}" wx:key='index' class="hotcity1"> <!-- 用了view循環(huán)之后要把view設(shè)置為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>
由于我的搜索框是用了自定義組件里面的搜索組件,我是在組件的基礎(chǔ)上改出來的,原組件是這樣的
我們需要把搜索圖標(biāo)隱藏,我們直接設(shè)置它的透明度為0,然后把我們的定位文字跟圖標(biāo)通過定位直接定位到搜索框的左邊,所以樣式的代碼如下(代碼太多不好找的話可以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; }
然后我們的搜索里面點(diǎn)擊搜索還會跳轉(zhuǎn)到新的搜索頁面,效果如下
這里我們可以直接復(fù)用上面的搜索組件,樣式代碼就不再貼出來了,這個模塊要將搜索自動匹配的地點(diǎn)名稱用循環(huán)的方式顯示出來,代碼如下
//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.外部跳轉(zhuǎn)
當(dāng)我們點(diǎn)擊外部的位置信息,就跳轉(zhuǎn)到內(nèi)部的定位模塊,剛剛我們在上面給外部的標(biāo)簽設(shè)置了觸摸事件getLocation,接下來只要到j(luò)s里面設(shè)置點(diǎn)擊跳轉(zhuǎn)(navigateTo)就可以了,但由于我們的位置信息是用全局變量賦值的,所以我們要在app.js設(shè)置一個全局變量,代碼如下
//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({ //跳轉(zhuǎn)到內(nèi)部定位頁面 url: '../location/location', }) }, )}
5.點(diǎn)擊定位
做這個功能之前我們需要先考慮用什么地圖接口,常用的有百度地圖,騰訊地圖,高德地圖,本文選用高德地圖接口作為演示,搜索https://lbs.amap.com/,注冊,進(jìn)入控制臺,創(chuàng)建新應(yīng)用,
再添加key
這個key就像我們小程序調(diào)用接口時的驗(yàn)證碼,有了它我們才能從高德調(diào)取位置的數(shù)據(jù),然后我們點(diǎn)擊key后面的設(shè)置,再點(diǎn)擊微信小程序SDK
進(jìn)去之后點(diǎn)這兩個,下載amap-wx.js 文件,然后在你的小程序目錄里面創(chuàng)建一個libs文件,把這個amap-wx.js扔進(jìn)去
接下來我們來到內(nèi)部定位頁面的js文件,因?yàn)檫@里要對全局變量進(jìn)行修改來達(dá)到修改頁面數(shù)據(jù)的效果,所以也要引入app.js,并把全局變量初始化到data里面,除此之外我們要引入高德的文件來實(shí)現(xiàn)高德接口的調(diào)用,在data里面我們這里順便把等會要用到的熱門城市等數(shù)據(jù)一并初始化了
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: {},//搜索自動匹配的內(nèi)容 longitude:'116.4',//經(jīng)度(初始值在北京) latitude:'39.9'//緯度(初始值在北京) }
然后我們給定位按鈕設(shè)置點(diǎn)擊事件getCity,這里用到高德地圖里面的獲取地址描述數(shù)據(jù)方法,教程可以參考剛剛高德控制臺微信SDK里面的教程(下面搜索自動匹配提示的教程也一樣)
此外我們我們還要在小程序后臺給高德的接口添加域名,操作步驟為
登錄微信公眾平臺,“設(shè)置“–>"開發(fā)設(shè)置"設(shè)置request合法域名,將https://restapi.amap.com 中添加進(jìn)去,這樣我們才能請求到高德的數(shù)據(jù)
代碼
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){ //失敗回調(diào) console.log(info) } }) },
getRegeo方法的成功回調(diào)函數(shù)里的參數(shù)包含了定位后的位置信息(可以自己輸出一下),我們把它賦值給全局變量,然后再用setData再次把全局變量appG.city賦值給data里面的city(因?yàn)閍ppG.city已經(jīng)改變了,要重新賦值頁面才會更新),除此之外我們還要把獲取到的位置信息同步緩存起來,下次進(jìn)入頁面的時候在onLoad里面先判斷有沒有緩存的數(shù)據(jù),如果有就直接使用緩存的數(shù)據(jù),沒有就用默認(rèn)值,代碼如下
onLoad: function (options) { // 進(jìn)頁面先看有無緩存數(shù)據(jù),如果沒有再讀默認(rèn)值,onLoad里面可以取到this.data const latitude=wx.getStorageSync('latitude') const longitude=wx.getStorageSync('longitude') const city=wx.getStorageSync('city') //用了三目運(yùn)算符,不習(xí)慣也可以使用if latitude&&longitude&&city? this.setData({ latitude:latitude, longitude:longitude }):false },
6.未定位時彈出定位框
給當(dāng)前位置標(biāo)簽添加點(diǎn)擊事件,判斷當(dāng)位置信息為初始值暫未定位時,彈出是否定位的選擇框,當(dāng)用戶點(diǎn)擊確定時,執(zhí)行一次getCity函數(shù)即可,效果如下
代碼
nowCity(){ if(this.data.city!='暫未定位'){ wx.switchTab({ url: '../about/about', }) }else{ wx.showModal({ title: '暫未定位', content: '現(xiàn)在要進(jìn)行定位嗎', success: (res)=>{ if (res.confirm) { this.getCity() } else if (res.cancel) { return false } } }) } },
7.熱門城市點(diǎn)擊跳轉(zhuǎn),更新數(shù)據(jù)
當(dāng)我們點(diǎn)擊熱門城市里面的按鈕時,跳轉(zhuǎn)到外部頁面,并且把對應(yīng)熱門城市名稱更新到全局的city來傳到外部頁面顯示,同時還要更新全局中的經(jīng)緯度數(shù)據(jù),對于經(jīng)緯度只要更新緩存即可,下一次進(jìn)入內(nèi)部定位頁面時再判斷緩存中有無定位數(shù)據(jù),如果有就直接用,city數(shù)據(jù)是更新+緩存,代碼如下
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) //跳轉(zhuǎn) wx.reLaunch({ url: '../about/about', success:()=>{ // 不要把數(shù)據(jù)的更新寫在這里,要在跳轉(zhuǎn)之前就寫好,因?yàn)檫@個回調(diào)函數(shù)是在跳轉(zhuǎn)的頁面所有函數(shù) // 執(zhí)行完之后才執(zhí)行的,會導(dǎo)致數(shù)據(jù)兩次跳轉(zhuǎn)次才更新 } }) },
上述代碼中注意要在熱門城市的循環(huán)標(biāo)簽用data-hotcityindex="{{index}}"把下標(biāo)傳到j(luò)s中,再在js中用e.currentTarget.dataset.hotcityindex去取出來用,這個下標(biāo)用來對應(yīng)熱門城市數(shù)組的每一個對象,這樣我們就可以用this.data.hotcity[index].cityName來獲取被點(diǎn)擊的城市的名稱,再把它更新到appG.city中,注意跳轉(zhuǎn)的時候不能用wx.switchTab,因?yàn)閺耐獠宽撁孢M(jìn)來的時候已經(jīng)打開了外部頁面,那么用wx.switchTab的時候只會執(zhí)行外部頁面的onShow函數(shù),而不會執(zhí)行onLoad,會導(dǎo)致頁面數(shù)據(jù)無法更新
8.搜索跳轉(zhuǎn)和輸入自動匹配地名
搜索跳轉(zhuǎn)新頁面(給內(nèi)部定位頁面設(shè)置聚焦事件)
bindFocus(e){ wx.navigateTo({ url: '../locationSearch/locationSearch', }) },
注意內(nèi)部頁面的搜索框不是自動聚焦的,而跳轉(zhuǎn)到新的搜索頁面的搜索框是會自動聚焦的,這一點(diǎn)我們可以通過在搜索組件的input標(biāo)簽添加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'});
然后我們來監(jiān)聽用戶的輸入行為,設(shè)置為bindInput函數(shù)
<input type="text" placeholder=" 請輸入你想要的內(nèi)容" placeholder-class="placeholder" bindinput="bindInput" bindfocus="bindFocus" auto-focus="{{autoFocus}}"></input>
搜索頁面的js中定義bindInput
bindInput(e){ myAmapFun.getInputtips({ // keywords為必填,不然無法獲得tips,也就不會進(jìn)入success函數(shù) keywords:e.detail.value, success:data=>{ this.setData({ tips:data.tips }) } }) },
上面的getInputtips就是我們第5點(diǎn)中講到的微信小程序SDK中的獲取提示詞里面的方法,可以自己去看高德的教程,此處不再贅述,上面的keywords的值就是用戶輸入的內(nèi)容,接口會根據(jù)這個去尋找對應(yīng)匹配的地名并返回在success函數(shù)的參數(shù)中,我們只需要在成功回調(diào)函數(shù)中更新tips就可以了,那么此時假如我們輸入武漢,效果如下
那么當(dāng)我們點(diǎn)擊自動匹配的地名的時候,需要返回到外部頁面,并且更新數(shù)據(jù),更新緩存,思路和上面的跳轉(zhuǎn)方法是一樣的,代碼如下
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: '暫無經(jīng)緯度數(shù)據(jù)', // 提示延遲時間,不能用字符串 duration:2000, icon:'none' }) },500); } }) }
由于不是每一個自動匹配的地點(diǎn)都有經(jīng)緯度,所以我們對沒有經(jīng)緯度的地名做業(yè)務(wù)退步處理,僅提醒暫無經(jīng)緯度的數(shù)據(jù),(有時候業(yè)務(wù)退一小步,技術(shù)就有一大步的發(fā)揮空間–《大型網(wǎng)站技術(shù)架構(gòu)》——李智慧),細(xì)心的你們肯定注意到上面用了定時器,因?yàn)槿绻皇褂枚〞r器,這個彈框是不會顯示出來的,這個函數(shù)在頁面加載完成之前就已經(jīng)執(zhí)行了,所以我們給他來一個定時器作為異步函數(shù)延遲執(zhí)行,才能有彈框
9.對整個模塊的優(yōu)化和思考
對上述代碼,筆者開發(fā)完之后發(fā)現(xiàn)了如下問題:
代碼冗余嚴(yán)重,主要表現(xiàn)在多次使用緩存的api,重復(fù)量的地方很多
整個模塊內(nèi)部互相調(diào)用復(fù)雜,高耦合,低拓展
某些地方把簡單的邏輯復(fù)雜化了,代碼不夠整潔
對于上述問題,筆者有如下思考:
通過封裝緩存api來減少不必要的代碼量,提高代碼整潔度
對整個模塊重新構(gòu)思,提高可拓展性和可復(fù)用性(由于筆者水平有限,暫時擱置)
模塊從開發(fā)開始到開發(fā)完成需要不斷的演化和改進(jìn),這個過程才是讓開發(fā)者成長的關(guān)鍵
到此這篇關(guān)于超詳細(xì)小程序定位地圖模塊全系列開發(fā)教學(xué) 的文章就介紹到這了,更多相關(guān)小程序定位地圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
textContent在Firefox下與innerText等效的屬性
textContent在Firefox下與innerText等效的屬性...2007-05-05自制的文件上傳JS控件可支持IE、chrome、firefox etc
這篇文章主要介紹了自制的文件上傳JS控件可支持IE、chrome、firefox etc,需要的朋友可以參考下2014-04-04JavaScript實(shí)現(xiàn)點(diǎn)擊自制菜單效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)點(diǎn)擊自制菜單效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-02-02