微信小程式全國城市列表索引開發案例

Jnst發表於2018-11-24

在一些需求中,我們需要有一個全國城市的列表供我們選擇,並且可以獲得對應的經緯度座標。
今天,我們就一起來實現這個需求。
好,我們先看一下我們期望的最終效果,如下圖:
52魔都.png

我們看到左側有個下拉選項,右側是供搜尋的輸入關鍵字用到的輸入框。
關於搜尋的需求可以看這個教程使用高德地圖微信小程式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” 並且滾動時有滑動效果。
52魔都.png
這個類似於網頁中的錨點,給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個事件。
52魔都.png
就像這樣,中間字母的預覽效果。
如果我們將這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/…

相關文章