当前位置:网站首页>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~
边栏推荐
- GoLand environment variable configuration
- Reading notes on how to connect the network - hubs, routers and routers (III)
- 什么是uid?什么是Auth?什么是验证器?
- Write a jison parser from scratch (6/10): parse, not define syntax
- Lauchpad x | MODE
- Get the source code in the mask with the help of shims
- 2022-2028 global industry research and trend analysis report on anterior segment and fundus OTC detectors
- Daughter love: frequency spectrum analysis of a piece of music
- China electronic grade sulfur trioxide Market Forecast and investment strategy report (2022 Edition)
- Reading notes on how to connect the network - tcp/ip connection (II)
猜你喜欢
2022-2028 global small batch batch batch furnace industry research and trend analysis report
LeetCode 74. Search 2D matrix
2022-2028 global optical transparency industry research and trend analysis report
2022-2028 global industry research and trend analysis report on anterior segment and fundus OTC detectors
How does idea withdraw code from remote push
26. Delete duplicates in the ordered array (fast and slow pointer de duplication)
el-table单选并隐藏全选框
AMLOGIC gsensor debugging
H5 audio tag custom style modification and adding playback control events
ASP. Net to access directory files outside the project website
随机推荐
Daughter love in lunch box
HMS core helps baby bus show high-quality children's digital content to global developers
如何编写单元测试用例
AMLOGIC gsensor debugging
Simulate EF dbcontext with MOQ - mocking EF dbcontext with MOQ
Four common methods of copying object attributes (summarize the highest efficiency)
PHP is used to add, modify and delete movie information, which is divided into foreground management and background management. Foreground users can browse information and post messages, and backgroun
Explanation of closures in golang
Are there any principal guaranteed financial products in 2022?
Implementing expired localstorage cache with lazy deletion and scheduled deletion
DR6018-CP01-wifi6-Qualcomm-IPQ6010-IPQ6018-FAMILY-2T2R-2.5G-ETH-port-CP01-802-11AX-MU-MIMO-OFDMA
Explanation of for loop in golang
In depth investigation and Strategic Research Report on China's motion controller Market (2022 Edition)
Development trend and market demand analysis report of high purity tin chloride in the world and China Ⓔ 2022 ~ 2027
[C Advanced] file operation (2)
Logstack configuration details -- elasticstack (elk) work notes 020
2022-2028 global gasket plate heat exchanger industry research and trend analysis report
Report on the development trend and prospect trend of high purity zinc antimonide market in the world and China Ⓕ 2022 ~ 2027
Flutter 小技巧之 ListView 和 PageView 的各種花式嵌套
C # use ffmpeg for audio transcoding