微信小程序自定義yPicker組件分析及省市區三級聯動實現



本文爲做者行舟客投稿,前端

原文地址:https://blog.csdn.net/qq_43624878/article/details/109284502?utm_source=appgit

完整項目地址:https://github.com/1314mxc/yunUIgithub

 點擊閱讀原文便可打開github,歡迎點贊!小程序




背景

自從上一篇文章:微信小程序自定義日曆組件及flex佈局最後一行對齊問題分析 出來之後,有人私聊我說能不能從頭分析一下我開源的自定義組件?一直沒時間。這不,最近項目中有個需求是 省市區三級聯動 ,我就順便從組件庫中的第一個 「擴展日期-時間(點此直接至GitHub)」picker組件開始說一下這兩個功能的實現。微信小程序


簡單說一下「自定義日期-時間組件」

它的背景是項目的初版當時發現微信小程序內置的日期組件:picker只能精確到某一天(年月日),可是咱們不少時候須要年月日時分甚至是年月日時分秒(如結束時間/發佈時間)。image.png數組

筆者仔細翻閱了官方文檔和許多博主文章發現提出了各類各樣的解決方案(但很遺憾沒發現有博主詳細公開代碼),可是對於這樣一個其實並不須要「聯動」、列數也不固定的功能,用多列picker模擬多列選擇器 便可。微信

<picker mode="multiSelector" bindchange="bindMultiPickerChange" bindcolumnchange="bindMultiPickerColumnChange" value="{{multiIndex}}" range="{{multiArray}}">
 <input value='{{time}}' readonly="" disabled="true" placeholder='{{defaulttext}}' />
</picker>

其中 readonly="" disabled="true" 的做用是使「input聚焦時軟鍵盤不彈出」(兩個屬性做用同樣,都寫是由於Android和iOS的兼容性問題)。app

用input代替view是由於input的placeholder能夠方便實現「無選中時默認提示」的效果。ide

主要實現策略函數

如上所示,監聽了兩個事件,分別是:日期選擇窗口彈出時以及點擊「肯定」按鈕時觸發函數change、多列選擇器每一列滑動時觸發事件columnchange。

  1. change中很簡單:只須要把選中的數據暴露給頁面中(或者經過 triggerEvent 返回給調用頁面)便可;
  2. columnchange中要作的就是當前選中的每一列的值填充到data中對應數組的某一項。好比:e.detail.column==1 時表示當前滑動的是第二列(月份),此時就要判斷每一月有幾天:
if (e.detail.column == 1) {
     let num = parseInt(this.data.multiArray[e.detail.column][e.detail.value]);
     let temp = [];
     if (num == 1 || num == 3 || num == 5 || num == 7 || num == 8 || num == 10 || num == 12) { //判斷31天的月份
       for (let i = 1; i <= 31; i++) {
         if (i < 10) {
           i = "0" + i;
         }
         temp.push("" + i);
       }
       this.setData({
         ['multiArray[2]']: temp   //天數更新(根據月份)
       });
    }
}

注意: 多列picker組件監聽兩個參數:multiArray和multiIndex,他們都是數組!multiArray主要用來表示監聽幾列,其元素都是一個個數組,如:[years, months, days, hours, minutes]multiIndex是當前每一列(點開時的)初始值!如:[10, meng_date.getMonth(), meng_date.getDate()-1, meng_date.getHours(), meng_date.getMinutes()]通常來講,multiIndex中的值也被用來當作取multiArray中元素時的第二個索引!


說說省市區三級聯動實現

先將城市列表文件發出來:(永久免費下載)

連接 提取碼
https://pan.baidu.com/s/1z4ZfOWnAG2zVaGfxXxpF9Q j3m3

使用時按以下引入便可:(是一個citysearch.js文件)

import placeArrays from 'citysearch文件路徑';
const placeArray=placeArrays.placeArray

image.pngcitys

正式開始

不知你們有沒有使用過,或聽太小程序的 picker-view 組件,其定位就是:嵌入頁面的滾動選擇器。它有三個參數:

參數 類型 說明
value Number Array 數組中的數字依次表示 picker-view 內的 picker-view-colume 選擇的第幾項(下標從 0 開始),數字大於 picker-view-column 可選項長度時,選擇最後一項。
indicator-style String 設置選擇器中間選中框的樣式
bindchange EventHandle 當滾動選擇,value 改變時觸發 change 事件,event.detail = {value: value} value爲數組,表示 picker-view 內的 picker-view-column 當前選擇的是第幾項(下標從 0 開始)

