uni-app日期选择组件-基于mx-datepicker修改

首先非常感谢mx-datepicker作者,这个时间组件非常漂亮且好用。由于我们的需求是,在一个可用的日期范围内选择一个日期,作者并没有支持这种场景,于是在作者的基础上进行了修改。具体的需求如下:可传入一个可选范围,打开选择器时,只有可选范围内的日期可点击选中,其他日期不可点击动态改变翻月翻年按钮可用性,如果上月数据中没有可选日期则向上翻月按钮不可点击。文末有完整代码下面来说一下我的改造过程。1.在props中增加一个参数,用于接收调用者传进来的可用日期范围enableRange,接.
摘要由CSDN通过智能技术生成

首先非常感谢mx-datepicker作者,这个时间组件非常漂亮且好用。
由于我们的需求是,在一个可用的日期范围内选择一个日期,作者并没有支持这种场景,于是在作者的基础上进行了修改。
具体的需求如下:

  • 可传入一个可选范围,打开选择器时,只有可选范围内的日期可点击选中,其他日期不可点击
  • 动态改变翻月翻年按钮可用性,如果上月数据中没有可选日期则向上翻月按钮不可点击。

文末有完整代码

日期选择控件
下面来说一下我的改造过程。

1.在props中增加一个参数,用于接收调用者传进来的可用日期范围enableRange,接收一个数组
props: {
   
		//颜色
		color: {
   
			type: String,
			default: '#409eff'
		},
		//是否显示秒 针对type为datetime或time时生效
		showSeconds: {
   
			type: Boolean,
			default: false
		},
		//初始的值
		value: [String, Array],
		//可用日期范围
		enableRange: [Array],
		//类型date time datetime range rangetime
		type: {
   
			type: String,
			default: 'range'
		},
		//是否显示
		show: {
   
			type: Boolean,
			default: false
		},
		//初始格式
		format: {
   
			type: String,
			default: ''
		},
		//显示公历节日
		showHoliday: {
   
			type: Boolean,
			default: false
		},
		//显示提示
		showTips: {
   
			type: Boolean,
			default: false
		},
		//开始文案 针对type为范围选择时生效
		beginText: {
   
			type: String,
			default: '开始'
		},
		//结束文案 针对type为范围选择时生效
		endText: {
   
			type: String,
			default: '结束'
		}
	},
2.找到关键方法refreshCalendarsprocCalendar

refreshCalendars用于刷新日历,首次打开和进行上下翻页时会调用,所以这个方法就是让我们控制是否可以进行翻页的关键。

refreshCalendars(refresh = false) {
   
	let date = new Date(this.date);
	
	let before = DateTools.getDateToMonth(date, date.getMonth() - 1);
	let after = DateTools.getDateToMonth(date, date.getMonth() + 1);
	if (this.calendarIndex == 0) {
   
		if (refresh) this.calendars.splice(0, 1, DateTools.getCalendar(date, this.procCalendar));
		this.calendars.splice(1, 1, DateTools.getCalendar(after, this.procCalendar));
		this.calendars.splice(2, 1, DateTools.getCalendar(before, this.procCalendar));
	} else if (this.calendarIndex == 1) {
   
		this.calendars.splice(0, 1, DateTools.getCalendar(before, this.procCalendar));
		if (refresh) this.calendars.splice(1, 1, DateTools.getCalendar(date, this.procCalendar));
		this.calendars.splice(2, 1, DateTools.getCalendar(after, this.procCalendar));
	} else if (this.calendarIndex == 2) {
   
		this.calendars.splice(0, 1, DateTools.getCalendar(after, this.procCalendar));
		this.calendars.splice(1, 1, DateTools.getCalendar(before, this.procCalendar));
		if (refresh) this.calendars.splice(2, 1, DateTools.getCalendar(date, this.procCalendar));
	}
	this.title = DateTools.format(this.date, 'yyyy年mm月');
},
3.解决上月上年下月下年四个按钮的可用性需求

要改造这个方法首先要定义四个变量,来控制是上月上年下月下年四个按钮的可用性(是否可点击,如果不可点击就置灰)

在data中定义四个变量

canLastYear: false, 
canNextYear: false,
canLastMonth: false,
canNextMonth: false

在template中根据变量来控制按钮状态

<view class="picker-modal-header">
	<view
		:class="[canLastYear ? '' : 'disabled-color', 'picker-icon picker-icon-zuozuo']"
		:hover-stay-time="100"
		hover-class="picker-icon-active"
		@click="canLastYear ? onSetYear('-1') : null"
	></view>
	<view
		:class="[canLastMonth ? '' : 'disabled-color', 'picker-icon picker-icon-zuo']"
		:hover-stay-time="100"
		hover-class="picker-icon-active"
		@click="canLastMonth ? onSetMonth('-1') : null"
	></view>
	<text class="picker-modal-header-title">{
  { title }}</text>
	<view
		:class="[canNextMonth ? '' : 'disabled-color', 'picker-icon picker-icon-you']"
		class=""
		:hover-stay-time="100"
		hover-class="picker-icon-active"
		@click="canNextMonth ? onSetMonth('+1') : null"
	></view>
	<view
		:class="[canNextYear ? '' : 'disabled-color', 'picker-icon picker-icon-youyou']"
		:hover-stay-time="100"
		hover-class="picker-icon-active"
		@click="canNextYear ? onSetYear('+1') : null"
	></view>
</view>

refreshCalendars方法中进行日期对比判断:

