小程序签到组件

在components目录下创建一个vue文件

<template>
  <view class="calendar">
    <view class="header" style="display: flex; justify-content: space-between; align-items: center; margin-top: 50rpx; background-color: #f8f8f8;">
	
	<view class="month">
		{{currentDate}}
	</view>
	<view class="year">
	{{year}}
	</view>
      <!-- <view class="current-date">{{ currentDate }}</view> -->
	  <view class="btn btn-prev" @click="onSwitchPrevMonth()">
		  <uni-icons style="margin-left: 300rpx;" type="left" size="24"></uni-icons>
		  
	  </view>
	  <view class="btn btn-next" @click="onSwitchNextMonth()">
		  <uni-icons type="right" size="24"></uni-icons>
	  </view>
		
    </view>
    <view class="body">
      <view class="weeks">
        <view class="week-item" v-for="week in weeks" :key="week"
          >{{ week }}
        </view>
      </view>
      <view class="day-list">
        <view
          :class="{
            'day-item': true,
            today: day.isToday,
            checked: day.checked,
            'current-month-day': day.type === 'current'
          }"
          v-for="(day, index) in dayList"
          :key="index"  
        >
          <text class="text">{{ day.checked ? '√' : day.day }}</text>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  props: {
    checks: {
      type: Array,
      default() {
        return []
      }
    }
  },
  data() {
    return {
      year: null,
      month: null,
      day: null,
      dayList: [],
      weeks: ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
    }
  },
  computed: {
    currentDate() {
      const year = this.year
      const month = this.month < 10 ? '0' + this.month : this.month
      return month
    }
  },
  watch: {
    checks() {
      this.initDate()
    }
  },
  created() {
    const { year, month, day } = this.getCurrentDate()

    this.initDate(year, month, day)
  },
  methods: {
    initDate(year = this.year, month = this.month, day = this.day) {
      const dayList = this.getDayList(year, month)

      this.year = year
      this.month = month
      this.day = day
      this.dayList = dayList
    },
	//点击日期签到
    handleClick(day) {
      const payload = {
        year: this.year,
        month: this.month,
        ...day
      }

      switch (day.type) {
        case 'prev':
          this.onSwitchPrevMonth(day)
          break
        case 'next':
          this.onSwitchNextMonth(day)
          break
        default:
          this.$emit('current-month-day', payload)
      }
    },
    onSwitchPrevMonth(day) {
      const { prevYear, prevMonth } = this.getPrevMonthInfo(
        this.year,
        this.month
      )
      const payload = {
        year: prevYear,
        month: prevMonth,
        oldYear: this.year,
        oldMonth: this.month,
        ...day
      }

      this.initDate(prevYear, prevMonth)
      this.$emit('prev-month-day', payload)
    },
    onSwitchNextMonth(day) {
		console.log(111)
      const { nextYear, nextMonth } = this.getNextMonthInfo(
        this.year,
        this.month
      )
      const payload = {
        year: nextYear,
        month: nextMonth,
        oldYear: this.year,
        oldMonth: this.month,
        ...day
      }

      this.initDate(nextYear, nextMonth)
      this.$emit('next-month-day', payload)
    },
    getPrevMonthInfo(year, month) {
      let prevYear = year
      let prevMonth = month - 1

      if (prevMonth < 1) {
        prevMonth = 12
        prevYear -= 1
      }

      return {
        prevYear,
        prevMonth
      }
    },
    getNextMonthInfo(year, month) {
      let nextYear = year
      let nextMonth = month + 1

      if (nextMonth > 12) {
        nextMonth = 1
        nextYear += 1
      }

      return {
        nextYear,
        nextMonth
      }
    },
    getDayList(year, month) {
      const prevMonthDays = this.getPrevMonthDays(year, month)
      const currentMonthDays = this.getCurrentMonthDays(year, month)
      const nextMonthDays = this.getNextMonthDays(year, month)

      return [...prevMonthDays, ...currentMonthDays, ...nextMonthDays]
    },
    getCurrentDate() {
      const date = new Date()
      const year = date.getFullYear()
      const month = date.getMonth() + 1
      const day = date.getDate()

      return {
        year,
        month,
        day
      }
    },
    getMonthLastDay(year, month) {
      const { nextYear, nextMonth } = this.getNextMonthInfo(year, month)
      const date = new Date(`${nextYear}/${nextMonth}/1`)
      const firstDayTimeStamp = date.getTime()
      const oneDayTimeStamp = 24 * 60 * 60 * 1000
      const prevMonthLastDay = new Date(
        firstDayTimeStamp - oneDayTimeStamp
      ).getDate()

      return prevMonthLastDay
    },
    getPrevMonthDays(year, month) {
      const { prevYear, prevMonth } = this.getPrevMonthInfo(year, month)
      const prevMonthLastDay = this.getMonthLastDay(prevYear, prevMonth)
      const date = new Date(`${year}/${month}/1`)
      const week = date.getDay()

      const days = []

      for (let i = 0; i < week; i++) {
        days.unshift({
          type: 'prev',
          checked: false,
          day: prevMonthLastDay - i
        })
      }

      return days
    },
    getCurrentMonthDays(year, month) {
      const currentMonthLastDay = this.getMonthLastDay(year, month)
      const checks = this.checks
      const days = []
      const {
        year: currentYear,
        month: currentMonth,
        day: currentDay
      } = this.getCurrentDate()

      for (let i = 1; i <= currentMonthLastDay; i++) {
        let checked = false
        let isToday =
          currentYear === year && currentMonth === month && currentDay === i

        checks.forEach(date => {
          const dateArr = date.split('-')

          if (year == dateArr[0] && month == dateArr[1] && i == dateArr[2]) {
            checked = true
          }
        })

        days.push({
          type: 'current',
          checked,
          isToday,
          day: i
        })
      }
      return days
    },
    getNextMonthDays(year, month) {
      const currentMonthLastDay = this.getMonthLastDay(year, month)
      const date = new Date(`${year}/${month}/${currentMonthLastDay}`)
      const week = date.getDay()
      const days = []

      let day = 0

      for (let i = week + 1; i <= 6; i++) {
        day++

        days.push({
          type: 'next',
          checked: false,
          day
        })
      }

      return days
    }
  }
}
</script>

