小程序日期(日历)时间 选择器组件
Posted 少年的范儿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小程序日期(日历)时间 选择器组件相关的知识,希望对你有一定的参考价值。
封装一个小程序日期(日历)时间 选择器组件
简要说明:
一共两个版本 ,date-time-picker 和 date-time-picker-plus.
date-time-picker 弹窗层是 基于 vant-weapp 的 van-popup 组件实现的
date-time-picker-plus 弹窗层是 基于 小程序 自带的 page-container 组件来实现的
*注意:date-time-picker 需要下载 vant-weapp 组件库配合一起使用,date-time-picker-plus 可以直接在小程序里面使用
首先看一下效果图
组件代码
两个版本代码几乎一样,只是弹窗层用的不一样,这里我就用 基于 vant-weapp UI一起使用的版本来写
- wxml 中
<view class="date-time-picker-box">
<van-popup show=" show " zIndex="9999" round position="bottom" custom-style="border-radius:16px 16px 0 0;min-height:355px;max-height:400px;" bind:close="handleCancel">
<view class="date-time-picker-title">
<view class="date-time-picker-nav">
<view bindtap="handleChangeTag" data-index="0" class="tag date-tag currentIndex == 0 ? 'active' : ''">
year年month月day日
</view>
<view bindtap="handleChangeTag" data-index="1" class="tag time-tag currentIndex == 1 ? 'active' : ''">
hour:minute
</view>
<view class="date-time-line" style="left:leftpx;width: widthpx;"></view>
</view>
<button bindtap="handleConfirm" class="date-picker-oper-btn">确定</button>
</view>
<view class="date-time-picker-content">
<!-- 日历主体 -->
<swiper current="currentIndex" style="height:100%;">
<swiper-item catchtouchmove="catchtouchmove">
<view class="swiper-item ">
<!-- 日历组件 -->
<calendar bindselectDay="selectDay" bindgetDateList="getDateList" vertical="vertical"></calendar>
</view>
</swiper-item>
<swiper-item catchtouchmove="catchtouchmove">
<view class="swiper-item ">
<div class="date-time-item">
<picker-view indicator-style="height: 50px;" style="width: 100%; height: 200px;text-align:center;" value="value" bindpickstart="bindpickstart" bindpickend="bindpickend" bindchange="bindChange">
<picker-view-column>
<view wx:for="hours" wx:key="*this" style="line-height: 50px">item时</view>
</picker-view-column>
<picker-view-column>
<view wx:for="minutes" wx:key="*this" style="line-height: 50px">
item分
</view>
</picker-view-column>
</picker-view>
</div>
</view>
</swiper-item>
</swiper>
</view>
</van-popup>
</view>
- wxss 中
.date-time-picker-box .date-time-picker-title
display: flex;
align-items: center;
justify-content: space-between;
padding: 0rpx 48rpx;
height: 112rpx;
box-sizing: border-box;
border-bottom: 2rpx solid #E5E3E3;
max-height: 400px;
/* overflow: hidden; */
.date-time-picker-box .date-time-picker-title .title-txt
font-size: 17px;
font-weight: 500;
color: #1F1E1E;
.date-time-picker-box .date-time-picker-title .date-picker-oper-btn
width: 104rpx;
height: 64rpx;
line-height: 64rpx;
text-align: center;
font-size: 28rpx;
border-radius: 8rpx;
font-weight: 500;
margin: 0;
padding: 0;
color: var(--themeTxtColor);
background-color: var(--themeColor);
.date-time-picker-box .date-time-picker-title .cancel-btn
color: #5C5959;
background-color: #fff;
text-align: left;
.date-time-picker-box .date-time-picker-title .date-time-picker-nav
position: relative;
display: flex;
align-items: center;
font-weight: 500;
color: #8F8D8D;
height: 100%;
.date-time-picker-box .date-time-picker-nav .date-tag
margin-right: 32rpx;
.date-time-picker-box .date-time-picker-nav .tag
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.date-time-picker-box .date-time-picker-nav .tag.active
color: #1F1E1E;
.date-time-picker-box .date-time-picker-nav .date-time-line
position: absolute;
bottom: 0;
width: 40rpx;
height: 4rpx;
background-color: #5C5959;
transition: all 0.3s linear;
.date-picker-btn-box
display: flex;
font-weight: 600;
margin-top: 40rpx;
color: var(--themeColor);
justify-content: space-around;
.date-time-picker-content
height: 600rpx;
box-sizing: border-box;
- json 中
"component": true,
"usingComponents":
"van-popup": "@vant/weapp/popup/index",
"calendar":"./calendar/index"
- js 中
const date = new Date(); // 获取系统日期
var getYear = date.getFullYear(),
getMonth =
date.getMonth() + 1 < 10
? "0" + (date.getMonth() + 1)
: date.getMonth() + 1,
getDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(),
isScroll = false;
Component(
properties:
show:
// 控制弹窗显示和隐藏
type: Boolean,
value: false,
,
vertical:
// 是否垂直滑动
type: Boolean,
value: false,
,
/**
* type 时间类型 分钟, 支持两种类型 time 和 part , 默认是part
* time : 2023-02-03 09:00 正常的日期时间 (例如: 09:30 、11:10 、12:36 ...)
* part : 2023-02-03 09:00 分钟只包含 00 和 30 (例如: 09:30 、11:00 、12:30 ...)
*/
type:
type: String,
value: "part", // time 和 part
,
,
data:
year: getYear, // 当前已选年份,默认是当年
month: getMonth, // 当前已选月份,默认是当月
day: getDate, // 当前已选天,默认是当天
hour: "09", // 当前已选小时, 默认 09 点
minute: "00", // 当前已选分钟,默认00
hours: [], // 时间选择器,存放的小时数组 0 - 23
minutes: [], // 时间选择器,存放的分钟数组 00 和 30 或者 00 - 59
value: [0, 0], // 时间选择器,当前选择时间 索引
currentIndex: 0, // tab导航当前索引
left: 0, // tab导航 底部线条 当前离左侧位置 距离
width: 123, // tab导航 底部线条 当前 宽度
firstEnter: true, // 是否第一次打开, 默认true
,
lifetimes:
attached: function ()
this.initDateTimePicker();
,
moved: function () ,
detached: function () ,
,
methods:
// 日期改变的回调
selectDay( detail )
console.log(detail, "selectDay detail");
let year, month, day = detail;
month = month > 9 ? month : "0" + month;
day = day > 9 ? day : "0" + day;
if (!this.data.firstEnter)
setTimeout(() =>
this.setData( currentIndex: 1 );
this.changeline();
, 300);
this.setData( year, month, day, firstEnter: false );
,
// 切换导航
handleChangeTag(e)
this.setData(
currentIndex: e.currentTarget.dataset.index,
firstEnter: false,
);
this.changeline();
,
// 渲染横线位置的方法
changeline()
let _this = this;
// SelectorQuery.in(Component component): 将选择器的选取范围更改为自定义组件 component 内
let query = wx.createSelectorQuery().in(this);
// select() 在当前页面下选择第一个匹配选择器 selector 的节点
// boundingClientRect() 添加节点的布局位置的查询请求。相对于显示区域,以像素为单位
query.select(".active").boundingClientRect();
// SelectorQuery.exec(function callback) 执行所有的请求
// 请求结果按请求次序构成数组,在callback的第一个参数中返回
query.exec(function (res)
// console.log(res);
_this.setData(
left: res && res[0].left - 24,
width: parseInt(res[0].width),
);
);
,
/***
* 滚动选择时触发change事件,
* 可以查看小程序官方文档了解
*/
bindChange(e)
const val = e.detail.value;
this.setData(
hour: this.data.hours[val[0]],
minute: this.data.minutes[val[1]],
);
,
// 滚动开始
bindpickstart()
isScroll = true;
,
//滚动结束
bindpickend()
isScroll = false;
,
// 点击取消按钮,关闭日期选择器
handleCancel()
this.setData( show: false );
,
// 点击确定按钮
handleConfirm()
let year, month, day, hour, minute = this.data;
// console.log(year, month, day, hour, minute)
// 判断用户选择时间滚动是否结束,解决 picker-view bindChange 延迟问题
if (isScroll) return;
const timeStr =
year + "-" + month + "-" + day + " " + hour + ":" + minute;
this.triggerEvent("onSelectDate", timeStr);
this.setData( show: false, currentIndex: 0 );
this.changeline();
,
// 初始化 picker 时间数据
initDateTimePicker()
let hours = [],
minutes = [];
// 存放小时的数组
for (let i = 0; i <= 23; i++)
if (i < 10)
i = "0" + i;
hours.push(i);
// 存放分钟的数组
if (this.data.type === 'time')
for (let i = 0; i <= 59; i++)
if (i < 10) i = '0' + i
minutes.push(i)
else
minutes = ['00', '30']
this.setData( hours, minutes );
this.setData( value: [9, 0] );
,
// 加载日历数据
getDateList()
// 防止滑动时 tab导航切换到时间模块
this.setData( firstEnter: true );
,
// 禁止 日期时间 swiper 滑动
catchtouchmove()
return false;
,
,
);
简要说明:
在 index.wxml 文件 中 ,会有一个 日历组件
<calendar bindselectDay="selectDay" bindgetDateList="getDateList" vertical="vertical"></calendar>
这个组件会放在 date-time-picker 组件目录下,这里我就不把代码贴出来了,可以直接去我的远程仓库去拉取。
组件代码仓库地址:Gitee | Github 或者直接复制下面的链接 直接下载代码
- Gitee 远程仓库下载链接
git clone https://gitee.com/junfeng535/wx-date-time-picker.git
- Github 远程仓库下载链接
git clone https://github.com/junfeng-git/wx-date-time-picker.git
反应日期选择器日期范围
【中文标题】反应日期选择器日期范围【英文标题】:React-datepicker date range 【发布时间】:2020-10-12 00:06:15 【问题描述】:我正在为我的应用程序使用 react-typescript。我正在使用React-datepicker 包。我想创建一个全球日期范围组件。所以我可以将它重用于不同的组件。我使用 React-datepicker 的 customInput
进行样式设置并创建了显示时间的按钮。我关注this link 的日期范围逻辑。在日历日期范围内似乎有效,这是image。我想在customInput's
按钮中显示选择开始日期和结束日期。但是一旦我选择了结束日期,两个按钮都会显示结束日期的值。我不知道如何解决它。
这是日期范围组件
import React, useState from "react";
import DatePicker, ReactDatePickerProps from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import moment from "moment";
import Button from "components/buttons";
export interface IDatepicker
value:
start: Date;
end: Date;
;
onBlur?: (i: React.FocusEvent<HTMLInputElement>) => void;
onFocus?: (i: React.FocusEvent<HTMLInputElement>) => void;
onChange: (i: Date) => void;
buttonComponent?: JSX.Element;
withPortal?: boolean;
showTimeSelect?: boolean;
dateFormat?: string;
timeFormat?: string;
export default (
value,
onChange,
onBlur,
onFocus,
buttonComponent,
withPortal = false,
showTimeSelect = false,
dateFormat = "MMMM d, yyyy h:mm aa",
timeFormat = "HH:mm"
: IDatepicker) =>
const handleChange = (date: Date | null) =>
date && onChange(date);
;
return (
<div style= display: "flex" >
<DatePicker
selected=value.start
onChange=handleChange
showTimeSelect=showTimeSelect
selectsStart
startDate=value.start
endDate=value.end
customInput=
<Button>
moment(value.start)
.format("MMMM Do YYYY")
.toString()
</Button>
/>
<div style= color: "black" >-</div>
<DatePicker
selected=value.end
onChange=handleChange
showTimeSelect=showTimeSelect
selectsEnd
startDate=value.start
endDate=value.end
minDate=value.start
customInput=
<Button>
moment(value.end)
.format("MMMM Do YYYY")
.toString()
</Button>
/>
</div>
);
;
这是我正在使用的日期范围组件
import React from "react";
import TimeLine from "components/datepicker";
export default () =>
const [state, setState] = useState(new Date());
return (
<div>
<TimeLine
value= start: state, end: state
onChange=setState
/>
</div>
);
;
【问题讨论】:
每次设置结束日期时,开始日期都会被覆盖,因为您在开始和结束日期DatePicker
实例中使用了相同的handleChange
回调。您需要在您所在的州保留两个日期,而不是一个日期,请参阅下面@Mahesh 的答案。
【参考方案1】:
您对开始和结束都使用单一状态值。我认为这是你问题的根本原因。 而不是使用
const [state, setState] = useState(new Date());
我认为您应该将其声明为
const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(new Date());
【讨论】:
以上是关于小程序日期(日历)时间 选择器组件的主要内容,如果未能解决你的问题,请参考以下文章