在一些需求中,我們需要有一個全國城市的列表供我們選擇,並且可以獲得對應的經緯度座標。
今天,我們就一起來實現這個需求。
好,我們先看一下我們期望的最終效果,如下圖:
我們看到左側有個下拉選項,右側是供搜尋的輸入關鍵字用到的輸入框。
關於搜尋的需求可以看這個教程使用高德地圖微信小程式SDK開發案例-輸入提示(附原始碼)
我們今天主要實現如下需求:
1.頁面佈局。
2.進入頁面自動定位當前所在的城市。
3.獲取全國城市列表,並且按照拼音的首字母排序。
4.點選後獲取對應的經緯度。
5.點選字母跳轉到同一類拼音首字母開始的列表。
知道的要做的事情,我們們就開始擼程式碼~
<view class=`list-city`>
<scroll-view scroll-y="true" style="height:100%;" scroll-into-view="{{scrollTopId}}" scroll-with-animation="true" enable-back-to-top="true">
<view class=`item`>
<view class=`fullname`>當前定位城市:{{citySelected}}</view>
</view>
<!-- 熱門城市 -->
<view class=`item`>
<view class=`py` id="hot">熱門城市</view>
<view class="fullname hot-city" wx:for="{{hotCityData}}" wx:key="key" data-fullname="{{item.fullname}}" data-lat="{{item.location.lat}}" data-lng="{{item.location.lng}}" bindtap=`selectCity`>{{item.fullname}}
</view>
</view>
<!-- 全部 -->
<view class=`item` wx:for="{{cityData}}" wx:for-index="idx" wx:for-item="group" wx:key="key">
<view class=`py` id="{{idx}}">{{idx}}</view>
<view class="fullname" wx:for="{{group}}" wx:key="key" data-fullname="{{item.fullname}}" data-lat="{{item.location.lat}}" data-lng="{{item.location.lng}}" bindtap=`selectCity`>{{item.fullname}}
</view>
</view>
</scroll-view>
<!-- 首字母 -->
<view class=`city-py` bindtouchstart="tStart" bindtouchend="tEnd" catchtouchmove="tMove">
<view wx:for="{{_py}}" wx:key="key" bindtouchstart="getPy" bindtouchend="setPy" id="{{item}}">{{item == `hot` ? "★" : item}}
</view>
</view>
</view>
這是頁面的主要結構,我們分為三大塊,熱門城市,全部城市,還是有首字母。
我們使用迴圈來展示城市名稱,並且使用data-fullname=”{{item.fullname}}” data-lat=”{{item.location.lat}}” data-lng=”{{item.location.lng}}” bindtap=`selectCity`來記錄對應城市的經緯度,同時繫結了點選事件來獲取經緯度和城市名稱。
至於頁面右側字母索引繫結的事件比較複雜,我們到後面詳細來講。
頁面的骨架有了,接著可以寫幾行css來美化下頁面。然後我們正式進入主要階段。
我們通過高德地圖微信小程式SDKhttps://lbs.amap.com/api/wx/g…。
onLoad: function() {
var that = this;
var myAmapFun = new amapFile.AMapWX({key:`高德Key`});
myAmapFun.getRegeo({
success: function(data){
//成功回撥,獲得當前所在城市名稱
let city = data.regeocodeData.addressComponent.province;
},
fail: function(info){
//失敗回撥
console.log(info)
}
})
},
或者我們也可以使用騰訊地圖微信小程式SDK https://lbs.qq.com/qqmap_wx_j… 提供的介面來獲取。因為我們接下來就要使用騰訊地圖微信小程式SDK。
第二步我們實現了,接下來獲取全國城市列表。
是的,https://lbs.qq.com/qqmap_wx_j…,在頁面上我們很快發現了這個介面,我們直接呼叫。然而我直接將資料儲存到了js檔案。
https://raw.githubusercontent…
我們根據資料直接賦值到頁面上的引數,結果很順利。
很快,我們到了第四步,我們為列表的事件新增函式。
//選擇城市
selectCity: function (e) {
var dataset = e.currentTarget.dataset;
this.setData({
citySelected: dataset.fullname,
location: {
latitude: dataset.lat,
longitude: dataset.lng
}
});
}
我們獲取到剛才我們設定的三個屬性,並且儲存他們,以備後續使用。
是的,很簡單,我們現在差後一步。當我們點選C的時候,頁面滾動到重慶市,點選W的時候頁面滾動到武清區。。。。以此類推。
於是我們字母索引新增2個事件,bindtouchstart=”getPy” bindtouchend=”setPy”。
//獲取點選的字母,在頁面放大上展示
getPy: function (e) {
this.setData({
hidden: false,
showPy: e.target.id,
})
},
//將設定到字母,賦值到scrollTopId
setPy: function (e) {
this.setData({
hidden: true,
scrollTopId: this.data.showPy
})
},
不急,我們慢慢來,這裡有幾個問題。
1.賦值到scrollTopId是為什麼?
<scroll-view scroll-y="true" scroll-into-view="{{scrollTopId}}" scroll-with-animation="true" enable-back-to-top="true">
我們看到我們使用了小程式的scroll-view元件,我們將scrollTopId這個值賦值給了scroll-into-view屬性,scroll-with-animation=”true” 並且滾動時有滑動效果。
這個類似於網頁中的錨點,給scroll-into-view賦一個值X以後,頁面將滾動到子元素設定屬性id=`x`的地方。所以我們看到:
<view class=`py` id="{{idx}}">{{idx}}</view>
我們為列表中的索引新增了屬性id。
第二個問題,為什麼繫結2個事件,而不是一個點選事件bindtap
這裡關係到我們下一個需求,就是我們手指點選索引那一欄之後,不離開,通過上下滑動,可以快速預覽城市列表,當手指離開之後,列表滾動到手指最後停留的那個字母位置。
而且,我們必須將滑動的互動事件繫結到字母索引的外層,就像我們看到的這樣:
<view class=`city-py` bindtouchstart="tStart" bindtouchend="tEnd" catchtouchmove="tMove">
<view wx:for="{{_py}}" wx:key="key" bindtouchstart="getPy" bindtouchend="setPy" id="{{item}}">
{{item == `hot` ? "★" : item}}
</view>
</view>
當我們將getPy有setPy合併到一個事件中時,我們將無法看到索引字母在頁面中間的效果,當我們手指觸控到的時候顯示,離開的時候消失,這裡是2個事件。
就像這樣,中間字母的預覽效果。
如果我們將這2個事件合併到父元素上時,我們將很難獲取到準確的字母索引值,也就是id。
我們在父元素上新增了三個事件,
//滑動時
tMove: function (e) {
var y = e.touches[0].clientY,
offsettop = e.currentTarget.offsetTop,
that = this;
//判斷選擇區域,只有在選擇區才會生效
if (y > offsettop) {
var num = parseInt((y - offsettop) / 12);
this.setData({
showPy: that.data._py[num]
})
};
},
//觸發全部開始選擇
tStart: function () {
this.setData({
hidden: false
})
},
//觸發結束選擇
tEnd: function () {
this.setData({
hidden: true,
scrollTopId: this.data.showPy
})
},
當我們在索引那一欄上下滑動手指的同時,計算出當前手指可能觸碰到的字母,並且當且僅當手指在元素範圍內的時候觸發。
可能你覺這些程式碼有部分冗餘,是否可以將tStart與tEnd捨去?答案是可以的,功能不受影響,但是當你在上下滑動的過程中,可以明顯感到中間索引的提示有明顯的卡頓,這不是我們想要的。
程式碼寫到這裡,基本上已經差不多了。
如有更好的實現方式希望在評論區能夠分享。
詳細案例請搜尋微信小程式:52魔都
原始碼地址:https://github.com/749264345/…