<style lang="scss" scoped>
.calendar {
	width: 702rpx;
	margin:  0 auto;
  background-color: #fff;
  color: $uni-text-color;
  .header {
    padding: 0 24upx;
    display: flex;
    justify-content: space-between;
    // border-bottom: 2upx solid #eee;
    .current-date {
      text-align: center;
      font-size: 24upx;
      padding: 32upx 0;
      color: #030303;
    }
    .btn-group {
      display: flex;
      align-items: center;
      .btn {
        line-height: 1;
        background: #fff;
        border: 1px solid #dcdfe6;
        color: #606266;
        text-align: center;
        box-sizing: border-box;
        font-weight: 500;
        padding: 12upx 20upx;
        font-size: 24upx;
        &.btn-prev {
          border-radius: 2px 0 0 2px;
          border-right: 0;
        }
        &.btn-next {
          border-radius: 0 2px 2px 0;
        }
      }
    }
  }
  .body {
    .weeks {
      display: flex;
      font-size: 26upx;
      padding: 32upx 0;
      .week-item {
        flex: 1;
        text-align: center;
      }
    }
    .day-list {
      display: flex;
      flex-wrap: wrap;
      .day-item {
        display: flex;
        justify-content: center;
		align-items: center;
        width: 14.285%;
        text-align: center;
        padding: 20upx 0;
        font-size: 36upx;
        color: #c8c8c8;
        &.current-month-day {
          color: #171717;
        }
        &.checked,
        &.today {
          // padding: 26upx 0;
          .text {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 80upx;
            height: 80upx;
            // border-radius: 100%;
            box-sizing: border-box;
            background-color: #9263FE;
            color: #fff;
            font-size: 28upx;
            padding: 28upx 0;
          }
        }
      }
    }
  }
}
.year{
	width: 108rpx;
	height: 70rpx;
	font-size: 48rpx;
	font-family: Source Han Sans CN-Regular, Source Han Sans CN;
	font-weight: 400;
	color: #BFBFBF;
}
.month{
	width: 54rpx;
	height: 70rpx;
	font-size: 48rpx;
	font-family: Source Han Sans CN-Regular, Source Han Sans CN;
	font-weight: 400;
	color: #1A1A1A;
}
</style>

