当前位置: 首页 > news >正文

微信小程序----日期时间选择器(自定义时间精确到分秒)

目录

页面效果

代码实现 

注意事项


页面效果

代码实现 

js 

Component({/*** 组件的属性列表*/properties: {pickerShow: {type: Boolean,},config: Object,},/*** 组件的初始数据*/data: {pickerReady: false,// pickerShow:true// limitStartTime: new Date().getTime()-1000*60*60*24*30,// limitEndTime: new Date().getTime(),// yearStart:2000,// yearEnd:2100},detached: function () {this.setData({pickerReady: false,});},attached: function () {this.readConfig();this.initPick(this.data.config || null);this.setData({startValue: this.data.startValue,endValue: this.data.endValue,pickerReady: true,});},ready: function () {},/*** 组件的方法列表*/methods: {/*** 读取并处理配置中的时间限制信息* 此函数用于初始化或更新时间选择器的限制范围,以及配置中的其他时间相关参数*/readConfig() {// 获取当前时间的时间戳,最大选的范围let limitEndTime = new Date().getTime();// 计算30天前的时间戳,最小可选择的范围let limitStartTime = new Date().getTime() - 1000 * 60 * 60 * 24 * 30;// 检查是否存在配置信息if (this.data.config) {let conf = this.data.config;// 如果配置中指定了日期限制,当为数字n时,范围是当前时间的最近n天if (typeof conf.dateLimit == "number") {limitStartTime =new Date().getTime() - 1000 * 60 * 60 * 24 * conf.dateLimit;}// 如果配置中指定了最小可选,则将其转换为时间戳if (conf.limitStartTime) {limitStartTime = new Date(conf.limitStartTime.replace(/-/g, "/")).getTime();}// 如果配置中指定了最大可选,则将其转换为时间戳if (conf.limitEndTime) {limitEndTime = new Date(conf.limitEndTime.replace(/-/g, "/")).getTime();}// 设置数据,包括年份范围、结束日期标志、日期限制和时间列的显示状态this.setData({yearStart: conf.yearStart || 2000, // 默认开始年份为2000yearEnd: conf.yearEnd || 2100, // 默认结束年份为2100endDate: conf.endDate || false, // 默认不启用结束日期dateLimit: conf.dateLimit || false, // 默认不设置日期限制hourColumn:conf.column == "hour" ||conf.column == "minute" ||conf.column == "second", // 根据配置决定是否显示小时列minColumn: conf.column == "minute" || conf.column == "second", // 根据配置决定是否显示分钟列secColumn: conf.column == "second", // 根据配置决定是否显示秒列});}// 将时间限制的时间戳格式化数组方便循环let limitStartTimeArr = formatTime(limitStartTime);let limitEndTimeArr = formatTime(limitEndTime);// 更新数据,包括时间限制的时间戳和格式化后的时间数组this.setData({limitStartTime, // 开始时间限制limitStartTimeArr, // 开始时间限制数组limitEndTime, // 结束时间限制limitEndTimeArr, //结束时间限制数组});},//滚动开始handlePickStart: function (e) {this.setData({isPicking: true,});},//滚动结束handlePickEnd: function (e) {this.setData({isPicking: false,});},onConfirm: function () {//滚动未结束时不能确认if (this.data.isPicking) {return;}let startTime = new Date(this.data.startPickTime.replace(/-/g, "/"));let endTime = new Date(this.data.endPickTime.replace(/-/g, "/"));if (startTime <= endTime || !this.data.endDate) {this.setData({startTime,endTime,});let startArr = formatTime(startTime).arr;let endArr = formatTime(endTime).arr;let format0 = function (num) {return num < 10 ? "0" + num : num;};let startTimeBack =startArr[0] +"-" +format0(startArr[1]) +"-" +format0(startArr[2]) +" " +(this.data.hourColumn ? format0(startArr[3]) : "00") +":" +(this.data.minColumn ? format0(startArr[4]) : "00") +":" +(this.data.secColumn ? format0(startArr[5]) : "00");let endTimeBack =endArr[0] +"-" +format0(endArr[1]) +"-" +format0(endArr[2]) +" " +(this.data.hourColumn ? format0(endArr[3]) : "00") +":" +(this.data.minColumn ? format0(endArr[4]) : "00") +":" +(this.data.secColumn ? format0(endArr[5]) : "00");let time = {startTime: startTimeBack,endTime: endTimeBack,};//触发自定义事件this.triggerEvent("setPickerTime", time);this.triggerEvent("hidePicker", {});} else {wx.showToast({icon: "none",title: "时间不合理",});}},hideModal: function () {this.triggerEvent("hidePicker", {});},changeStartDateTime: function (e) {let val = e.detail.value;this.compareTime(val, "start");},changeEndDateTime: function (e) {let val = e.detail.value;this.compareTime(val, "end");},/*** 比较时间是否在指定范围内* @param {Array} val_ 时间数组,包含年、月、日、时、分、秒的数值* @param {string} type 类型指示符,"start"表示开始时间,"end"表示结束时间* @description 该函数用于比较给定的时间是否在系统或用户设定的时间范围内* 根据比较结果,设置开始时间或结束时间*/compareTime(val_, type) {// 将时间数组中的每个元素转换为字符串const val = val_.map((it) => it.toString());// 获取小时、分钟、秒的字符串表示,如果不存在则默认为"00"let h = val[3] ? this.data.HourList[val[3]] : "00";let m = val[4] ? this.data.MinuteList[val[4]] : "00";let s = val[5] ? this.data.SecondList[val[5]] : "00";// 构造完整的时间字符串let time =this.data.YearList[val[0]] +"-" +this.data.MonthList[val[1]] +"-" +this.data.DayList[val[2]] +" " +h +":" +m +":" +s;// 获取系统或用户设定的开始和结束时间let start = this.data.limitStartTime;let end = this.data.limitEndTime;// 将输入的时间字符串转换为时间戳let timeNum = new Date(time.replace(/-/g, "/")).getTime();// 用于存储限制日期的各部分let year, month, day, hour, min, sec, limitDate;let tempArr = [];// 根据不同的条件计算限制日期if (!this.data.dateLimit) {// 如果没有设定日期限制,则直接使用输入的日期limitDate = [this.data.YearList[val[0]],this.data.MonthList[val[1]],this.data.DayList[val[2]],this.data.HourList[val[3]],this.data.MinuteList[val[4]],this.data.SecondList[val[5]],];} else if (type == "start" &&timeNum > new Date(this.data.endPickTime.replace(/-/g, "/")) &&this.data.config.endDate) {// 如果是开始时间且输入时间晚于结束选择时间,则使用结束选择时间limitDate = formatTime(this.data.endPickTime).arr;} else if (type == "end" &&timeNum < new Date(this.data.startPickTime.replace(/-/g, "/"))) {// 如果是结束时间且输入时间早于开始选择时间,则使用开始选择时间limitDate = formatTime(this.data.startPickTime).arr;} else if (timeNum < start) {// 如果输入时间早于系统或用户设定的开始时间,则使用设定的开始时间limitDate = this.data.limitStartTimeArr.arr;} else if (timeNum > end) {// 如果输入时间晚于系统或用户设定的结束时间,则使用设定的结束时间limitDate = this.data.limitEndTimeArr.arr;} else {// 如果输入时间在系统或用户设定的范围内,则直接使用输入的日期limitDate = [this.data.YearList[val[0]],this.data.MonthList[val[1]],this.data.DayList[val[2]],this.data.HourList[val[3]],this.data.MinuteList[val[4]],this.data.SecondList[val[5]],];}// 将限制日期的各部分分配给相应的变量year = limitDate[0];month = limitDate[1];day = limitDate[2];hour = limitDate[3];min = limitDate[4];sec = limitDate[5];// 根据类型指示符设置开始时间或结束时间if (type == "start") {this.setStartDate(year, month, day, hour, min, sec);} else if (type == "end") {this.setEndDate(year, month, day, hour, min, sec);}},/*** 获取指定月份的天数** 此函数根据给定的年份和月份,返回该月份的天数。特别地,对于二月份,* 该函数考虑了闰年的情况,确保返回准确的天数。** @param {number} year - 指定的年份,用于计算二月份的天数是否为29天(闰年)* @param {number} month - 指定的月份,用于确定该月的天数* @returns {number} 返回指定月份的天数*/getDays: function (year, month) {// 定义一个数组,包含除二月外各月份的天数let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];// 如果是二月份if (month === 2) {// 判断是否为闰年,如果是闰年则返回29天,否则返回28天return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0? 29: 28;} else {// 非二月份则直接返回对应月份的天数return daysInMonth[month - 1];}},/*** 初始化选择器* @param {Object} initData - 初始化数据对象* 初始化startTime和endTime,如果传入的initData对象中包含initStartTime和initEndTime属性,* 则使用这些属性值作为时间选择器的初始值,否则使用当前时间作为默认值*/initPick: function (initData) {// 初始化开始时间选择器默认时间(默认为当前时间)const date = initData.initStartTime? new Date(initData.initStartTime.replace(/-/g, "/")): new Date();// 初始化结束时间选择器默认时间 (默认为当前时间)const endDate = initData.initEndTime? new Date(initData.initEndTime.replace(/-/g, "/")): new Date();const startDate = date;// 从date中提取年月日时分秒信息const startYear = date.getFullYear();const startMonth = date.getMonth() + 1;const startDay = date.getDate();const startHour = date.getHours();const startMinute = date.getMinutes();const startSecond = date.getSeconds();// 从endDate中提取年月日时分秒信息const endYear = endDate.getFullYear();const endMonth = endDate.getMonth() + 1;const endDay = endDate.getDate();const endHour = endDate.getHours();const endMinute = endDate.getMinutes();const endSecond = endDate.getSeconds();// 定义各个时间单位的列表let YearList = [];let MonthList = [];let DayList = [];let HourList = [];let MinuteList = [];let SecondList = [];// 设置年份列表,范围从开始年份到结束年份for (let i = this.data.yearStart; i <= this.data.yearEnd; i++) {YearList.push(i);}// 设置月份列表,从1月到12月for (let i = 1; i <= 12; i++) {MonthList.push(i);}// 设置日期列表,从1日到31日for (let i = 1; i <= 31; i++) {DayList.push(i);}// 设置小时列表,从00到23for (let i = 0; i <= 23; i++) {if (0 <= i && i < 10) {i = "0" + i;}HourList.push(i);}// 设置分钟和秒列表,从00到59for (let i = 0; i <= 59; i++) {if (0 <= i && i < 10) {i = "0" + i;}MinuteList.push(i);SecondList.push(i);}// 将构建好的时间列表数据绑定到组件的数据对象中this.setData({YearList,MonthList,DayList,HourList,MinuteList,SecondList,});// 设置开始日期和结束日期this.setStartDate(startYear,startMonth,startDay,startHour,startMinute,startSecond);this.setEndDate(endYear, endMonth, endDay, endHour, endMinute, endSecond);// 注释掉的setTimeout可能用于解决某些异步问题或界面更新,但此处未实际使用// setTimeout(() => {//   this.setStartDate(nowYear, nowMonth, nowDay, nowHour, nowMinute)//   this.setEndDate(nowYear, nowMonth, nowDay, nowHour, nowMinute)// }, 0);},/*** 设置选择器日期数组* 根据给定的年、月、日、时、分、秒来设置日期选择器的数组* @param {string} type - 类型指示符,可以是"start"或"end"* @param {number} year - 指定的年份* @param {number} month - 指定的月份* @param {number} day - 指定的日期* @param {number} hour - 指定的小时* @param {number} minute - 指定的分钟* @param {number} second - 指定的秒数* @returns {Object} 返回一个对象,包含各个日期组件在选择器中的索引*/setPickerDateArr(type, year, month, day, hour, minute, second) {// 初始化各个日期组件的索引变量let yearIdx = 0;let monthIdx = 0;let dayIdx = 0;let hourIdx = 0;let minuteIdx = 0;let secondIdx = 0;// 查找年份在年份列表中的索引this.data.YearList.map((v, idx) => {if (parseInt(v) === year) {yearIdx = idx;}});// 查找月份在月份列表中的索引this.data.MonthList.map((v, idx) => {if (parseInt(v) === month) {monthIdx = idx;}});// 重新设置日期列表 (根据月份计算天数)let DayList = [];for (let i = 1; i <= this.getDays(year, month); i++) {DayList.push(i);}// 查找日期在日期列表中的索引DayList.map((v, idx) => {if (parseInt(v) === day) {dayIdx = idx;}});// 根据类型更新开始或结束的日期列表if (type == "start") {this.setData({ startDayList: DayList });} else if (type == "end") {this.setData({ endDayList: DayList });}// 查找小时在小时列表中的索引this.data.HourList.map((v, idx) => {if (parseInt(v) === parseInt(hour)) {hourIdx = idx;}});// 查找分钟在分钟列表中的索引this.data.MinuteList.map((v, idx) => {if (parseInt(v) === parseInt(minute)) {minuteIdx = idx;}});// 查找秒数在秒数列表中的索引this.data.SecondList.map((v, idx) => {if (parseInt(v) === parseInt(second)) {secondIdx = idx;}});// 返回包含所有日期组件索引的对象return {yearIdx,monthIdx,dayIdx,hourIdx,minuteIdx,secondIdx,};},/*** 设置开始日期函数** 此函数的作用是根据传入的年、月、日、时、分、秒参数,生成一个可用于选择器的日期数组,* 并更新组件的数据,以在界面上显示选择的开始日期。它首先调用了一个辅助函数来处理日期数组的生成,* 然后使用setData方法更新了多个与日期选择器相关的数据属性,包括年、月、时、分、秒的列表,* 以及选择器的默认值和显示的日期格式字符串。** @param {number} year - 传入的年份* @param {number} month - 传入的月份,注意JavaScript中月份是从0开始的,所以这里传入的值需要减1* @param {number} day - 传入的日* @param {number} hour - 传入的小时* @param {number} minute - 传入的分钟* @param {number} second - 传入的秒*/setStartDate: function (year, month, day, hour, minute, second) {// 调用辅助函数处理日期数组let pickerDateArr = this.setPickerDateArr("start",year,month,day,hour,minute,second);// 更新界面数据,设置日期选择器的列表和默认选中值this.setData({startYearList: this.data.YearList, // 年份列表startMonthList: this.data.MonthList, // 月份列表// startDayList: this.data.DayList,startHourList: this.data.HourList, // 小时列表startMinuteList: this.data.MinuteList, // 分钟列表startSecondList: this.data.SecondList, // 秒钟列表startValue: [// 设置日期选择器的默认选中值pickerDateArr.yearIdx,pickerDateArr.monthIdx,pickerDateArr.dayIdx,pickerDateArr.hourIdx,pickerDateArr.minuteIdx,pickerDateArr.secondIdx,],// 构造日期时间字符串用于界面显示startPickTime:this.data.YearList[pickerDateArr.yearIdx] +"-" +this.data.MonthList[pickerDateArr.monthIdx] +"-" +this.data.DayList[pickerDateArr.dayIdx] +" " +this.data.HourList[pickerDateArr.hourIdx] +":" +this.data.MinuteList[pickerDateArr.minuteIdx] +":" +this.data.SecondList[pickerDateArr.secondIdx],});},setEndDate: function (year, month, day, hour, minute, second) {let pickerDateArr = this.setPickerDateArr("end",year,month,day,hour,minute,second);this.setData({endYearList: this.data.YearList,endMonthList: this.data.MonthList,// endDayList: this.data.DayList,endHourList: this.data.HourList,endMinuteList: this.data.MinuteList,endSecondList: this.data.SecondList,endValue: [pickerDateArr.yearIdx,pickerDateArr.monthIdx,pickerDateArr.dayIdx,pickerDateArr.hourIdx,pickerDateArr.minuteIdx,pickerDateArr.secondIdx,],endPickTime:this.data.YearList[pickerDateArr.yearIdx] +"-" +this.data.MonthList[pickerDateArr.monthIdx] +"-" +this.data.DayList[pickerDateArr.dayIdx] +" " +this.data.HourList[pickerDateArr.hourIdx] +":" +this.data.MinuteList[pickerDateArr.minuteIdx] +":" +this.data.SecondList[pickerDateArr.secondIdx],});},},
});function formatTime(date) {if (typeof date == "string" || "number") {try {date = date.replace(/-/g, "/"); //兼容ios} catch (error) {}date = new Date(date);}const year = date.getFullYear();const month = date.getMonth() + 1;const day = date.getDate();const hour = date.getHours();const minute = date.getMinutes();const second = date.getSeconds();return {str:[year, month, day].map(formatNumber).join("-") +" " +[hour, minute, second].map(formatNumber).join(":"),arr: [year, month, day, hour, minute, second],};
}
function formatNumber(n) {n = n.toString();return n[1] ? n : "0" + n;
}

wxml

<!-- components/timePicker/timePicker.wxml -->
<!-- 自定义时间筛选器 -->
<view wx:if="{{pickerShow&&pickerReady}}"><view class="picker-container {{pickerShow?'show_picker':'hide_picker'}}"><view class="btn-box"><view class="pick_btn" bind:tap="hideModal">取消</view><view class='pick_btn' style="color: #19f" bind:tap="onConfirm">确定</view></view><view><picker-view class='sensorTypePicker' indicator-style='height: 35px;' bindchange="changeStartDateTime" value="{{startValue}}" style="height: {{endDate?'120px':'250px'}};" bindpickstart="handlePickStart" bindpickend="handlePickEnd" data-type="start"><picker-view-column style="min-width: 70px;flex-shrink: 0"><view class='picker-item' wx:for="{{startYearList}}" wx:key='*this'>{{item}}年</view></picker-view-column><picker-view-column><view class='picker-item' wx:for="{{startMonthList}}" wx:key='*this'>{{item}}月</view></picker-view-column><picker-view-column><view class='picker-item' wx:for="{{startDayList}}" wx:key='*this'>{{item}}日</view></picker-view-column><picker-view-column hidden="{{!hourColumn}}"><view class='picker-item' wx:for="{{startHourList}}" wx:key='*this'>{{item}}时</view></picker-view-column><picker-view-column hidden="{{!minColumn}}"><view class='picker-item' wx:for="{{startMinuteList}}" wx:key='*this'>{{item}}分</view></picker-view-column><picker-view-column hidden="{{!secColumn}}"><view class='picker-item' wx:for="{{startSecondList}}" wx:key='*this'>{{item}}秒</view></picker-view-column></picker-view></view><view wx:if="{{endDate}}"><view class='to' style='margin-top: 4px;margin-bottom: 4px;'>至</view><picker-view class='sensorTypePicker' indicator-style='height: 35px;' bindchange="changeEndDateTime" bindpickstart="handlePickStart" bindpickend="handlePickEnd" value="{{endValue}}"><picker-view-column style="min-width: 70px;flex-shrink: 0"><view class='picker-item' wx:for="{{endYearList}}" wx:key='*this' style="min-width: 70px;">{{item}}年</view></picker-view-column><picker-view-column><view class='picker-item' wx:for="{{endMonthList}}" wx:key='*this'>{{item}}月</view></picker-view-column><picker-view-column><view class='picker-item' wx:for="{{endDayList}}" wx:key='*this'>{{item}}日</view></picker-view-column><picker-view-column hidden="{{!hourColumn}}"><view class='picker-item' wx:for="{{endHourList}}" wx:key='*this'>{{item}}时</view></picker-view-column><picker-view-column hidden="{{!minColumn}}"><view class='picker-item' wx:for="{{endMinuteList}}" wx:key='*this'>{{item}}分</view></picker-view-column><picker-view-column hidden="{{!secColumn}}"><view class='picker-item' wx:for="{{startSecondList}}" wx:key='*this'>{{item}}秒</view></picker-view-column></picker-view></view><!-- <view class='sure' bindtap="onConfirm">确定</view> --></view><!-- 遮罩 --><view class="sensorType-screen" bind:tap="hideModal" />
</view>

wxss

/* components/timePicker/timePicker.wxss */.picker-item{line-height: 50px;  display: flex;justify-content: center;align-items: center;
}/* 自定义时间 */
.picker-container {display: flex;flex-direction: column;/* justify-content: center; */align-items: center;width: 100%;overflow: hidden;position: fixed;bottom: 0rpx;left: 0;height: 0;transition: height 0.5s;z-index: 2000;background: white;border-top: 1px solid #EFEFF4;
}
.sensorType-screen{width: 100vw;/* height:400rpx; */position: fixed;top: 0;right: 0;bottom: 0;left: 0;background:#000;opacity: 0.7;overflow: hidden;z-index: 1999;color: #fff;
}
.sensorTypePicker{width: 690rpx;height: 120px;/* padding: 45px 0; */
}
.picker-item{line-height: 50px;  display: flex;justify-content: center;align-items: center;font-size: 16px;/* overflow: hidden; */
}
.box{padding: 0 10px; 
}/* 至 */
.to{width:100%;display: flex;justify-content: center;align-items: center;color:rgb(138,138,138);/* font-size:30rpx; */
}/* 确定 */
.sure{width:100%;height:45px;border-top: 1px solid #EFEFF4;display: flex;justify-content: center;align-items: center;color: rgb(36,123,255);font-size:16px;
}.btn-box{width: 100%;display: flex;justify-content: space-between;align-items: center;border-bottom: 1px solid #eee;
}
.pick_btn{padding: 7px 15px;color: #ccc;/* background-color: #159; */
}.show_picker{height: 320px;
}
.hide_picker{height: 0;
}

json

{"component": true,"usingComponents": {}}

注意事项

微信小程序自定义时间选择器,支持多种自定义功能。

在开发工具中浏览: https://developers.weixin.qq.com/s/N9EdArmQ7a6j
复制链接在浏览器中打开

配置项

pickerConfig: {endDate: true,                          // 是否需要结束时间,为true时显示开始时间和结束时间两个pickercolumn: "second",                       //可选的最小时间范围day、hour、minute、secenddateLimit: true,                        //是否现在时间可选范围,false时可选任意时间;当为数字n时,范围是当前时间的最近n天initStartTime:'2019-01-01 12:32:44',    //picker初始时间,默认当前时间initEndTime: "2019-12-01 12:32:44",     //picker初始结束时间,默认当前时间limitStartTime: "2015-05-06 12:32:44",  //最小可选时间limitEndTime: "2055-05-06 12:32:44"     //最大可选时间 
}
其他限制条件可修改组件中的compareTime函数定义

endDate: true

endDate: false

pickerReady 为了保证加载顺序初始化正常 Skyline 模式下初始化会触发change 导出初始化异常

未解决 用户快速滚动会造成页面卡死 有思路的大佬可以留言解决方案


http://www.mrgr.cn/news/28426.html

相关文章:

  • C# 选择文件夹路径
  • EHOME视频平台EasyCVR多品牌摄像机视频平台监控视频编码H.265与Smart 265的区别?
  • 堆排序法,
  • STM32 设计的较为复杂的物联网项目,包括智能家居控制系统,涵盖了硬件和软件的详细设计。
  • Cellebrite VS IOS18Rebooting
  • Linux软件包管理与Vim编辑器使用指南
  • (183)时序收敛--->(33)时序收敛三三
  • 《并发之危:错误实现的并发数据结构如何“摧毁”程序》
  • 模型训练的过程中对学习不好的样本怎么处理更合适
  • 什么是 HTTP/3?下一代 Web 协议
  • 后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0916)
  • Django_Vue3_ElementUI_Release_003_前端Vue3项目初始化
  • 【系统架构设计师】软件架构的概念(经典习题)
  • shopify主题开发之template模板解析
  • 【JAVA干货店】带你玩转数组与递归
  • IAPP发布《2024年人工智能治理实践报告》
  • 算法题解:斐波那契数列(C语言)
  • 15. 三数之和(实际是双指针类型的题目)
  • 支持升降压型、升压、降压、60V的1.2MHz频率LED恒流驱动器LGS63040、LGS63042
  • C/C++实现植物大战僵尸(PVZ)(打地鼠版)
  • 配置cobbler服务提供centos7安装源
  • [OpenCV] 数字图像处理 C++ 学习——15像素重映射(cv::remap) 附完整代码
  • 初中生物--5.单细胞生物
  • 大数据新视界 --大数据大厂之MongoDB与大数据:灵活文档数据库的应用场景
  • 建设世界一流财务管理体系【数字化顶层设计】【持续更新】
  • 大学生看过来,必备4款写论文AI写作网站先稿后付