问题产生
最近需要一个组件,但是uview-plus 没有可以使用的日历组件,从而借鉴了网上的思路,写了一个以下代码,但是渲染的时候出现问了,命名设置了不同日期,但是在数组中并没有生效
这个是存在问题的图片
我已经计算出了上下月的日期 但是在push操作时并没有push成功,这是为什么? 有没有大神解释一下
代码
<template>
<view class="container" :style="{ background }">
<!-- 日历头部 -->
<view class="tmt-header">
<view class="select-wrap" :style="{ color: actionColor }">
<!-- 左箭头减少一月 -->
<view class="p20" @click="changMonth(-1)"> <view class="arrow-left" /> </view>
<!-- 单数字加前缀 0 -->
<view class="time"> {{ `${currentYearMonth.year}年${currentYearMonth.month >= 10 ? currentYearMonth.month : '0' + currentYearMonth.month}月`}} </view>
<!-- 右箭头增加一月 -->
<view class="p20" @click="changMonth(1)"> <view class="arrow-right" /> </view>
</view>
<!-- 返回本月 -->
<view class="back" @click="init(true)"> 返回本月 </view>
</view>
<!-- 日历内容 -->
<view class="tmt-content">
<!-- 星期标题展示 -->
<view class="tmt-week-wrap">
<view class="cell week-item" :style="{ color: weekColor }" v-for="(item, index) in week" :key="index">
{{ item.label }} </view>
</view>
<!-- 日期展示 -->
<view class="tmt-day-wrap" :style="({ height: unfold ? contentHeight : '88rpx' })">
<view class="cell" v-for="(item, index) in dateContent" @click="changeDay(item)">
<!-- 此处想订制不同月之间的数字 -->
<view class="dayText" :style="(current.year == item.year && current.month == item.month && current.day == item.day) ? 'background:' + selectBg : '',(item.type !== 0) ? 'color' + unSignColor : '' ">
<!-- 已经签到的日子 -->
<view class="point " :style="{ background: pointColor }" v-if="item.isSign" />
<view class="bgIcon" v-if="item.isSign"> <image src="@/static/image/Signin.svg" mode="widthFix" class="imgIcon" /> </view>
<text> {{ item.today ? '今' : item.day }} </text>
</view>
</view>
</view>
</view>
<!-- 折叠按钮 -->
<view v-if="showBtn" class="tmt-footer" @click="unfold = !unfold">
<view :class="['arrow-down', { on: unfold }]"></view>
</view>
</view>
</template>
<script setup lang="ts">
import { computed, CSSProperties, onMounted, reactive, ref, toRaw } from 'vue';
interface dateType {
year: number,
month: number,
day: number
}
interface signDateType extends dateType {
type?: number,// -1 上个月 0. 本月月 1. 下个月
today?: boolean,// 是不是今天
isSign?: boolean
}
interface weekType {
label: string,
value: number
}
const week: Array<weekType> = [
{
label: '一',
value: 1
},
{
label: '二',
value: 2
},
{
label: '三',
value: 3
},
{
label: '四',
value: 4
},
{
label: '五',
value: 5
},
{
label: '六',
value: 6
},
{
label: '日',
value: 7
}
]
const unfold = ref(true);
onMounted(() => {
unfold.value = props.show
init(false)
})
// 渲染用到的 30 天
const dateContent = reactive<Array<signDateType>>([]);
// 今天
const today = reactive<dateType>({} as dateType)
// 此刻年月 用于快速返回本月
const current = reactive<dateType>({} as dateType)
// 游标 记录展示的年月
const currentYearMonth = reactive({
year: -1,
month: -1,
})
const contentHeight = computed(() => Math.ceil(( dateContent.length) / 7) * 88 + 'rpx')
// 后端给的签到日子
const listData = [{
day: 1,
month: 12,
year: 2022,
},
{
day: 2,
month: 12,
year: 2022,
},
{
day: 2,
month: 12,
year: 2022,
},
]
interface PropType {
pointList?: Array<Object>,
defaultDate?: string,
showBtn?: boolean,
show?: boolean,
background?: string,
weekColor?: string,
dayColor?: string,
selectBg?: string,
pointColor?: string,
backColor?: string,
backBg?: string,
actionColor?: string,
unfoldBtnColor?: string,
unSignColor?: string
}
const props = withDefaults(defineProps<PropType>(), {
pointList: () => [],
defaultDate: '2022-11-11',
showBtn: true,
show: true,
background: 'linear-gradient(45deg, #5A24A6 0%, #7E3CB5 100%)',
weekColor: "#fff",
dayColor: "#fff",
selectBg: 'linear-gradient(180deg, #FF855E 0%, #ED6337 100%)',
pointColor: "#fff",
backColor: "#fff",
backBg: 'rgba(255, 255, 255, 0.19)',
actionColor: '#fff',
unfoldBtnColor: '#fff',
unSignColor: "red"
})
// 点击选中这个日期
const changeDay = (item: dateType) => {
current.year = item.year
current.month = item.month
current.day = item.day
console.log(item);
}
// 左右箭头 改变月份
const changMonth = (num: number) => {
const {
year,
month
} = getMonthYear(num)
makeCalendar(year, month)
}
// 点击左右箭头触发计算的月份与年份
const getMonthYear = (num: number) => {
let year = currentYearMonth.year
let month = currentYearMonth.month + num
// 负数月份
while (month <= 0) {
month += 12;
year -= 1;
}
// 大于12 月
while (month > 12) {
year += 1;
month -= 12;
}
return {
year,
month
}
}
// 初始化一个日期
const init = (isUserTime = true) => {
let setTime = isUserTime ? new Date() : new Date(props.defaultDate)
let year = setTime.getFullYear()
let month = setTime.getMonth() + 1
let day = setTime.getDate()
if (!(props.defaultDate != '' && isUserTime)) {
current.year = year;
current.month = month;
current.day = day;
}
today.year = new Date().getFullYear();
today.month = new Date().getMonth() + 1;
today.day = new Date().getDay();
makeCalendar(year, month)
}
const makeCalendar = (year: number, month: number) => {
// 修改展示月份标题
currentYearMonth.year = year;
currentYearMonth.month = month;
// 本次要展示的日子
let daysArr: Array<signDateType> = []
// 展示月的天数
let days = getDays(year, month)
// 上个月
let { year: lastYear, month: lastMonth } = getMonthYear(-1);
console.log(lastYear, lastMonth, "上个月");
// 上个月的天数
let lastDay = getDays(lastYear, lastMonth);
//获得展示月第一天的星期
let firstDayWeek = getWeekByDay(`${year}-${month}-1`);
// 找到起点
let weekIndex = week.findIndex(item => item.value == firstDayWeek);
// 上个月剩下未展示的天数
const lastShowDay = weekIndex == -1 ? 0 : weekIndex;
// 下个月
let { year: nextYear, month: nextMonth } = getMonthYear(1);
console.log(nextYear, nextMonth, "下个月");
// 下个月开头的天数
let nextDays = (7 - (days + lastShowDay) % 7) % 7;
// 1. 先添加上个月剩下的天数
for (let i = 1; i <= lastShowDay; i += 1) {
daysArr.push({
year: lastYear,
month: lastMonth,
day: lastDay - lastShowDay + i,
today: lastYear == today.year && lastMonth == today.month && lastDay - lastShowDay + i == today.day
});
}
// 2.添加本月的天数
for (let i = 1; i <= days; i++) {
daysArr.push({
year,
month,
day: i,
today: year == today.year && month == today.month && i == today.day
});
}
// 3.添加下个月的天数
for (let i = 1; i <= nextDays; i += 1) {
daysArr.push({
year: nextYear,
month: nextMonth,
day: i,
today: nextYear == today.year && nextMonth == today.month && i == today.day
});
}
// 添加签到日期
for (let i = 0; i < daysArr.length; i++) {
for (let j = 0; j < listData.length; j++) {
if (daysArr[i].day == listData[j].day && daysArr[i].month == listData[j].month) {
daysArr[i].isSign = true
}
}
}
// 修改指定日期的type
for (let i = 0; i < daysArr.length; i++) {
if (daysArr[i].month = currentYearMonth.month) {
daysArr[i].type = 0;
}
}
dateContent.length = 0;
dateContent.push(...daysArr);
console.log("本次渲染的日期", dateContent);
}
// 获取某年某月的天数
const getDays = (year: number, month: number) => new Date(year, month, 0).getDate()
//获取某一天为星期几
const getWeekByDay = (time: string) => {
let day = new Date(Date.parse(time.replace(/-/g, '/'))); //将日期值格式化
return day.getDay() == 0 ? 7 : day.getDay();
}
</script>
<style lang="less" scoped>
.p20 {
padding: 20upx;
}
.container {
padding: 0 20upx;
}
.tmt-header {
display: flex;
justify-content: space-between;
padding: 20upx 0;
.select-wrap {
display: flex;
align-items: center;
.arrow-left {
width: 18upx;
height: 18upx;
transform: rotate(45deg);
border-left-width: 1upx;
border-bottom-width: 1upx;
border-left-style: solid;
border-bottom-style: solid;
border-left-color: v-bind(actionColor);
border-bottom-color: v-bind(actionColor);
}
.time {
font-size: 36upx;
margin: 0 20upx;
}
.arrow-right {
width: 18upx;
height: 18upx;
transform: rotate(45deg);
border-top-width: 1upx;
border-right-width: 1upx;
border-top-style: solid;
border-right-style: solid;
border-left-color: v-bind(actionColor);
border-right-color: v-bind(actionColor);
}
}
.back {
padding: 0 20upx;
font-size: 24upx;
height: 52upx;
color: #fff;
line-height: 52upx;
background: rgba(255, 255, 255, .19);
text-align: center;
border-radius: 30upx;
color: v-bind(backColor);
background: v-bind(backBg);
}
}
.cell {
width: 14.28%;
height: 88upx;
text-align: center;
line-height: 88upx;
display: flex;
align-items: center;
justify-content: center;
position: relative;
.bgIcon {
position: absolute;
width: 100%;
height: 100%;
.imgIcon {
width: 100%;
display: block;
}
}
.point {
width: 6upx;
height: 6upx;
position: absolute;
bottom: 3upx;
border-radius: 50%;
left: 50%;
transform: translateX(-50%);
}
.dayText {
width: 56upx;
height: 56upx;
text-align: center;
line-height: 56upx;
border-radius: 50%;
&.on {
background: linear-gradient(180deg, #FF855E 0%, #ED6337 100%);
}
}
}
.tmt-content {
padding-bottom: 20upx;
.tmt-week-wrap {
display: flex;
.week-item {
font-size: 36upx;
}
}
.tmt-day-wrap {
display: flex;
flex-wrap: wrap;
transition: height .3s;
overflow: hidden;
color: v-bind(dayColor);
}
}
.tmt-footer {
display: flex;
align-items: center;
justify-content: center;
height: 80upx;
margin-top: -36upx;
.arrow-down {
width: 18upx;
height: 18upx;
transform: rotate(-45deg);
border-left-width: 1upx;
border-bottom-width: 1upx;
border-left-style: solid;
border-bottom-style: solid;
transition: all .3s;
border-left-color: v-bind(unfoldBtnColor);
border-bottom-color: v-bind(unfoldBtnColor);
&.on {
transform: rotate(135deg);
}
}
}
</style>