2.引入

<template>
	<view class="box">
		<view class="custom-title-box">
			<view class="status-bar-height-box" :style="{height: statusBarHeight + 'px'}"></view>
			<view class="title-box" :style="{height: titleHeight + 'px'}">
				<uni-icons type="back" class="left" size="30" color="#fff" @click="back()"></uni-icons>
				签到
			</view>
		</view>
		<view class="empty-box" :style="{height: statusBarHeight + titleHeight + 'px'}" style="width: 100%;"></view>
		<ss-calendar class="s" :checks="checks" @current-month-day="onSignIn" @prev-month-day="onPrev" @next-month-day="onNext" />
		<button @click="signIn" class="click">签到</button>
	</view>
</template>

<script>
	import ssCalendar from '@/components/ss-calendar/ss-calendar.vue'
	export default {
		components: {
			ssCalendar
		},
		data() {
			return {
				statusBarHeight: 0, // 状态栏高度
				titleHeight: 0, // 标题栏高度
				checks: ["2023-08-01"],
			}
		},
		onLoad() {
			this.checks = uni.getStorageSync("qd")
		},
		onReady() {
			uni.getSystemInfo({
				success: res => {
					this.statusBarHeight = res.statusBarHeight
				}
			})
			const btnInfo = uni.getMenuButtonBoundingClientRect();
			this.titleHeight = (btnInfo.top - this.statusBarHeight) * 2 + btnInfo.height
		},
		methods: {
			back() {
				uni.navigateBack()
			},
			onSignIn(payload) {
				const {
					checked,
					year,
					month,
					day
				} = payload;
				const today = new Date();
				const todayYear = today.getFullYear();
				const todayMonth = today.getMonth() + 1; // 月份从0开始计算,需要加1
				const todayDay = today.getDate();
				if (!checked && year === todayYear && month === todayMonth && day === todayDay) {
					this.checks.push(`${year}-${month}-${day}`);
				}
				console.log('onSignIn', payload);
			},
			signIn() {
				const currentDate = new Date().toISOString().split('T')[0]; // 获取当前日期的字符串表示,例如:Sat Nov 20 2021
				if (!this.checks.includes(currentDate)) {
					this.checks.push(currentDate);
					// uni.setStorageSync("qd",this.checks)
					uni.showToast({
						title: "签到成功"
					})

				} else {
					uni.showToast({
						title: "今天已签过",
						icon: "none"
					})
					console.log('今天已经签过到了!');
				}
				uni.setStorageSync("qd", this.checks)
			},
			onPrev(payload) {
				console.log('onPrev', payload)
			},
			onNext(payload) {
				console.log('onNext', payload)
			}

		},
	}
</script>
<style lang="scss">
	.custom-title-box {
		width: 750rpx;
		position: fixed;
		top: 0;
		left: 0;
		z-index: 999;
		background-color: #9263FE;

		.title-box {
			// background-color: red;
			display: flex;
			justify-content: center;
			align-items: center;
			font-size: 36rpx;
			color: #FFFFFF;

			>image {
				width: 346rpx;
				height: 96rpx;
			}

			.left {
				width: 60rpx;
				height: 60rpx;
				position: absolute;
				left: 24rpx;
				bottom: 10rpx;
			}
		}
	}

	.box {
		width: 750rpx;
		height: 1624rpx;
		background-color: #F8F8F8;
		position: relative;
	}
	.s{
		width: 702rpx;
		margin: 0 auto;
		
	}
	.click{
		width: 382rpx;
		height: 110rpx;
		background: #9263FE;
		border-radius: 60rpx 60rpx 60rpx 60rpx;
		opacity: 1;
		font-size: 44rpx;
		font-family: PingFang SC-Medium, PingFang SC;
		font-weight: 400;
		color: #FFFFFF;
		text-align: center;
		line-height: 110rpx;
		margin-top: 52rpx;
	}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值