目的:
在实际开发中,小程序提供的picker时间选择器无法修改样式,这可能与项目整体的风格不一致,因此借助小程序picker-view实现自定义样式的时间选择器
功能:
支持默认时间,初始值是当天,根据选择的不同年月日限制可选值(因为大小月平年闰年天数不一样)
readme
Props
defaultValue:string(2019-10-15)
默认值:当前时间
Events
cancel:Function
说明:取消时触发
参数:null
confirm:Function
说明:确定时触发
参数:event.detail选中的时间
直接将下面代码复制即可直接使用
js
// components/date_time_picker/index.js
const years = [];
const months = [];
const days = [];
const date = new Date(new Date().getTime() + 24 * 3600 * 1000);
const currentYear = date.getFullYear();
const currentMonth = date.getMonth() + 1;
const currentDay = date.getDate();
// 根据年和月获取当月天数
function getDayNum(year, month) {
return new Date(year, month, 0).getDate();
}
for (let i = currentYear; i <= 2099; i++) {
years.push(i);
}
for (let i = currentMonth; i <= 12; i++) {
months.push(i);
}
for (let i = currentDay; i <= getDayNum(currentYear, currentMonth); i++) {
days.push(i);
}
let selectedYear = currentYear;
let selectedMonth = currentMonth;
let selectedDay = currentDay;
Component({
ready() {
let timeArr = this.data.defaultValue.split('-').map(i => Number(i));
selectedYear = timeArr[0];
selectedMonth = timeArr[1];
selectedDay = timeArr[2];
let months = [];
let days = [];
let monthStartFlag = 1;
let monthEndFlag = 12;
let dayStartFlag = 1;
let datEndFlag = getDayNum(timeArr[0], timeArr[1]);
if (timeArr[0] === currentYear) {
monthStartFlag = currentMonth;
}
if (timeArr[0] === currentYear && timeArr[1] === currentMonth) {
dayStartFlag = currentDay;
}
for (let i = monthStartFlag; i <= monthEndFlag; i++) {
months.push(i);
}
for (let i = dayStartFlag; i <= datEndFlag; i++) {
days.push(i);
}
this.setData({
months,
days
});
let yearIndex = this.data.years.indexOf(timeArr[0]);
let monthIndex = this.data.months.indexOf(timeArr[1]);
let dayIndex = this.data.days.indexOf(timeArr[2]);
this.setData({
yearDefaultIndex: yearIndex,
monthDefaultIndex: monthIndex,
dayDefaultIndex: dayIndex
});
},
properties: {
defaultValue: {
type: String,
value: `${currentYear}-${currentMonth}-${currentDay}`
}
},
data: {
years,
months,
days,
yearDefaultIndex: null,
monthDefaultIndex: null,
dayDefaultIndex: null
},
methods: {
pickerChange: function(ev) {
let _this = this;
let index = ev.detail.value[0];
let type = ev.target.dataset.type;
let typeMap = {
year: function(index) {
let year = _this.data.years[index];
console.log(year, '年');
selectedYear = year;
// 设置月
let monthStartFlag = 1;
let months = [];
if (year === currentYear) {
monthStartFlag = currentMonth;
let monthIndex = null;
let dayIndex = null;
if (selectedMonth <= currentMonth) {
selectedMonth = currentMonth;
monthIndex = 0;
if (selectedDay < currentDay) {
selectedDay = currentDay;
dayIndex = 0;
} else {
dayIndex = selectedDay - currentDay;
}
} else {
monthIndex = selectedMonth - currentMonth;
dayIndex = selectedDay - 1;
}
_this.setData({
monthDefaultIndex: monthIndex,
dayDefaultIndex: dayIndex
});
} else {
setTimeout(() => {
_this.setData({
monthDefaultIndex: selectedMonth - 1,
dayDefaultIndex: selectedDay - 1
});
}, 0);
}
for (let i = monthStartFlag; i <= 12; i++) {
months.push(i);
}
_this.setData({
months
});
// 设置日
let dayStartFlag = 1;
let days = [];
let dayEndFlag = getDayNum(selectedYear, selectedMonth);
if (selectedYear === currentYear && selectedMonth === currentMonth) {
dayStartFlag = currentDay;
}
for (let i = dayStartFlag; i <= dayEndFlag; i++) {
days.push(i);
}
_this.setData({
days
});
},
month: function(index) {
let month = _this.data.months[index];
console.log(month, '月');
selectedMonth = month;
let dayStartFlag = 1;
let days = [];
let dayEndFlag = getDayNum(selectedYear, selectedMonth);
if (selectedYear === currentYear && selectedMonth === currentMonth) {
dayStartFlag = currentDay;
selectedMonth = currentMonth;
selectedDay = currentDay;
_this.setData({
monthDefaultIndex: 0,
dayDefaultIndex: 0
});
} else {
let selectedDayIndex = selectedDay - 1;
setTimeout(() => {
if (selectedDayIndex >= _this.data.days.length) { // 大月最后一天会大于小月
selectedDayIndex = _this.data.days.length - 1;
selectedDay = _this.data.days.slice(-1)[0];
}
_this.setData({
dayDefaultIndex: selectedDayIndex
});
}, 0);
}
for (let i = dayStartFlag; i <= dayEndFlag; i++) {
days.push(i);
}
_this.setData({
days
});
},
day: function(index) {
let day = _this.data.days[index];
console.log(day, '日');
selectedDay = day;
}
};
typeMap[type](index);
},
cancelAction: function() {
this.triggerEvent('cancel');
},
confirmAction: function() {
let year = selectedYear;
let month = selectedMonth;
let day = selectedDay;
if (month < 10) {
month = '0' + month;
}
if (day < 10) {
day = '0' + day;
}
this.triggerEvent('confirm', `${year}-${month}-${day}`);
}
}
});
wxml
<!--components/date_time_picker/index.wxml-->
<view class="picker-wrapper">
<view class="picker-toolbar border-bottom">
<text class="cancel" catch:tap="cancelAction">取消</text>
<text class="confirm" catch:tap="confirmAction">确定</text>
</view>
<view class="picker-item-wrapper">
<picker-view value="{{[yearDefaultIndex]}}" class="picker-item-year" indicator-style="height: 40px;" bindchange="pickerChange" data-type="year">
<picker-view-column>
<view wx:for="{{years}}" wx:key="index" class="picker-item-value">{{item}}年</view>
</picker-view-column>
</picker-view>
<picker-view value="{{[monthDefaultIndex]}}" class="picker-item-month" indicator-style="height: 40px;" bindchange="pickerChange" data-type="month">
<picker-view-column>
<view wx:for="{{months}}" wx:key="index" class="picker-item-value">{{item}}月</view>
</picker-view-column>
</picker-view>
<picker-view value="{{[dayDefaultIndex]}}" class="picker-item-day" indicator-style="height: 40px;" bindchange="pickerChange" data-type="day">
<picker-view-column>
<view wx:for="{{days}}" wx:key="index" class="picker-item-value">{{item}}日</view>
</picker-view-column>
</picker-view>
</view>
</view>
/* components/date_time_picker/index.wxss */
@keyframes popupTitle {
from {
bottom: 0;
}
to {
bottom: 40%;
}
}
@keyframes popup {
from {
bottom: -40%;
}
to {
bottom: 0rpx;
}
}
.picker-wrapper {
z-index: 999;
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
}
.picker-wrapper .picker-toolbar {
background-color: white;
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 48px;
display: flex;
align-items: center;
font-size: 32rpx;
justify-content: space-between;
padding: 0 32rpx;
animation: popupTitle 0.4s normal forwards;
}
.picker-wrapper .picker-toolbar .confirm {
color: #006EFF;
}
.picker-wrapper .picker-item-wrapper {
display: flex;
background-color: white;
position: absolute;
right: 0;
bottom: -40%;
left: 0;
height: 40%;
animation: popup 0.4s normal forwards;
}
.picker-wrapper .picker-item-year,
.picker-item-month,
.picker-item-day {
flex: 1;
}
.picker-wrapper .picker-item-year,
.picker-item-month,
.picker-item-day .picker-item-value {
text-align: center;
line-height: 40px;
}