uniapp ,vue,js日历卡片可滑动日期可点击选择可更改颜色样式

效果图

日期可左右滑动无限制,当天日期纯绿色填充标识样式,点击其他日期绿色边框标识(日期颜色可在样式里面更改$am-color)

1.创建一个.vue文件

<template>
	<view :class="[fold&&'flex flex-items-center', 'wx-card mt20']">
		<view :class="[!fold&&'f32 flex flex-center pb20',fold&&'card-header']" @click="initDate">
			<view :class="[fold&&'f26 tc']">{{nowDay.year}}年</view>
			<view :class="[fold&&'flex flex-center flex-items-end']">
				<text :class="[fold&&'f70']">{{nowDay.month}}</text>
				<text :class="[fold&&'f30','pb10 ml5']">月</text>
			</view>
		</view>
		<view v-if="verticaled" class="flex flex-items-center flex-around pb10">
			<view :class="['tc w7']" v-for="item in weeks" :key="item">
				{{item}}
			</view>
		</view>
		<view class="flex-1 fit-height">
			<swiper 
			:current="tabIndex" 
			:animation="animationData" 
			:class="[fold?'swiper-week':'swiper-month','flex-1']" 
			:vertical="verticaled"
			:duration="duration" 
			@change="ontabchange" 
			@animationfinish="animationfinish" >
				<swiper-item v-for="(days,index1) in list" :key="index1">
					<template v-if="fold">
						<view class="month-wrap flex flex-items-center flex-around pt5">
							<view :class="['tc',!(item.isNow||item.isFuture)&&'graya']" v-for="item in days.weeks" :key="item.day" @click="clickTime(item)">
								<view>{{item.week}}</view>
								<view :class="[item.isNow&&'active',item.isActive&&'active','mt20 pb20',!item.isAct&&item.isAM&&'isAM',!item.isAct&&item.isPM&&'isPM',item.isAct&&'isAct']">
									<text :class="[item.isNow&&'isNowWap',item.isActive&&'isSelect']">{{item.day}}</text>
								</view>
							</view>
						</view>
					</template>
					<template v-else>
						<view class="month-wrap">
							<view v-if="!verticaled" class="flex flex-items-center flex-around">
								<view :class="['tc w7']" v-for="item in weeks" :key="item">
									{{item}}
								</view>
							</view>
							<view class="flex flex-items-center flex-wrap">
								<view :class="['tc w7',(!(item.isNow||item.isFuture)&&!verticaled||(!item.isMonth))&&'graya',item.isNow&&'active',item.isActive&&'active',!item.isAct&&item.isAM&&'isAM',!item.isAct&&item.isPM&&'isPM',item.isAct&&'isAct']" v-for="(item,index) in days.months" :key="index" @click="clickTime(item)">
									<view :class="[item.isNow&&'isNowWap',item.isActive&&'isSelect','mt30 mb20']">{{item.day}}</view>
								</view>
							</view>
						</view>
					</template>
				</swiper-item>
			</swiper>
		</view>
	</view>
</template>

