微信自带的组件只有时间和日期,分开的的组件,所以自己封装了一个时间日期联动的组件
一、组件需求
- 可以传入初始时间,否则就是当前时间
- 可以选择日期时间
- 可以做一些限制,比如选择年份的范围,是否可以选择当前日期之后的日期
二、实现思路
2.1使用小程序组件进行组装
结构如下
2.2 难点
个人觉得时间日期的唯一一个坑点是,2月份的瑞年天数变动,实现的方案是,以前在android踩过很多坑,直接把所有数据都直接引入,这样很不便捷,幸好,小程序已经封装好了很多功能,比如滑动监听,让简单化的实现成为可能:
解决方案如下:
在动态的获取中,监听年份和月份的变化,只有当年份和月份发生变化时,才触发更新天数,其中除了2月份,其他的天数均直接写四,代码如下:
_getMonthDays(year,month) {
let that = this;
// 优化算法,只有当月份是2月份的时候,才会动态加载
if ([1, 3, 5, 7, 8, 10, 12].includes(month)) {
return 31;
} else if ([4, 6, 9, 11].includes(month)) {
return 30;
} else {
return new Date(year, month,0).getDate(); // 这个技巧是,获取上月最后一天是上月的第多少天,比如,我们想获取2月份的天数,就传入3月份的第零0天,因为天数是从1开始,那么0就是2月份的最后以一天
}
},
提示一下,月份是从0开始的哦
三、实现
3.1 布局文件
为了实用和美观,我们不仅要实现功能,还要有背景遮罩,定位的底部,先上布局文件.wxml
<view class='mask' hidden="{{!showDatePick}}">
<view class='content'>
<view class='header'>
<view class='cancle' bindtap='_cancle'>取消</view>
<view class='confirm' bindtap='_confirm'>确定</view>
</view>
<picker-view
indicator-class='select'
class='pick-view'
value="{{currentDate}}"
bindchange="_bindChange">
<picker-view-column>
<view class="item" wx:for="{{yearList}}" wx:key="{{index}}">{{item}}年</view>
</picker-view-column>
<picker-view-column>
<view class="item" wx:for="{{monthList}}" wx:key="{{index}}">{{item}}月</view>
</picker-view-column>
<picker-view-column>
<view class="item" wx:for="{{dateList}}" wx:key="{{index}}">{{item}}日</view>
</picker-view-column>
<picker-view-column>
<view class="item" wx:for="{{hourList}}" wx:key="{{index}}">{{item}}时</view>
</picker-view-column>
<picker-view-column>
<view class="item" wx:for="{{minusList}}" wx:key="{{index}}">{{item}}分</view>
</picker-view-column>
</picker-view>
</view>
</view>
应该能看懂,具体的wxss文件可以到github下载查看,最后会贴上demo
3.2 js核心代码
// components/aydk_date_ymdhm/aydk_date_ymdhm.js
const MAX_REGION_YEAR = 50;// 默认年的区间是当前时间的开始和结束50年
Component({
/**
* 组件的属性列表
*/
properties: {
// isAfter:{ // 是否允许选择当前日期之后的日期 之后优化再做,谁有兴趣可以优化一下
// type:Boolean,
// value: false
// },
initDate:{ //初始化时间,格式是string,可以被new Date(param) 初始化的时间
type:String,
value: new Date().getTime()
},
showDatePick:{
type: Boolean,
value: false,
observer: function (newVal, oldVal) {
// 属性值变化时执行
let that = this;
if(newVal){
that._initCurrentDate();
}
}
}
},
/**
* 组件的初始数据
*/
data: {
showDatePick: false,
currentDate: [0,0,0,0,0],
yearList: [],
monthList: [],
dateList: [],
hourList: [], //代码初始化
minusList: [] // 代码初始化
},
//初始化写到挂载事件中,不能写到create钩子里
attached() {
let that = this;
that._initCurrentDate();
that._initHour();
that._initMinus();
},
// 为了保证数据初始化完成
ready() {
let that = this;
that.setData({
currentDate: that.data.currentDate
})
},
/**
* 组件的方法列表
*/
methods: {
/**
* 函数调用,可选
* @date 初始化时间,可选
*/
showDate(date){
let that = this;
if(date) {
this.initDate = date;
}
that._initCurrentDate();
that.setData({
showDatePick: true
})
},
/**
* 初始化开始时间
*/
_initCurrentDate() {
let that = this;
let now = new Date(that.data.initDate);
that.data.currentDate[1] = now.getMonth(); // 初始化月份
that.data.currentDate[2] = now.getDate()-1; // 初始化天
that.data.currentDate[3] = now.getHours(); // 初始化小时
that.data.currentDate[4] = now.getMinutes(); // 初始化分钟
that._initYear(now.getFullYear()); // 初始化年
that._initMonth(); // 初始化月份
that._initDate(now.getFullYear(), now.getMonth()+1); // 初始化天
},
/**
* 初始化年滚动
* 参数为当前年
*/
_initYear(year) {
let that = this;
that.data.yearList = [];
for (let orgion = 0; orgion < MAX_REGION_YEAR; orgion++){
if(year-orgion>=1970){
that.data.yearList.unshift(year-orgion);
}
that.data.yearList.push(orgion+year+1);// 当前年份已经push了
}
that.data.currentDate[0] = that.data.yearList.indexOf(year);
that.setData({
currentDate: that.data.currentDate,
yearList: that.data.yearList
})
},
_initMonth(){
let that = this;
that.setData({
monthList:Array.from(Array(12), (v,k)=>(k+1))
})
},
_initDate(year,month) {
let that = this;
that.setData({
dateList: Array.from(Array(that._getMonthDays(year,month)), (v, k) => (k + 1))
})
},
_initHour() {
let that = this;
that.setData({
hourList: Array.from(Array(24), (v, k) => k)
})
},
_initMinus() {
let that = this;
that.setData({
minusList: Array.from(Array(60), (v, k) => k)
})
},
_getMonthDays(year,month) {
let that = this;
// 优化算法,只有当月份是2月份的时候,才会动态加载
if ([1, 3, 5, 7, 8, 10, 12].includes(month)) {
return 31;
} else if ([4, 6, 9, 11].includes(month)) {
return 30;
} else {
return new Date(year, month,0).getDate();
}
},
_bindChange(e){
let that = this;
if (e.detail.value[0] !== that.data.currentDate[0] || e.detail.value[1] !== that.data.currentDate[1]) {
that._initDate(that.data.yearList[e.detail.value[0]], that.data.monthList[e.detail.value[1]]);
}
that.data.currentDate = e.detail.value;
},
_cancle(){
let that = this;
that.setData({
showDatePick: false
})
},
_confirm(){
let that = this;
that.setData({
showDatePick: false
})
that.triggerEvent('getDate', [that.data.yearList[that.data.currentDate[0]], that.data.monthList[that.data.currentDate[1]],that.data.dateList[that.data.currentDate[2]],that.data.hourList[that.data.currentDate[3]],that.data.minusList[that.data.currentDate[4]]]);
}
}
})
3.3 最后上调用代码
//先在json中声明
"usingComponents": {
"date":"../../components/aydk_date_ymdhm/aydk_date_ymdhm"
}
// 使用代码 ,这只是最基本的调用
<date
showDatePick='{{showDatePick}}'
bind:getDate="getDateData">
</date>
四、问题(留给你们)
写的时候为求速度,到快写完发现准备加上点击遮罩关闭组件,但是发现布局设计的不太合理,没办法加,还有就是最后的返回数据,应该可以返回数组和时间,让调用更傻瓜点。
好啦,基本结束啦
五、demo
欢迎加群交流哦