首先找到calendars这个二维数组,这里面存放着三页的数据,上一页,当前页,下一页,既然我们要控制上下两页,那么就从这个数组中拿出calendars[0]calendars[2].

判断上月上一年的逻辑代码如下:

let lastMonth = this.calendars[0]; //取出上一页的所有数据
let enableStartDate = this.enableRange[0]; // 取出调用者传入的起始可用日期
for (var i = 0; i < lastMonth.length; i++) {
   
	let date = lastMonth[i].dateObj;
	if (DateTools.compareDate(date, enableStartDate) == 1 || DateTools.compareDate(date, this.enableRange[0]) == 0) {
   
		this.canLastMonth = true;
		if (DateTools.compareYear(enableStartDate, date) == -1) {
   
			this.canLastYear = true;
			break;
		} else {
   
			this.canLastYear = false;
		}
		break;
	} else {
   
		this.canLastMonth = false;
		this.canLastYear = false;
	}
}

判断下月下一年的逻辑代码如下:`

let nextMonth = this.calendars[2];
let enableEndDate = this.enableRange[1];
for (var i = 0; i < nextMonth.length; i++) {
   
	let date = nextMonth[i].dateObj;
	if (DateTools.compareDate(date, enableEndDate) == -1 || DateTools.compareDate(date, enableEndDate) == 0) {
   
		this.canNextMonth = true;
		if (DateTools.compareYear(enableEndDate, date) == 1) {
   
			this.canNextYear = true;
			break;
		} else {
   
			this.canNextYear = false;
		}
		break;
	} else {
   
		this.canNextMonth = false;
		this.canNextYear = false;
	}
}
4.解决起始日期之外的日期不可点击的需求

refreshCalendars方法中可以看出,刷新每个日期空间的方法是procCalendar,可以看出此方法会带入一个item对象,此方法中就是根据一些特定的条件去处理每个日期的显示样式。我们要实现某些日期不可点击并置灰显示,也需要在这个方法中进行。

procCalendar未修改的代码:

procCalendar(item) {
   
	//定义初始样式
	item.statusStyle = {
   
		opacity: 1,
		color:item.isOtherMonth ? '#abcfff' : '#000',
		background: 'transparent'
	};
	item.bgStyle = {
   
		type: '',
		background: 'transparent'
	};
	item.dotStyle = {
   
		opacity: 1,
		background: 'transparent'
	};
	item.tips = '';
	//标记今天的日期
	if (DateTools.isSameDay(new Date(), item.dateObj)) {
   
		item.statusStyle.color = this.color;
		if (item.isOtherMonth) item.statusStyle.opacity = 0.3;
	}
	//标记选中项
	this.checkeds.forEach(date => {
   
		if (DateTools.isSameDay(date, item.dateObj)) {
   
			item.statusStyle.background = this.color;
			item.statusStyle.color = '#fff';
			item.statusStyle.opacity = 1;
			if (this.isMultiSelect && this.showTips) item.tips = this.beginText;
		}
	});
	//节假日或今日的日期标点
	if (item.statusStyle.background != this.color) {
   
		let holiday = this.showHoliday ? DateTools.getHoliday(item.dateObj) : false;
		if (holiday || DateTools.isSameDay(new Date(), item.dateObj)) {
   
			item.title = holiday || item.title;
			item.dotStyle.background = this.color;
			if (item.isOtherMonth) item.dotStyle.opacity = 0.2;
		}
	} else {
   
		item.title = item.dateObj.getDate();
	}
	//有两个日期
	if (this.checkeds.length == 2) {
   
		if (DateTools.isSameDay(this.checkeds[0], item.dateObj)) {
   
			//开始日期
			item.bgStyle.type = 'bgbegin';
		}
		if (DateTools.isSameDay(this.checkeds[1], item.dateObj)) {
   
			//结束日期
			if (this.isMultiSelect && this.showTips) item.tips = item.bgStyle.type ? this.beginText + ' / ' + this.endText : this.endText;
			if (!item.bgStyle.type) {
   
				//开始日期不等于结束日期
				item.bgStyle.type = 'bgend';
			} else {
   
				item.bgStyle.type = '';
			}
		}
		if (!item.bgStyle.type && (+item.dateObj > +this.checkeds[0] && +item.dateObj < +this.checkeds[1])) {
   
			//中间的日期
			item.bgStyle.type = 'bg';
			item.statusStyle.color = this.color;
		}
		if (item.bgStyle.type) {
   
			item.bgStyle.background = this.color;
			item.dotStyle.opacity = 1;
			item.statusStyle.opacity = 1;
		}
	}
},

要想实现按钮根据不同的状态展示不同的样式和相应不同的操作,我们还需要给在item中增加一个属性disable
procCalendar中增加判断:

//如果起始日期大于该日期
//可用范围
let startresult = DateTools.compareDate(this.enableRange[0], item.dateObj) == -1 || DateTools.compareDate(this.enableRange[0], item.dateObj) == 0;
let endresult = DateTools.compareDate(item.dateObj, this.enableRange[1]) == -1 || DateTools.compareDate(item.dateObj, this.enableRange[1]) == 0;
if (startresult && endresult) {
   
	item.disable = false;
} else {
   
	item.disable = true;
}

将样式定义的部分改成如下:

//定义初始样式
item.statusStyle = {
   
	opacity: 1,
	color: item.disable ? '#ddd' : item.isOtherMonth ? '#abcfff' : '#000',
	background: 'transparent'
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值