当前位置:网站首页>Write a mobile date selector component by yourself
Write a mobile date selector component by yourself
2022-07-04 09:35:00 【Dandelion_ drq】
List of articles
background
The component written in this article is based on uni-app Under the framework of , But in fact, the framework is not important , It's all the same .
Some students may ask ,uni-app It doesn't exist in itself picker,mode=time Is the time selector when , Why write one by yourself ? That's because our product boss said , Don't fix it at the bottom to pop up the selected , Want to nest in the page filter , Because considering interaction blabla Of …… I thought about it , ok , Give time to say everything , Let's build a wheel by ourselves ~
Effect demonstration
Let's see the effect first ~
- Full functionality

- Year month day mode

- Year month day hour minute second mode

- Month month mode

Ideas
Before starting to work, first brush your mind .
The date filter interaction on the mobile end is more common, which is multi column scrolling , So we can use picker-view To achieve . In addition to basic interaction , The point that components need to pay attention to is the correlation between month, year and day , such as 1 Monthly 31 God ,4 Month is 30 God , Leap year 2 Month is 29 God wait for this , That is, the month, year and day need to be interrelated and dynamic . In addition, you can add the maximum and minimum time range for supporting configuration , Support switching between different time modes ( For example, mm / DD / yyyy / years / Mm / DD / yyyy HHM / S ) etc. .
The main functions of a commonly used date selector component are the above .
For the full code, see :https://github.com/Dandelion-drq/uniapp-datetime-picker
Welcome to my favorite friend star Ha ~
Realization
1. picker-view Realize basic interaction
First encapsulate a multi column scrolling selection component that accepts multiple arrays , It is convenient to support different date mode switching later .
<template>
<picker-view class="picker-view" :value="indexArr" @change="onChange">
<picker-view-column class="picker-view-column" v-for="(col, colIdx) in columns" :key="colIdx">
<view v-for="(item, idx) in col" :key="idx">{
{ item }}</view>
</picker-view-column>
</picker-view>
</template>
<script src="./index.js"></script>
<style lang="css" scoped src="./index.css"></style>
.picker-view {
height: 356rpx;
}
.picker-view-column {
font-size: 14px;
line-height: 34px;
text-align: center;
color: #333;
}
export default {
data() {
return {
};
},
props: {
// All column option data
columns: {
type: Array,
default: () => []
},
// The default selected value array for each column , The first item is selected by default
selectVals: {
type: Array,
default: () => []
}
},
computed: {
// Index of selected items in each column , When the default selection value changes, this value also changes
indexArr: {
// Multidimensional arrays , Deep monitoring
cache: false,
get() {
// console.log('indexArr', this.selectVals, this.columns);
if (this.selectVals.length > 0) {
return this.columns.map((col, cIdx) => {
return col.findIndex((i) => i == this.selectVals[cIdx]);
});
} else {
return [].fill(0, 0, this.columns.length);
}
}
}
},
methods: {
onChange(e) {
const {
value } = e.detail;
// console.log('pickerview change ', value, this.columns);
let ret = this.columns.map((item, index) => {
let idx = value[index];
if (idx < 0) {
idx = 0;
}
if (idx > item.length - 1) {
idx = item.length - 1;
}
return item[idx];
});
// console.log(' Selected value ', ret);
this.$emit('onChange', {
value: ret
});
}
}
};
2. Dynamic configuration of year, month and day, and support the maximum and minimum dates
The year is relatively simple , It is good to generate an array from the configured minimum date year to the maximum date year . Pay attention to the month when the selected year happens to be the smallest / The year of the maximum optional date , The month should start from the smallest / The maximum optional date starts / end , Other months are 1~12. First, list the number of days per person in a normal year , Then pay attention to leap years 2 Month is 29 God , Also, like the month, it should be noted that if the selected year and month happen to be the smallest / The year, month and hour of the maximum optional date , From the smallest / The maximum optional date starts / end . The same goes for hours, minutes and seconds .
<template>
<view class="datetime-picker">
<CustomPickerView :columns="dateConfig" :selectVals="selectVals" @onChange="onChangePickerValue" />
</view>
</template>
<script src="./index.js"></script>
import CustomPickerView from '../customPickerView/index.vue';
import DateUtil from '../dateTimePicker/dateUtil';
export default {
components: {
CustomPickerView
},
data() {
return {
selectYear: new Date().getFullYear(),
selectMonth: new Date().getMonth() + 1, // Selected month ,1~12
selectDay: new Date().getDate(),
selectHour: new Date().getHours(),
selectMinute: new Date().getMinutes(),
selectSecond: new Date().getSeconds()
};
},
props: {
// Optional minimum date , Default ten years ago
minDate: {
type: String,
default: ''
},
// Optional maximum date , Default ten years later
maxDate: {
type: String,
default: ''
}
},
computed: {
minDateObj() {
let minDate = this.minDate;
if (minDate) {
if (this.mode == 2 && minDate.replace(/\-/g, '/').split('/').length == 2) {
// When the date mode is year / month, it may be transmitted minDate yes 2022-02 This format , stay ios Next new Date Will report a mistake , Add the date part to make it compatible
minDate += '-01';
}
return new Date(DateUtil.handleDateStr(minDate));
} else {
// No minimum date is sent , Default ten years ago
minDate = new Date();
minDate.setFullYear(minDate.getFullYear() - 10);
return minDate;
}
},
maxDateObj() {
let maxDate = this.maxDate;
if (maxDate) {
if (this.mode == 2 && maxDate.replace(/\-/g, '/').split('/').length == 2) {
// When the date mode is year / month, it may be transmitted maxDate yes 2022-02 This format , stay ios Next new Date Will report a mistake , Add the date part to make it compatible
maxDate += '-01';
}
return new Date(DateUtil.handleDateStr(maxDate));
} else {
// No minimum date is sent , Default ten years later
maxDate = new Date();
maxDate.setFullYear(maxDate.getFullYear() + 10);
return maxDate;
}
},
years() {
let years = [];
let minYear = this.minDateObj.getFullYear();
let maxYear = this.maxDateObj.getFullYear();
for (let i = minYear; i <= maxYear; i++) {
years.push(i);
}
return years;
},
months() {
let months = [];
let minMonth = 1;
let maxMonth = 12;
// If the selected year happens to be the year of the minimum optional date , The month should start from the month of the minimum date
if (this.selectYear == this.minDateObj.getFullYear()) {
minMonth = this.minDateObj.getMonth() + 1;
}
// If the selected year happens to be the year of the maximum optional date , That month will end in the month of the maximum date
if (this.selectYear == this.maxDateObj.getFullYear()) {
maxMonth = this.maxDateObj.getMonth() + 1;
}
for (let i = minMonth; i <= maxMonth; i++) {
months.push(i);
}
return months;
},
days() {
// In a year 12 The number of days of each month
let monthDaysConfig = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
// Leap year 2 Monthly 29 God
if (this.selectMonth == 2 && this.selectYear % 4 == 0) {
monthDaysConfig[1] = 29;
}
let minDay = 1;
let maxDay = monthDaysConfig[this.selectMonth - 1];
if (this.selectYear == this.minDateObj.getFullYear() && this.selectMonth == this.minDateObj.getMonth() + 1) {
minDay = this.minDateObj.getDate();
}
if (this.selectYear == this.maxDateObj.getFullYear() && this.selectMonth == this.maxDateObj.getMonth() + 1) {
maxDay = this.maxDateObj.getDate();
}
let days = [];
for (let i = minDay; i <= maxDay; i++) {
days.push(i);
}
return days;
},
hours() {
let hours = [];
let minHour = 0;
let maxHour = 23;
if (
this.selectYear == this.minDateObj.getFullYear() &&
this.selectMonth == this.minDateObj.getMonth() + 1 &&
this.selectDay == this.minDateObj.getDate()
) {
minHour = this.minDateObj.getHours();
}
if (
this.selectYear == this.maxDateObj.getFullYear() &&
this.selectMonth == this.maxDateObj.getMonth() + 1 &&
this.selectDay == this.maxDateObj.getDate()
) {
maxHour = this.maxDateObj.getHours();
}
for (let i = minHour; i <= maxHour; i++) {
hours.push(i);
}
return hours;
},
minutes() {
let mins = [];
let minMin = 0;
let maxMin = 59;
if (
this.selectYear == this.minDateObj.getFullYear() &&
this.selectMonth == this.minDateObj.getMonth() + 1 &&
this.selectDay == this.minDateObj.getDate() &&
this.selectHour == this.minDateObj.getHours()
) {
minMin = this.minDateObj.getMinutes();
}
if (
this.selectYear == this.maxDateObj.getFullYear() &&
this.selectMonth == this.maxDateObj.getMonth() + 1 &&
this.selectDay == this.maxDateObj.getDate() &&
this.selectHour == this.maxDateObj.getHours()
) {
maxMin = this.maxDateObj.getMinutes();
}
for (let i = minMin; i <= maxMin; i++) {
mins.push(i);
}
return mins;
},
seconds() {
let seconds = [];
let minSecond = 0;
let maxSecond = 59;
if (
this.selectYear == this.minDateObj.getFullYear() &&
this.selectMonth == this.minDateObj.getMonth() + 1 &&
this.selectDay == this.minDateObj.getDate() &&
this.selectHour == this.minDateObj.getHours() &&
this.selectMinute == this.minDateObj.getMinutes()
) {
minSecond = this.minDateObj.getSeconds();
}
if (
this.selectYear == this.maxDateObj.getFullYear() &&
this.selectMonth == this.maxDateObj.getMonth() + 1 &&
this.selectDay == this.maxDateObj.getDate() &&
this.selectHour == this.maxDateObj.getHours() &&
this.selectMinute == this.maxDateObj.getMinutes()
) {
maxSecond = this.maxDateObj.getSeconds();
}
for (let i = minSecond; i <= maxSecond; i++) {
seconds.push(i);
}
return seconds;
}
}
}
// DateUtil.js
/** * Date time format * @param {Date} date Date object to format * @param {String} fmt Formatted string ,eg:YYYY-MM-DD HH:mm:ss * @returns Formatted date string */
function formatDate(date, fmt) {
if (typeof date == 'string') {
date = new Date(handleDateStr(date));
}
var o = {
'M+': date.getMonth() + 1, // month
'd+': date.getDate(), // Japan
'D+': date.getDate(), // Japan
'H+': date.getHours(), // Hours
'h+': date.getHours(), // Hours
'm+': date.getMinutes(), // branch
's+': date.getSeconds(), // second
'q+': Math.floor((date.getMonth() + 3) / 3), // quarter
S: date.getMilliseconds() // millisecond
};
if (/([y|Y]+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').slice(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).slice(('' + o[k]).length));
}
}
return fmt;
}
/** * Processing time string , compatible ios Next new Date() return NaN problem * @param {*} dateStr Date string * @returns */
function handleDateStr(dateStr) {
return dateStr.replace(/\-/g, '/');
}
/** * Date of judgment 1 Is it on the date 2 Before , That is, the date 1 Less than date 2 * @param {Date} date1 * @param {Date} date2 * @returns */
function isBefore(date1, date2) {
if (typeof date1 == 'string') {
date1 = new Date(handleDateStr(date1));
}
if (typeof date2 == 'string') {
date2 = new Date(handleDateStr(date2));
}
return date1.getTime() < date2.getTime();
}
/** * Date of judgment 1 Is it on the date 2 after , That is, the date 1 Greater than date 2 * @param {Date} date1 * @param {Date} date2 * @returns */
function isAfter(date1, date2) {
if (typeof date1 == 'string') {
date1 = new Date(handleDateStr(date1));
}
if (typeof date2 == 'string') {
date2 = new Date(handleDateStr(date2));
}
return date1.getTime() > date2.getTime();
}
export default {
formatDate,
handleDateStr,
isBefore,
isAfter
};
3. Support different date modes
Support many different date modes , Including mm / DD / yyyy ( Default )、 years 、 year 、 Mm / DD / yyyy HHM / S . The main processing logic is based on mode The change of , To dynamically generate and transmit to pickerView An array of components , And its default selected value , And notice pickerView Components onChange The processing of events also needs to consider different date patterns .
<template>
<view class="datetime-picker">
<PickerView :columns="dateConfig" :selectVals="selectVals" @onChange="onChangePickerValue" />
</view>
</template>
<script src="./index.js"></script>
<style scoped></style>
{
props: {
// Date mode ,1: Specific date ,2: years ,3: year ,4: Mm / DD / yyyy HHM / S
mode: {
type: Number,
default: 1
},
// The default selected date ( Note that it should correspond to the date pattern )
defaultDate: {
type: String,
default: ''
}
}
computed: {
// Pass to pickerView An array of components , according to mode To generate different data
dateConfig() {
if (this.mode == 2) {
// Month month mode
let years = this.years.map((y) => y + ' year ');
let months = this.months.map((m) => m + ' month ');
return [years, months];
} else if (this.mode == 3) {
// Only year mode
let years = this.years.map((y) => y + ' year ');
return [years];
} else if (this.mode == 4) {
// Year month day hour minute second mode
let years = this.years.map((y) => y + ' year ');
let months = this.months.map((m) => m + ' month ');
let days = this.days.map((d) => d + ' Japan ');
let hours = this.hours.map((h) => h + ' when ');
let minutes = this.minutes.map((m) => m + ' branch ');
let seconds = this.seconds.map((s) => s + ' second ');
return [years, months, days, hours, minutes, seconds];
} else {
// Default , Year month day mode
let years = this.years.map((y) => y + ' year ');
let months = this.months.map((m) => m + ' month ');
let days = this.days.map((d) => d + ' Japan ');
return [years, months, days];
}
},
// pickerView The default value is , according to mode To change the value
selectVals() {
if (this.mode == 2) {
return [this.selectYear + ' year ', this.selectMonth + ' month '];
} else if (this.mode == 3) {
return [this.selectYear + ' year '];
} else if (this.mode == 4) {
return [
this.selectYear + ' year ',
this.selectMonth + ' month ',
this.selectDay + ' Japan ',
this.selectHour + ' when ',
this.selectMinute + ' branch ',
this.selectSecond + ' second '
];
} else {
return [this.selectYear + ' year ', this.selectMonth + ' month ', this.selectDay + ' Japan '];
}
}
},
methods: {
onChangePickerValue(e) {
const {
value } = e;
// console.log('onChangePickerValue', value);
if (this.mode == 2 && value[0] && value[1]) {
// Month month mode
this.selectYear = Number(value[0].replace(' year ', ''));
this.selectMonth = Number(value[1].replace(' month ', ''));
} else if (this.mode == 3 && value[0]) {
// Only year mode
this.selectYear = Number(value[0].replace(' year ', ''));
} else if (this.mode == 4 && value[0] && value[1] && value[2] != '' && value[3] && value[4] && value[5]) {
// Year month day hour minute second mode
this.selectYear = Number(value[0].replace(' year ', ''));
this.selectMonth = Number(value[1].replace(' month ', ''));
this.selectDay = Number(value[2].replace(' Japan ', ''));
this.selectHour = Number(value[3].replace(' when ', ''));
this.selectMinute = Number(value[4].replace(' branch ', ''));
this.selectSecond = Number(value[5].replace(' second ', ''));
} else if (value[0] && value[1] && value[2]) {
// Default , Year month day mode
this.selectYear = Number(value[0].replace(' year ', ''));
this.selectMonth = Number(value[1].replace(' month ', ''));
this.selectDay = Number(value[2].replace(' Japan ', ''));
} else {
// Other situations may be pickerView There is a problem with the returned data , Don't deal with
console.log('onChangePickerValue Other situations ');
return;
}
let formatTmpl = 'YYYY-MM-DD';
if (this.mode == 2) {
formatTmpl = 'YYYY-MM';
} else if (this.mode == 3) {
formatTmpl = 'YYYY';
} else if (this.mode == 4) {
formatTmpl = 'YYYY-MM-DD HH:mm:ss';
}
this.$emit(
'onChange',
DateUtil.formatDate(
new Date(`${
this.selectYear}/${
this.selectMonth}/${
this.selectDay} ${
this.selectHour}:${
this.selectMinute}:${
this.selectSecond}`),
formatTmpl
)
);
}
}
}
Completed the above 3 spot , The date selector component is written , Complete code and use demo see :https://github.com/Dandelion-drq/uniapp-datetime-picker
Welcome to my favorite friend star~
边栏推荐
- lolcat
- ASP. Net to access directory files outside the project website
- Implementing expired localstorage cache with lazy deletion and scheduled deletion
- 法向量点云旋转
- Reading notes of how the network is connected - understanding the basic concepts of the network (I)
- H5 audio tag custom style modification and adding playback control events
- Research and investment strategy report of China's electronic hydrogen peroxide industry (2022 Edition)
- How should PMP learning ideas be realized?
- 2022-2028 global tensile strain sensor industry research and trend analysis report
- Solution to null JSON after serialization in golang
猜你喜欢