須要注意的是:其中只可放置<picker-view-column/>組件,其餘節點不會顯示,其孩子節點的高度會自動設置成與picker-view的選中框的高度一致。

有了這個組件,咱們是否是能想到:在一個彈出view中設置三個picker-view組件,每一個組件中放一個picker-view-column組件用於展現當前列?

value中也能夠只放一個number(一般能夠放數組元素下標),picker-view會自動將其轉爲 [下標值]

就像這樣:

<view style="width:100%;position:fixed;bottom:0;left:0;z-index:10000;height:500rpx;background-color:white">
  <!-- 仿原生picker的「肯定」和「取消」按鈕 -->
  <view style="display:flex;width:100%;height:100%">
    <view
      style="position: absolute;top:0;width:100%;height:100rpx;z-index:1000000;display:flex;justify-content:space-between;align-items:center;">

      <view style="width:calc(100% / 3);text-align:center;color:rgba(0,0,0,.6);font-size:39rpx" bindtap="displayer">取消
      </view>
      <view style="width:calc(100% / 3);text-align:center;color:rgb(63,142,255);font-size:39rpx" bindtap="confirm">肯定
      </view>
    </view>
    
    <picker-view indicator-style="height: 200rpx;"
      style="width: 100%;height: 300rpx;text-align: center;margin-top:150rpx" value="{{pIndex}}"
      bindchange="changeProvince">

      <picker-view-column>
        <view wx:for="{{placeArray}}" wx:key="name" style="line-height: 77rpx">{{item.name}}</view>
      </picker-view-column>
    </picker-view>
    <picker-view indicator-style="height: 200rpx;"
      style="width: 100%;height: 300rpx;text-align: center;margin-top:150rpx" value="{{cIndex}}"
      bindchange="changeCity">

      <picker-view-column>
        <view wx:for="{{placeArray[pIndex].city}}" wx:key="name" style="line-height: 77rpx">{{item.name}}</view>
      </picker-view-column>
    </picker-view>
    <picker-view indicator-style="height: 200rpx;"
      style="width: 100%;height: 300rpx;text-align: center;margin-top:150rpx" value="{{aIndex}}"
      bindchange="changeArea">

      <picker-view-column>
        <view wx:for="{{placeArray[pIndex].city[cIndex].area}}" wx:key="*this" style="line-height: 77rpx">{{item}}
        </view>
      </picker-view-column>
    </picker-view>
    
  </view>
</view>

能夠看到,每個picker-view-column中作的惟一一件事就是:遍歷固定的某一列(某一個數組)並渲染出來。image.png

// js-data
data:{
 placeArray: placeArray,
    province"",//placeArray[0].name - 省
    pIndex0,
    city"",//placeArray[0].city[0].name - 市
    cIndex0,
    area"",//placeArray[0].city[0].area[0] - 區
    aIndex0,
}

而後如上wxml中爲每一列(picker-view)都綁定了一個change函數——滑動時觸發:

changeProvince: function(e){
  const val = e.detail.value
  this.setData({
    pIndex: val,
    cIndex0,
    aIndex0,
    province: placeArray[val].name,
    city: placeArray[val].city[0].name,
    area: placeArray[val].city[0].area[0]
  })
},
changeCityfunction(e){
  const val = e.detail.value
  this.setData({
    cIndex: val,
    aIndex0,
    city: placeArray[this.data.pIndex].city[val].name,
    area: placeArray[this.data.pIndex].city[val].area[0]
  })
},
changeAreafunction(e){
  const val = e.detail.value
  this.setData({
    aIndex: val,
    area: placeArray[this.data.pIndex].city[this.data.cIndex].area[val]
  })
},

他們的做用就是把當前選擇列的選中元素(出如今indicator-style視野中的元素)暴露到頁面上,並將下標定位到這裏 —— 以便在頁面無刷新下的下一次點開時從這裏開始找!而後最重要的一點就是:在滑動中止時,將另外兩列的數據從新定位到第一個!
——固然,你也能夠選擇在一個picker-view中放置多個picker-view-column組件,這樣的話就和上面多列picker同樣,須要多個數組聯動來傳遞數據了!image.png



最後

  • 歡迎加我微信(winty230),拉你進技術羣,長期交流學習...

  • 歡迎關注「前端Q」,認真學前端,作個專業的技術人...

image.png

相關文章
相關標籤/搜索