当前位置:网站首页>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~
边栏推荐
- 法向量点云旋转
- PHP book borrowing management system, with complete functions, supports user foreground management and background management, and supports the latest version of PHP 7 x. Database mysql
- How to display √ 2 on the command line terminal ̅? This is actually a blog's Unicode test article
- 2022-2028 global industrial gasket plate heat exchanger industry research and trend analysis report
- China battery grade manganese sulfate Market Forecast and strategic consulting report (2022 Edition)
- Golang defer
- After unplugging the network cable, does the original TCP connection still exist?
- Analysis report on the production and marketing demand and investment forecast of tellurium dioxide in the world and China Ⓣ 2022 ~ 2027
- Global and Chinese trisodium bicarbonate operation mode and future development forecast report Ⓢ 2022 ~ 2027
- Ultimate bug finding method - two points
猜你喜欢
PHP student achievement management system, the database uses mysql, including source code and database SQL files, with the login management function of students and teachers
Markdown syntax
How to batch change file extensions in win10
pcl::fromROSMsg报警告Failed to find match for field ‘intensity‘.
Daughter love in lunch box
C # use gdi+ to add text to the picture and make the text adaptive to the rectangular area
You can see the employment prospects of PMP project management
Reload CUDA and cudnn (for tensorflow and pytorch) [personal sorting summary]
Log cannot be recorded after log4net is deployed to the server
How should PMP learning ideas be realized?
随机推荐
自动化的优点有哪些?
2022-2028 global seeder industry research and trend analysis report
【leetcode】29. Divide two numbers
Get the source code in the mask with the help of shims
【leetcode】540. A single element in an ordered array
PHP student achievement management system, the database uses mysql, including source code and database SQL files, with the login management function of students and teachers
About the for range traversal operation in channel in golang
Problems encountered by scan, scanf and scanln in golang
Function comparison between cs5261 and ag9310 demoboard test board | cost advantage of cs5261 replacing ange ag9310
In depth investigation and Strategic Research Report on China's motion controller Market (2022 Edition)
Implementing expired localstorage cache with lazy deletion and scheduled deletion
Nurse level JDEC addition, deletion, modification and inspection exercise
Mantis creates users without password options
Dynamic analysis and development prospect prediction report of high purity manganese dioxide in the world and China Ⓡ 2022 ~ 2027
Rules for using init in golang
Explain TCP protocol in detail three handshakes and four waves
如何编写单元测试用例
2022-2028 global visual quality analyzer industry research and trend analysis report
2022-2028 global industrial gasket plate heat exchanger industry research and trend analysis report
2022-2028 global elastic strain sensor industry research and trend analysis report