H5 audio tag custom style modification and adding playback control events

Dede plug-in (multi-function integration)

C # use gdi+ to add text with center rotation (arbitrary angle)

Explain TCP protocol in detail three handshakes and four waves

Nurse level JDEC addition, deletion, modification and inspection exercise
自动化的优点有哪些?

165 webmaster online toolbox website source code / hare online tool system v2.2.7 Chinese version

Opencv environment construction (I)

【LeetCode 42】501. Mode in binary search tree

2022-2028 global intelligent interactive tablet industry research and trend analysis report
随机推荐
《网络是怎么样连接的》读书笔记 - 集线器、路由器和路由器(三)
Opencv environment construction (I)
Implementing expired localstorage cache with lazy deletion and scheduled deletion
In depth investigation and Strategic Research Report on China's motion controller Market (2022 Edition)
《网络是怎么样连接的》读书笔记 - Tcp/IP连接(二)
Reading notes on how to connect the network - hubs, routers and routers (III)
AMLOGIC gsensor debugging
Basic data types in golang
26. Delete duplicates in the ordered array (fast and slow pointer de duplication)
Pueue data migration from '0.4.0' to '0.5.0' versions
2022-2028 global industrial gasket plate heat exchanger industry research and trend analysis report
DR6018-CP01-wifi6-Qualcomm-IPQ6010-IPQ6018-FAMILY-2T2R-2.5G-ETH-port-CP01-802-11AX-MU-MIMO-OFDMA
H5 audio tag custom style modification and adding playback control events
How do microservices aggregate API documents? This wave of show~
Launpad | Basics
What is uid? What is auth? What is a verifier?
MySQL foundation 02 - installing MySQL in non docker version
C # use gdi+ to add text to the picture and make the text adaptive to the rectangular area
Dede plug-in (multi-function integration)
Problems encountered by scan, scanf and scanln in golang