<script>
/**
 * 一个简单的时间切换
 使用示例:<moSimpleDate @changeTime="changeTime"/>
 * 
 */
	export default {
		name: 'moSimpleDate',
		props: {
			fold: { // 是否收起
				type: Boolean,
				default: true
			},
			time: { // 起始时间
				type: [String, Number],
				default: 0
			},
			immite: {  // 是否立即执行
				type: Boolean,
				default: true
			},
			delay: {  // 切换时间
				type: Number,
				default: 300
			},
			selectTime: {  // 被选中的日期列表
				type: Array,
				default: ()=>[]
			},
			active: {  // 是否开启点击选中样式
				type: Boolean,
				default: true
			},
			vertical: {  // 是否垂直切换(fold=false时有效)
				type: Boolean,
				default: false
			},
		},
		data() {
			return {
                tabIndex: 1,
				duration: 50,
				weekList:[],
				monthList:[],
				nowTime: 0,
				timer: null,
				weeks: ["一", "二", "三", "四", "五", "六", "日"],
				animationData: {}
			}
		},
		computed: {
			verticaled(){
				return !this.fold ? this.vertical : false
			},
			list(){
				return this.fold ? this.weekList : this.monthList
			},
			nowDay(){
				const now = new Date(this.nowTime)
				const weekNumber = now.getDay()||7
				
				return this.fold ? {
					temps: now.getTime(),
					weekNumber: weekNumber,
					weeks: this.weekList[1].weeks,
					...this.weekList[1].weeks[weekNumber-1]
				} : {
					temps: now.getTime(),
					month: now.getMonth() + 1,
					year: now.getFullYear(),
					weekNumber,
					months: this.monthList[1].months,
					// ...this.monthList[1].months.filter(item=>item.isMonth)[0]
				}
			}
		},
		watch: {
			fold: {
				handler(_new){
					this.initDate(this.immite)
				},
				immediate: true
			},
			selectTime: {
				handler(_new){
					this.fold&&this.getWeekList(this.nowTime)
					!this.fold&&this.getMonthList(this.nowTime)
				},
			},
		},
		methods: {
			initDate(immite = true){
				const NowTimeMs = new Date().setHours(0,0,0,0)
				const getTimeMs = new Date(this.nowTime).setHours(0,0,0,0)
				this.nowTime = this.time ? new Date(this.time) : new Date()
				this.fold&&this.getWeekList()
				!this.fold&&this.getMonthList()
				this.switchTab(1)
				if(this.tabIndex==1&&NowTimeMs!=getTimeMs&&immite){
					this.$emit('changeTime',this.nowDay)
				}
				const _this = this
				this.$nextTick(()=>{
					_this.getHeg()
				})
			},
			getHeg(){
				const query = uni.createSelectorQuery().in(this);
				query.selectAll('.month-wrap').boundingClientRect(res=>{
					if(!res) return
					// const monthY = Math.max.apply(Math, res.map(e=> e.height))
					const monthY = res[1].height
					let animation = uni.createAnimation({
						duration: 200,
						timingFunction: "ease",
						delay: 0,
					})
					animation.height(monthY).step()
					this.animation = animation
					this.animationData = this.animation.export()
				}).exec()
			},
            ontabchange(e) {
                let index = e.target.current || e.detail.current;
				let dat = new Date(this.nowTime)
				if(index==2){
					this.nowTime = this.fold ? dat.setDate(dat.getDate() + 7) : dat.setMonth(dat.getMonth() + 1);
				}
				if(index==0){
					this.nowTime = this.fold ? dat.setDate(dat.getDate() - 7) : dat.setMonth(dat.getMonth() - 1);
				}
				this.switchTab(index)
				const _this = this
				this.$nextTick(()=>{
					_this.getHeg()
				})
				e.stopPropagation()
            },
			animationfinish(){
				if (this.tabIndex === 1) return;
				let _this = this
				this.duration = 0
				if (this.timer) {
					clearTimeout(this.timer)
					this.timer = null
				}
				
				this.timer = setTimeout(function(){
					_this.fold&&_this.getWeekList(_this.nowTime)
					!_this.fold&&_this.getMonthList(_this.nowTime)
					_this.switchTab(1,true)
				}, 0)
			},
			switchTab(index,ani) {
				this.duration = ani ? 0 : this.delay
				if (this.tabIndex === index) return
				this.tabIndex = index
				this.tabIndex==1&&this.$emit('changeTime',this.nowDay)
			},
			select(item){
				if(this.fold){
					const weeks = JSON.parse(JSON.stringify(this.weekList[1].weeks))
					weeks.forEach(day=>{
						day.isActive = item.temps == day.temps
					})
					this.weekList = [
						this.weekList[0],
						{type:4, weeks},
						this.weekList[2],
					]
				}else{
					const months = JSON.parse(JSON.stringify(this.monthList[1].months))
					months.forEach(day=>{
						day.isActive = item.temps == day.temps
						day.ss = 1212
					})
					const data = [
						this.monthList[0],
						{type:4, months},
						this.monthList[2],
					]
					this.monthList = JSON.parse(JSON.stringify(data))
				}
			},
			clickTime(item){
				this.active&&this.select(item)
				const res = JSON.parse(JSON.stringify(item))
				Object.keys(res).forEach(e=>{
					delete res['isMonth']
				})
				this.$emit('clickTime', this.fold ? item : res)
			},
			getWeekList(now){
				const nowTime = new Date(now || new Date)
				const lastTime = new Date(nowTime).setDate(nowTime.getDate() - 7);
				const nextTime = new Date(nowTime).setDate(nowTime.getDate() + 7);
				this.weekList = [
					{type:0,weeks:this.getWeeks(lastTime)},
					{type:1,weeks:this.getWeeks(nowTime)},
					{type:2,weeks:this.getWeeks(nextTime)},
				]
			},
			getWeeks(now){
				const dat = new Date(now);
				const day = dat.getDay();   
				dat.setDate(dat.getDate() + (1 - day));
				const _weeks = ["一", "二", "三", "四", "五", "六", "日"]
				return _weeks.reduce((weeks,week)=>{
					const NowTimeMs = new Date().setHours(0,0,0,0)
					const getTimeMs = new Date(dat).setHours(0,0,0,0)
					const isAM = this.isActive(dat, 0)
					const isPM = this.isActive(dat, 1)
					const date = {
						temps: new Date(dat).getTime(),
						year: dat.getFullYear(), 
						month: dat.getMonth() + 1,
						day: dat.getDate(), 
						week, 
						isNow: NowTimeMs == getTimeMs, 
						isFuture: NowTimeMs < getTimeMs,
						isAM,
						isPM,
						isAct: isAM&&isPM,
					}
					dat.setDate(dat.getDate() +1)
					return weeks.concat(date)
				},[])
			},
			getMonthList(now){
				const nowTime = new Date(now || new Date)
				const lastTime = new Date(nowTime).setMonth(nowTime.getMonth() - 1);
				const nextTime = new Date(nowTime).setMonth(nowTime.getMonth() + 1);
				this.monthList = [
					{type:0,months:this.getMonths(lastTime)},
					{type:1,months:this.getMonths(nowTime)},
					{type:2,months:this.getMonths(nextTime)},
				]
			},
			getMonths(now){
				const nowTime = new Date(now);
				const oneTime = nowTime.setDate(1)   // 设置为本月第一天
				nowTime.setDate(nowTime.getDate() + (1 - (nowTime.getDay()||7))); // 设置周一

				const nextTime = new Date(oneTime) 
				nextTime.setMonth(nextTime.getMonth() + 1)  // 设置为下个月第一天
				nextTime.setDate(0)   // 设置为本月最后一天
				nextTime.setDate(nextTime.getDate() + (7 - (nextTime.getDay()||7)));  // 设置为结束
				
				return this.getDayList(nowTime,nextTime,[],oneTime)
			},
			getDayList(start, end, dayList=[],oneTime){
				if(start>end) return
				const nowTimeMs = new Date().setHours(0,0,0,0)
				const oneTimeMs = new Date(oneTime).getMonth()
				const startTime = new Date(start)
				const startTimeMs = startTime.setHours(0,0,0,0)
				const isAM = this.isActive(start, 0)
				const isPM = this.isActive(start, 1)
				const date = {
					year: startTime.getFullYear(), 
					month: startTime.getMonth() + 1,
					day: startTime.getDate(), 
					week: this.getWeekStr(startTime.getDay()||7),
					weekNumber: startTime.getDay()||7, 
					temps: new Date(start).getTime(),
					isNow: nowTimeMs == startTimeMs, 
					isFuture: nowTimeMs < startTimeMs,
					isMonth: oneTimeMs == startTime.getMonth(),
					isAM,
					isPM,
					isAct: isAM&&isPM,
				}
				dayList.push(date)
				startTime.setDate(startTime.getDate() +1)
				this.getDayList(new Date(startTime),end,dayList,oneTime)
				return dayList
			},
			getWeekStr(number){
				const _weeks = ["一", "二", "三", "四", "五", "六", "日"]
				return _weeks[number-1]
			},
			isActive(time,type = 0){  //type = 0 上午  | 1 下午
				const nowday = new Date(time).setHours(0,0,0,0)
				return this.selectTime.some(item=>{
					const actDate = new Date(item)
					const actday = new Date(item).setHours(0,0,0,0)
					const amVSpm = !type ? actDate.getHours()>=0&&actDate.getHours()<12 : actDate.getHours()>=12&&actDate.getHours()<=18
					return nowday == actday && amVSpm
				})
			},
		}
	}
