小程序--自定义日期控件(起始时间段选择)
2019-12-05 本文已影响0人
张付东
具体的实现效果如下图所示,思路就是利用picker-view自定义实现,对于这种类型的时间选择器,核心点就是对数据的处理,牵扯到数据的初始化以及数据的传递。
设计稿.png
为了更便捷的引用,本次封装采用组件化的模式,具体如下
组件化.png
1: 在此详谈com-date-picker.js
(1) 初始化日期数据
// 初始化日期模态框数据
let date = new Date();
let years = [];
let months = [];
let days = [];
for (let i = date.getFullYear()-10; i <= (date.getFullYear()+10); i++) {
years.push(String(i))
}
for (let i = 1; i <= 12; i++) {
months.push(String(i))
}
//后面会根据需求动态改变每月的天数,数组
for (let i = 1; i <= 31; i++) {
days.push(String(i))
}
(2) 引用页面传递的参数和该界面所需的参数
properties: {
//开始期间
startAt: {
type: String,
value: "",
observer: "onStartAt"
},
//结束时间
endAt: {
type: String,
value: "",
observer: "onEndAt"
},
isShow: {
type: Boolean,
value: false,
observer: "onDateShow"
}
},
data: {
years: years,
months: months,
days: days,
startValue:[],
endValue:[],
showPicker: false,
tapIndex: "startTime"
},
(3) 处理界面传递的参数
methods: {
onStartAt() {
this.data.startValue = this.getDateArrWithtime(this.data.startAt,years,months,days);
days = this.getTotalDayByMonth(this.data.years[this.data.startValue[0]],this.data.months[this.data.startValue[1]]);
},
onEndAt() {
this.data.endValue = this.getDateArrWithtime(this.data.endAt,years,months,days);
},
onDateShow() {
this.setData({
showPicker: this.data.isShow
});
},
//获取月的总天数--数组
getTotalDayByMonth: function (year, month) {
month = parseInt(month, 10);
var d = new Date(year, month, 0);
let totalDay = d.getDate();
let daySource = [];
for (let i = 1; i <= totalDay; i++) {
daySource.push(String(i))
}
return daySource;
},
//根据时间2019-01-02 得到 ['2019','1','2']
getDateArrWithtime: function (str, years, months, days) => {
let arr = [];
arr = (str).split('-');
arr[0] = years.indexOf(arr[0]);
arr[1] = months.indexOf((arr[1].startsWith('0') ? arr[1].substr(1, arr[1].length) : arr[1]));
arr[2] = days.indexOf((arr[2].startsWith('0') ? arr[2].substr(1, arr[2].length) : arr[2]));
return arr;
}
}
(4) 处理完基本数据之后,进行刷新
lifetimes: {
attached: function () {
this.setData({
days: days,
tapIndex: this.data.tapIndex,
startValue: this.data.startValue,
endValue: this.data.endValue
})
}
},
此时就能够初步显示这个时间选择器
(5) 滚动日期的时候,会动态改变显示的起始日期
methods: {
bindPickerChange(e) {
if (this.data.tapIndex == 'startTime') {
this.data.startValue = e.detail.value;
} else {
this.data.endValue = e.detail.value;
}
this.calculate();
},
calculate() {
if (this.data.tapIndex == "startTime") {
let curYear = this.data.years[this.data.startValue[0]];
let curMonth = this.data.months[this.data.startValue[1]];
let curDay = this.data.days[this.data.startValue[2]];
this.data.startAt = curYear+'-'+(curMonth.length==1 ? ('0'+curMonth):curMonth)+'-'+(curDay.length==1 ? ('0'+curDay):curDay);
this.setData({
days: this.getTotalDayByMonth(curYear,curMonth),
startAt: this.data.startAt
})
} else {
let endCurYear = this.data.years[this.data.endValue[0]];
let endCurMonth = this.data.months[this.data.endValue[1]];
let endCurDay = this.data.days[this.data.endValue[2]];
this.data.endAt = endCurYear+'-'+(endCurMonth.length==1 ? ('0'+endCurMonth):endCurMonth)+'-'+(endCurDay.length==1 ? ('0'+endCurDay):endCurDay);
this.setData({
days: this.getTotalDayByMonth(endCurYear,endCurMonth),
endAt: this.data.endAt,
})
}
}
}
(6) 点击切换其实时间的tab,会通过调用下面的方法进行刷新界面
methods: {
onTapTimeIndex(e) {
this.data.tapIndex = e.currentTarget.dataset.type;
if (this.data.tapIndex == "startTime") {
let curYear = this.data.years[this.data.startValue[0]];
let curMonth = this.data.months[this.data.startValue[1]];
days = this.getTotalDayByMonth(curYear,curMonth);
} else {
let endCurYear = this.data.years[this.data.endValue[0]];
let endCurMonth = this.data.months[this.data.endValue[1]];
days = this.getTotalDayByMonth(endCurYear,endCurMonth);
}
this.setData({
tapIndex: this.data.tapIndex,
startValue:this.data.startValue,
endValue:this.data.endValue,
days: days
})
}
}
(7) 此时基础的数据转换就都实现了,接下来就是要点击完成按钮,将所选择的起始日期传递给所用的界面,具体实现操作如下:
methods: {
onSureClick(e) {
if (new Date(this.data.startAt).getTime() <= new Date(this.data.endAt).getTime()) {
this.triggerEvent('sureclick', {
startAt: this.data.startAt,
endAt: this.data.endAt,
});
} else {
utils.showCommonDialog('开始时间不能晚于结束时间');
}
}
}
(8) 点击蒙版,日期选择器会消失,具体实现操作如下:
methods: {
onTouchmask: function(event) {
this.triggerEvent('onTouchmask', {});
}
}
2: 在此详谈com-date-picker.wxss
@keyframes fade-in {
0% {
top: 1000rpx;
opacity: 0;
}
/*初始状态 透明度为0*/
40% {
top: 1000rpx;
opacity: 0;
}
/*过渡状态 透明度为0*/
100% {
margin-top: 0rpx;
opacity: 1;
}
/*结束状态 透明度为1*/
}
.date-picker {
position: fixed;
top: 0;
left: 0;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
z-index: 999;
animation: fade-in 0.5s ease 1 forwards;
}
.date-picker-mask {
position: fixed;
top: 0;
left: 0;
bottom: 590rpx;
background-color: #353535;
opacity: 0.4;
width: 100%;
z-index: 1000;
}
.date-picker-content {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 590rpx;
border-top-left-radius: 16rpx;
border-top-right-radius: 16rpx;
background-color: #fff;
z-index: 9999;
overflow: hidden;
}
.date-picker-date-content {
position: relative;
display: flex;
height: 160rpx;
width: 750rpx;
}
.date-picker-date-content-image {
position: absolute;
top: 0rpx;
left: 0rpx;
width: 100%;
height: 100%;
}
.date-picker-date-content-bg-left {
position: absolute;
top: 0rpx;
left: 0rpx;
width: 50%;
height: 100%;
}
.date-picker-date-content-bg-right {
position: absolute;
top: 0rpx;
right: 0rpx;
width: 50%;
height: 100%;
}
.date-picker-date-content-title {
position: relative;
color: #333;
font-size: 26rpx;
margin-left: 70rpx;
margin-top: 40rpx;
}
.date-picker-date-content-time {
position: relative;
color: #333;
font-size: 32rpx;
font-weight: bold;
margin-left: 70rpx;
margin-top: 4rpx;
}
.date-picker-content-top {
display: flex;
flex-direction: row;
align-items: center;
height: 80rpx;
justify-content: space-between;
}
.hover-class {
background-color: #e6e6e6;
}
.date-picker-content-line {
background-color: #d3dce6;
height: 1rpx;
width: 100%;
opacity: 0.8;
}
.date-picker-content-cancel {
line-height: 50rpx;
height: 50rpx;
color: #353535;
padding: 10rpx 48rpx;
flex: 1;
font-size: 28rpx
}
.date-picker-content-sure {
line-height: 50rpx;
color: #0096FF;
height: 50rpx;
padding: 10rpx 48rpx;
text-align: right;
flex: 1;
font-size: 28rpx
}
.date-picker-content-center {
display: flex;
flex-direction: row;
align-items: center;
height: 340rpx;
overflow: hidden;
margin-top: 6rpx;
margin-bottom: 6rpx;
justify-content: space-between;
}
.date-picker-content-item {
width: 33.3%;
height: 350rpx;
text-align: center;
}
3: 在此详谈com-date-picker.wxml
<view wx:if="{{showPicker}}" class="date-picker">
<view class="date-picker-mask" catchtouchstart="onTouchmask"></view>
<view class="date-picker-content">
<view class="date-picker-date-content">
<image src="../../../../image/picker_date_header_{{tapIndex=='startTime'?'left':'right'}}.png" class="date-picker-date-content-image"></image>>
<view class="date-picker-date-content-bg-left" bindtouchstart="onTapTimeIndex" data-type="startTime">
<view class="date-picker-date-content-title">开始于</view>
<view class="date-picker-date-content-time">{{startAt}}</view>
</view>
<view class="date-picker-date-content-bg-right" bindtouchstart="onTapTimeIndex" data-type="endTime">
<view class="date-picker-date-content-title">结束于</view>
<view class="date-picker-date-content-time">{{endAt}}</view>
</view>
</view>
<view class='date-picker-content-top'>
<view class="date-picker-content-cancel" ></view>
<view style="color: #666666; font-size: 28rpx">选择日期</view>
<view class="date-picker-content-sure" catchtouchend="onSureClick">完成</view>
</view>
<view class="date-picker-content-line"></view>
<view class="date-picker-content-center">
<picker-view indicator-style="height: 70rpx;" style="width: 100%; height: 360rpx;" value="{{tapIndex==='startTime'?startValue:endValue}}" catchchange="bindPickerChange">
<picker-view-column wx:if="{{years.length > 0}}" class="date-picker-content-item">
<view wx:for="{{years}}" wx:key="{{index}}" style="line-height: 70rpx">{{item}}年</view>
</picker-view-column>
<picker-view-column wx:if="{{months.length > 0}}" class="date-picker-content-item">
<view wx:for="{{months}}" wx:key="{{index}}" style="line-height: 70rpx">{{item}}月</view>
</picker-view-column>
<picker-view-column wx:if="{{days.length > 0}}" class="date-picker-content-item">
<view wx:for="{{days}}" wx:key="{{index}}" style="line-height: 70rpx">{{item}}日</view>
</picker-view-column>
</picker-view>
</view>
</view>
</view>
4: 至此,已经完成了日期选择器组建的封装,接下来介绍该如何引用
(1) 在所需要的index.json里
{
"usingComponents": {
"com-date-picker":"../../core/base/components/com-date-picker/com-date-picker"
}
}
(2): 在所需要的index.js里
datePickerIsShow: false,
startAt: this.getCurrentDate(),
endAt: this.getCurrentDate()
//选择时间
selectDate: function (e) {
this.setData({
datePickerIsShow: true
});
},
//获取当前日期
getCurrentDate: function() {
var now = new Date();
var year = now.getFullYear(); //得到年份
var month = now.getMonth();//得到月份
var date = now.getDate();//得到日期
month = month + 1;
if (month < 10) month = "0" + month;
if (date < 10) date = "0" + date;
var time = year + "-" + month + "-" + date;
return time;
}
(3): 在所需要的index.wxml里
<block wx:if="{{datePickerIsShow}}">
<com-date-picker
id="date-picker"
startAt="{{startAt}}"
endAt="{{endAt}}"
isShow="{{datePickerIsShow}}"
bindsureclick="onDatePickerOnSureClick"
bindonTouchmask="onTouchmask">
</com-date-picker>
</block>
5: 到这里起始日期选择器就完成了,如果在初始化起始日期的时候,想往前推一周,自己在网上找方法即可替换,也可调用如下方法解决
(1) 具体方法(moment.js)
var Moment = function (date) {
var date;
if (date) {
this.date = new Date(date);
} else {
this.date = new Date();
}
return this;
};
Moment.prototype.format = function (format) {
var date = this.date;
// var r= /^(\d{4})-(\d{1,2})-(\d{1,2})$/; //正则表达式 匹配出生日期(简单匹配)
// r.exec('1985-10-15');
// s1=RegExp.$1;s2=RegExp.$2;s3=RegExp.$3;//结果为1985 10 15
if (typeof date === 'string') {
date = this.parse(date);
}
var o = {
"M+": date.getMonth() + 1, //月份
"(d+|D+)": date.getDate(), //日
"(h+|H+)": date.getHours(), //小时
"m+": date.getMinutes(), //分
"s+": date.getSeconds(), //秒
"q+": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
var week = {
"0": "/u65e5",
"1": "/u4e00",
"2": "/u4e8c",
"3": "/u4e09",
"4": "/u56db",
"5": "/u4e94",
"6": "/u516d"
};
if (/(y+|Y+)/.test(format)) {
format = format.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
}
if (/(E+)/.test(format)) {
format = format.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + week[date.getDay() + ""]);
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(format)) {
format = format.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
}
return format;
}
Moment.prototype.parse = function () {
return this.date;
}
//计算两个日期差差
Moment.prototype.differ = function (date) {
var time1 = this.date.getTime();
if (typeof date === 'string')
date = new Date(date);
var time1 = this.date.getTime();
var time2 = date.getTime();
var differ = Math.ceil((time1 - time2) / (1000 * 3600 * 24))
return differ;
}
Moment.prototype.add = function (num, optionType) {
var date = this.date;
if ('day' === optionType) {
date.setDate(date.getDate() + num);
}
if ('month' === optionType) {
date.setMonth(date.getMonth() + num);
}
if ('year' === optionType) {
date.setFullYear(date.getFullYear() + num);
}
this.date = date;
return this;
}
module.exports = function (date) {
return new Moment(date);
}
(2) 如下调用
startAt: Moment(new Date()).add(-6, 'day').format('YYYY-MM-DD'),
endAt: Moment(new Date()).format('YYYY-MM-DD')