当前位置:网站首页>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~
边栏推荐
- Dede plug-in (multi-function integration)
- 2022-2028 global industrial gasket plate heat exchanger industry research and trend analysis report
- 《网络是怎么样连接的》读书笔记 - FTTH
- Launchpad x | mode
- el-table单选并隐藏全选框
- Golang defer
- How do microservices aggregate API documents? This wave of show~
- Global and Chinese markets of water heaters in Saudi Arabia 2022-2028: Research Report on technology, participants, trends, market size and share
- GoLand environment variable configuration
- Trees and graphs (traversal)
猜你喜欢
2022-2028 global small batch batch batch furnace industry research and trend analysis report
How do microservices aggregate API documents? This wave of show~
2022-2028 global industry research and trend analysis report on anterior segment and fundus OTC detectors
Svg image quoted from CodeChina
Nurse level JDEC addition, deletion, modification and inspection exercise
回复评论的sql
2022-2028 global strain gauge pressure sensor industry research and trend analysis report
Jianzhi offer 09 realizes queue with two stacks
After unplugging the network cable, does the original TCP connection still exist?
Solve the problem of "Chinese garbled MySQL fields"
随机推荐
Lauchpad x | MODE
Mantis creates users without password options
ASP. Net to access directory files outside the project website
el-table单选并隐藏全选框
Flutter tips: various fancy nesting of listview and pageview
China battery grade manganese sulfate Market Forecast and strategic consulting report (2022 Edition)
lolcat
How to batch change file extensions in win10
Research Report on the development trend and Prospect of global and Chinese zinc antimonide market Ⓚ 2022 ~ 2027
Investment analysis and prospect prediction report of global and Chinese high purity tin oxide Market Ⓞ 2022 ~ 2027
Opencv environment construction (I)
UML sequence diagram [easy to understand]
How to display √ 2 on the command line terminal ̅? This is actually a blog's Unicode test article
Target detection -- intensive reading of yolov3 paper
Service call feign of "micro service"
Launchpad x | mode
Global and Chinese market of air fryer 2022-2028: Research Report on technology, participants, trends, market size and share
Leetcode (Sword finger offer) - 35 Replication of complex linked list
Global and Chinese trisodium bicarbonate operation mode and future development forecast report Ⓢ 2022 ~ 2027
HMS core helps baby bus show high-quality children's digital content to global developers