Use effect

The date-time-picker made by wechat picker is very smooth. When it is gently slippery, it does not stall or jump at all. The whole line rolls smoothly, just like slipping on ice, and it cannot stop.

Since the use of their own written small wheels, feel the whole small program smooth up, the whole body comfortable ha ha ha.

Why did you make the little wheel

You need to use date and time pickers in wechat mini programs, and wechat official pickers only have five types of pickers: ordinary/multi-column/time/date/province.

Because the vant library is referenced in the applet, the timing component (DatetimePicker) is naturally found there. However, in the process of using the real machine, it is found that the problem of stalling and jumping options often occurs in the scrolling column options.

Surfing the Internet shows that many people have encountered this problem in real life, and have come up with various ways to trap the free spirit of the DatetimePicker. I also followed the operation of some, but maybe my three years ago Android does not deserve it, the components still have their own ideas, jumping around.

After I carefully scrolled to 35 again and it slowly bounced to 43, I grumpily shut down the widget and decided to make my own date and time picker with the official picker.

The solution

The multi-column selector type that uses the wechat applet native picker is encapsulated as a date-time-picker component.

Imaginary trouble spots: 1. Special day problem; 2. Time boundary problem

Practice process:

A basis,

1. Pass three time stamps (minTime, maxTime, defaultTime) to verify the timestamp relationship when referencing the component. MinTime <=defaultTime<=maxTime to perform other operations.

CheckCondition () {let minTime = this.data. MinTime let maxTime = this.data. MaxTime let currentTime = this.data This. Data. DefaultTime if (maxTime - minTime < 0) {console. Error (' wrong range of optional parameters')} else if (currentTime - minTime < 0 | | CurrentTime - maxTime > 0) {console.error(' default time is not optional ')} else {this.getCondition()}}Copy the code

2. The specific data of the basic timestamp (Y-M-D-H-I) needs to be obtained, and zeros need to be added when displayed in the list.

GetTimeInfo (stamp) {let time = new Date(stamp) let obj = {y: time.getFullYear() + '', m: this.setZero(time.getMonth() + 1), d: this.setZero(time.getDate()), h: this.setZero(time.getHours()), i: This.setzero (time.getminutes ())} return obj}, setZero(value) {return Number(value) < 10? '0' + value : String(value) }Copy the code

3. Customize defaultInfo to show the time in your life for easy use. Such as range (month 1-12, hour 0-23, minute 0-59), big month time (1, 3, 5, 7, 8, 10, 12), days (divided by month and year)

LimitInfo: {minM: 1, maxM: 12, minD: 1, maxD: 31, minH: 0, maxH: 23, minI: 0, maxI: }, // bigDaysMonth: [1, 3, 5, 7, 8, 10, 12], // daysInfo: {isBigMonth: 31, isLitMonth: 30, isLeapYearFeb: 29, isCommonYearFeb: 28 } }Copy the code

4. The daily list is the most special, relating to the year and month, so it is extracted and calculated separately.

GetDays (year, month) { let y = Number(year) let m = Number(month) let bigDaysMonth = defaultInfo.bigDaysMonth let daysInfo = Defaultinfo.daysinfo let days = 0 if (m === 2) {// Leap year 29 days in February 28 days = (y % 4 == 0 && y % 100! == 0 || y % 400 == 0) ? daysInfo.isLeapYearFeb : Daysinfo.iscommonyearfeb} else if (bigdaysmonth.includes (m)) {// daysInfo.isbigMonth} else {// daysInfo.isBigMonth 30 days days = daysInfo.isLitMonth } return days },Copy the code

Set the columns of the multi-column selector

In picker scrolling, the boundary position of both ends (minTime, maxTime) is critical. For example, the original month is 1-12, but if the current month is 2022-3-14 to 2022-11-25, the minimum value of the 2022 month list should be 3 instead of 1, and the maximum value should be 11 instead of 12.

In light of the above, it becomes important to analyze whether the upper layer is at the boundary and whether you are at the boundary. (The upper layer, according to Y-M-D-H-I, for example, is the year and month)

In the implementation process, I choose setYear->setMonth->setDay->setHour->setMin processing method. Each method has the same idea:

1. Check whether the current item is in limit

// set the current value and the limit value getInfo(key, val) { currentInfo[key] = val let value = Number(val) let min = Number(minInfo[key]) let max = Number(maxInfo[key]) return { min: min, max: max, isMin: value === min, isMax: value === max } }Copy the code

2. Check whether all upper levels of the current item are limits

3. Determine the value range of the current column and scope according to the above two points

// Let scopeMin = upperLimit. IsMin? info.min : limitInfo.minM let scopeMax = upperLimit.isMax ? info.max : limitInfo.maxM let scope = this.getScopeArr(scopeMin, scopeMax) let index = scope.indexOf(value)Copy the code

4. Calculate whether the current item is within scope. If not, the current item will change. After obtaining the new index, redetermine whether the current item is at the scope boundary and save the state of the limit.

// If the current value is not in the range as a result of the change in the range, take the smallest value and the largest value. CheckInScope (key, index, value, scope, min, Max, isMin, isMax) { let newIsMin = isMin let newIsMax = isMax let newIndex = index if (index === -1) { newIndex = Number(value) < Number(scope[0]) ? Zero: scope.length - 1 currentInfo[key] = scope[newIndex] newIsMin = Number(scope[newIndex]) === min newIsMax = Number(scope[newIndex]) === max } return { index: newIndex, isMin: newIsMin, isMax: newIsMax } }Copy the code

Through the above operations, you can set the display contents of the five columns.

Write in the last

This is actually not optimal, because when a column rolls, you have to compute the lower layer behind it, even though the lower layer doesn’t need to change. For example, if the boundary is 2016-3-21 17:32 to 2025-12-14 07:12, and the current is 2022-3-14 17:32, I scroll the first column to 2023, and all the lower columns do not need to change, but all the calculations have been made.

A better approach is to determine whether you need to calculate before you do, and leave it at that.

Change it when you have time hahaha.

Component source code here, need to look at