Analysis of custom yPicker component of WeChat applet and realization of three-level linkage between provinces and cities

Since the last article: WeChat applet custom calendar components and the last line of flex layout alignment problems were analyzed , someone chatted privately and asked me if I could analyze my open source custom components from the beginning? There has been no time. This does not, there is a demand in recent project is the provinces three linkage , my first one on the way "from the component library extension date - time picker (Click here to directly to the GitHub, welcome star) " assembly began to say about this The realization of two functions.


Briefly say "custom date-time components"

Its background is that the first version of the project found that the built-in date component of the WeChat applet: picker can only be accurate to a certain day (year, month, day), but we often need year, month, day, hour, and even year, month, day, hour, minute, and second (such as End time/release time).
yPicker

The author carefully looked through the official documents and many bloggers’ articles and found that various solutions were proposed (but unfortunately no bloggers disclosed the code in detail), but there is no need for “linkage” and the number of columns for such a For non-fixed functions, use a multi-column picker to simulate a multi-column selector .

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

Which readonly="" disabled="true"is the role of the "input soft keyboard does not pop up when the focus" (action of two properties, as they are written because of compatibility issues with Android and iOS).

Use input instead of view because the placeholder of input facilitates the effect of "prompt by default when not selected".

Main implementation strategy

As shown above, two events are monitored: when the date selection window pops up and when the "OK" button is clicked, the function change is triggered, and the event columnchange is triggered when each column in the multi-column selector slides.

  1. change is very simple: just need to be exposed to the selected data page (or by triggerEventthe return to the calling page) can be;
  2. What to do in columnchange is to fill the value of each column currently selected into an item of the corresponding array in data. For example: e.detail.column==1Hour means that the current sliding is the second column (month). At this time, it is necessary to judge how many days each month:
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   //第三列天数更新(根据月份)
       });
    }
}

Note: The multi-column picker component monitors two parameters: multiArray and multiIndex, they are both arrays!
multiArray is mainly used to indicate the monitoring of several columns, and its elements are arrays, such as: [years, months, days, hours, minutes]
multiIndex is the initial value of each column (when it is clicked)! Such as: [10, meng_date.getMonth(), meng_date.getDate()-1, meng_date.getHours(), meng_date.getMinutes()]
Generally speaking, the value in multiIndex is also used as the second index when fetching elements in multiArray!


Talk about the realization of three-level linkage between provinces and cities

Send out the city list file first: (forever free download)

link Extraction code
https://pan.baidu.com/s/1z4ZfOWnAG2zVaGfxXxpF9Q j3m3

When using, it can be imported as follows: (is a citysearch.js file)

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

citys

Officially begin

I wonder if you have not used before, or heard applet picker-viewassembly position is: embedded scroll selector page .
It has three parameters:

parameter Types of Description
value Number Array The numbers in the array indicate the number of items selected by picker-view-colume in picker-view (the subscript starts from 0). When the number is greater than the length of the picker-view-column option, the last item is selected.
indicator-style String Set the style of the selected box in the middle of the selector
bindchange EventHandle When scrolling selection, the change event is triggered when the value changes. The event.detail = {value: value}value is an array, which means the picker-view-column in the picker-view is currently selected (the subscript starts from 0)

It should be noted that: only <picker-view-column/>components can be placed in it , other nodes will not be displayed, and the height of its child nodes will be automatically set to be the same as the height of the check box of picker-view.

With this component, can we think of: set three picker-view components in a pop-up view, and put a picker-view-column component in each component to display the current column?

You can also put only one number in the value (usually you can put the subscript of the array element), and picker-view will automatically convert it to [下标值]

like this:

<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>

As you can see, the only thing that each picker-view-column does is to traverse a fixed column (an array) and render it.
city_picker

// 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,
}

Then a change function is bound to each column (picker-view) in the above wxml-triggered when sliding:

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]
  })
},

Their role is to expose the selected elements of the current selection column (elements that appear in the indicator-style field of view) to the page, and position the subscripts here - so that they can be opened from here when the page is not refreshed next time. Start looking!
Then the most important point is: when the sliding stops, reposition the other two columns of data to the first one!


——Of course, you can also choose to place multiple picker-view-column components in a picker-view. In this way, just like the above multi-column picker, multiple arrays are needed to transfer data!

Guess you like

Origin blog.csdn.net/qq_43624878/article/details/109284502