自從上一篇文章:微信小程式自定義日歷組件及flex布局最后一行對齊問題分析 出來以后,有人私聊我說能不能從頭分析一下我開源的自定義組件?一直沒時間,這不,最近專案中有個需求是 省市區三級聯動 ,我就順便從組件庫中的第一個 「擴展日期-時間picker(點此直接至GitHub,歡迎star)」組件開始說一下這兩個功能的實作,
簡單說一下“自定義日期-時間組件”
它的背景是專案的第一版當時發現微信小程式內置的日期組件:picker只能精確到某一天(年月日),但是我們很多時候需要年月日時分甚至是年月日時分秒(如結束時間/發布時間),

筆者仔細翻閱了官方檔案和許多博主文章發現提出了各種各樣的解決方案(但很遺憾沒發現有博主詳細公開代碼),但是對于這樣一個其實并不需要“聯動”、列數也不固定的功能,用多列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的兼容性問題),
用input代替view是因為input的placeholder方便實作“無選中時默認提示”的效果,
主要實作策略
如上所示,監聽了兩個事件,分別是:日期選擇視窗彈出時以及點擊“確定”按鈕時觸發函式change、多列選擇器中每一列滑動時觸發事件columnchange,
- change中很簡單:只需要把選中的資料暴露給頁面中(或者通過
triggerEvent回傳給呼叫頁面)即可; - 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

正式開始
不知大家有沒有使用過,或聽過小程式的 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中做的唯一一件事就是:遍歷固定的某一列(某一個陣列)并渲染出來,

// js-data
data:{
placeArray: placeArray,
province: "",//placeArray[0].name - 省
pIndex: 0,
city: "",//placeArray[0].city[0].name - 市
cIndex: 0,
area: "",//placeArray[0].city[0].area[0] - 區
aIndex: 0,
}
然后如上wxml中為每一列(picker-view)都系結了一個change函式——滑動時觸發:
changeProvince: function(e){
const val = e.detail.value
this.setData({
pIndex: val,
cIndex: 0,
aIndex: 0,
province: placeArray[val].name,
city: placeArray[val].city[0].name,
area: placeArray[val].city[0].area[0]
})
},
changeCity: function(e){
const val = e.detail.value
this.setData({
cIndex: val,
aIndex: 0,
city: placeArray[this.data.pIndex].city[val].name,
area: placeArray[this.data.pIndex].city[val].area[0]
})
},
changeArea: function(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一樣,需要多個陣列聯動來傳遞資料了!
CSDN認證博客專家
ECMAScript 6
Node.js
CSS
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/193476.html
標籤:python