</script>
<style lang="scss" scoped>
	// $theme-color: rgb(255, 165, 104);
	$theme-color: #1ABC9C;
	$am-color: rgb(8, 201, 95);
	// $pm-color: rgb(235, 148, 35);
	$pm-color: rgb(38, 129, 243);
	$act-color: rgb(38, 129, 243);
	.flex {display: flex;}
	.flex-items-center {align-items: center;}
	.flex-items-end {align-items:flex-end;}
	.flex-center {justify-content:center;}
	.flex-around {justify-content: space-around;}
	.flex-wrap {flex-wrap: wrap;}
	.flex-1 {flex: 1; min-width: 0;}
	.fit-height {height: 100%;}
	.graya{ color: #aaa; }
	.tc{ text-align: center; }
	.f26{font-size: 26rpx;}
	.f30{font-size: 30rpx;}
	.f32{font-size: 32rpx;}
	.f70{font-size: 70rpx;}
	.pb20{padding-bottom: 20rpx;}
	.pb15{padding-bottom: 15rpx;}
	.pb10{padding-bottom: 10rpx;}
	.pt5{padding-top: 5rpx;}
	.mt30{margin-top: 30rpx;}
	.mt20{margin-top: 20rpx;}
	.mt15{margin-top: 15rpx;}
	.ml5{margin-left: 5rpx;}
	.w7{ width: calc(100% * 1/7); }

	.wx-card {
		border-radius: 12rpx;
		background-color: #fff;
		padding: 30rpx;
	}
	.card-header{
		width: 150rpx;
		padding-right: 30rpx;
	}
	.swiper-week{
		height: 120rpx;
	}
	.swiper-month{
		height: 300rpx;
	}
	.isAM,.isPM,.isAct{
		// color: $theme-color;
		position: relative;
		&::after{
			display: block;
			content: '';
			position: absolute;
			left: 50%;
			top: 100%;
			transform: translate(-50%,0);
			margin-top: -10rpx;
			width: 10rpx;
			height: 10rpx;
			border-radius: 10rpx;
			background-color: $theme-color;
		}
		&.isAM{
			// color: $am-color;
			&::after{
				background-color: $am-color;
			}
		}
		&.isPM{
			// color: $pm-color;
			&::after{
				background-color: $pm-color;
			}
		}
		&.isAct{
			// color: $act-color;
			&::after{
				background-color: $act-color;
			}
		}
	}
	.active{
		position: relative;
		display: flex;
		align-items: center;
		justify-content: center;
		.isSelect{
			position: relative;
			color: $theme-color;
			&::after{
				display: block;
				content: '';
				position: absolute;
				width: 50rpx;
				height: 50rpx;
				border: 1px solid $theme-color;
				border-radius: 50%;
				left: 50%;
				top: 50%;
				z-index: -1;
				transform: translate(-50%,-50%);
			}
		}
		.isNowWap{
			position: relative;
			color: #fff;
			&::after{
				display: block;
				content: '';
				position: absolute;
				width: 50rpx;
				height: 50rpx;
				border: 1px solid $theme-color;
				background: $theme-color;
				border-radius: 50%;
				left: 50%;
				top: 50%;
				z-index: -1;
				transform: translate(-50%,-50%);
			}
		}

	}
	
</style>

2.在需要的页面中进行引入

//标签

<moSimpleDate :fold='true' :active="true" @changeTime="changeTime" @clickTime="clickTime"/>




//引入

import moSimpleDate from './moSimpleDate.vue'
components: {
	moSimpleDate
},



//方法

//进入页面初始化会走一次此方法
changeTime(time) {
	console.log('切换', time.temps)
    //打印出来当天时间戳
},

//选中某一日期会走此方法
clickTime(time) {
	console.log('点击', time.temps)
    //打印出来选中日期的时间戳
},

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值