封装一个日历面板

<template>
    <div class="calendar-panel">
        <!-- 日历头部 -->
        <div class="calendar-header">
            <button @click="changeMonth(-1)">&lt;</button>
            <span v-if="currentdataType=='day'" @click="showYearMonthPanel" class="header-text">
                {{ currentMoment.format('YYYY年 MM月') }}
            </span>
            <span v-if="currentdataType=='month'" @click="showYearMonthPanel" class="header-text">
                {{ currentMoment.format('YYYY年') }}
            </span>
            <button @click="changeMonth(1)">&gt;</button>
        </div>

        <!-- 主日历面板 -->
        <div class="calendar-content">
            <!-- 星期表头 -->
            <div class="calendar-weeks" v-show="currentdataType=='day'">
                <div v-for="week in weeks" :key="week" class="week-item">{{ week }}</div>
            </div>

            <!-- 日期格子 -->
            <div class="calendar-days" v-if="currentdataType=='day'">
                <div v-for="day in days" :key="day.date" class="day-item" :class="{
            'other-month': !day.currentMonth,
            'selected': isSelected(day.date),
            'today': isToday(day.date)
          }" @click="selectDate(day.date)">
                    {{ day.day }}
                </div>
            </div>
            <div class="calendar-months" v-if="currentdataType=='month'">
                <div v-for="month in monthss" :key="month" class="month-item" :class="{
  
            'selected': isSelected(month.month),'today': isToday(month.month),
       
          }" @click="selectDate(month.month)">
                    {{ month.key }}
                </div>
            </div>
        </div>

        <!-- 年月选择面板 -->

    </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import moment from 'moment'
import 'moment/locale/zh-cn' // 设置中文

moment.locale('zh-cn') // 使用中文

const props = defineProps({
    modelValue: {
        type: String,
        default: moment().format('YYYY-MM-DD')
    },
    type: {
        type: String,
        default: 'day'
    }
})
const currentdataType = ref(props.type)

const emit = defineEmits(['update:modelValue'])

// 基础数据
const weeks = ['日', '一', '二', '三', '四', '五', '六']
const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']

// 当前显示的日期
const currentMoment = ref(moment(props.modelValue))

// 年月选择面板控制
const showYearMonth = ref(false)
const tempYear = ref(currentMoment.value.year())
const tempMonth = ref(currentMoment.value.month())
const yearRangeStart = ref(Math.floor(currentMoment.value.year() / 10) * 10)

// 计算当月所有日期
const days = computed(() => {
    const days = []
    const firstDay = moment(currentMoment.value).startOf('month')
    const lastDay = moment(currentMoment.value).endOf('month')

    // 上月补充的天数
    const firstDayWeek = firstDay.day()
    for (let i = firstDayWeek; i > 0; i--) {
        const date = moment(firstDay).subtract(i, 'days')
        days.push({
            date: date,
            day: date.date(),
            currentMonth: false
        })
    }

    // 当月的天数
    for (let i = 1; i <= lastDay.date(); i++) {
        const date = moment(currentMoment.value).date(i)
        days.push({
            date: date,
            day: i,
            currentMonth: true
        })
    }

    // 下月补充的天数
    const lastDayWeek = lastDay.day()
    for (let i = 1; i < 7 - lastDayWeek; i++) {
        const date = moment(lastDay).add(i, 'days')
        days.push({
            date: date,
            day: date.date(),
            currentMonth: false
        })
    }
    return days
})
const monthss = computed(() => {
    const months = []
    const firstDay = moment(currentMoment.value).year()

    for (let i = 1; i <=12; i++) {
        months.push({
            month:moment(`${firstDay}-${i<10?i.toString().padStart(2, '0'):i}`),
            date:`${firstDay}-${i<10?i.toString().padStart(2, '0'):i}`,
            key:i+'月'
        })
    }
    return months
})


// 年份范围
const yearRange = computed(() => {
    return Array.from({ length: 12 }, (_, i) => yearRangeStart.value + i - 1)
})

const yearRangeText = computed(() => {
    return `${yearRangeStart.value} - ${yearRangeStart.value + 9}`
})

// 显示年月选择面板
const showYearMonthPanel = () => {
    showYearMonth.value = true
    tempYear.value = currentMoment.value.year()
    tempMonth.value = currentMoment.value.month()
    yearRangeStart.value = Math.floor(currentMoment.value.year() / 10) * 10
}

// 切换年份范围
const changeYearRange = (offset) => {
    yearRangeStart.value += offset
}

// 切换月份
const changeMonth = (offset) => {
    if (currentdataType.value == 'day') {
        currentMoment.value = moment(currentMoment.value).add(offset, 'months')
    } else if (currentdataType.value == 'month') {
        currentMoment.value = moment(currentMoment.value).add(offset, 'year')
    }

}

// 选择年份
const selectYear = (year) => {
    tempYear.value = year
}

// 选择月份
const selectMonth = (month) => {
    tempMonth.value = month
    currentMoment.value = moment([tempYear.value, month, 1])
    showYearMonth.value = false
}

// 选择日期
const selectDate = (date) => {
    emit('update:modelValue', date.format('YYYY-MM-DD'))
}

// 判断是否是选中日期
const isSelected = (date) => {
  if(currentdataType.value=='day'){
    return date.format('YYYY-MM-DD') === moment(props.modelValue).format('YYYY-MM-DD')
  }else if(currentdataType.value=='month'){
    return date.format('YYYY-MM') === moment(props.modelValue).format('YYYY-MM')
  }
}

// 判断是否是今天
const isToday = (date) => {
  if(currentdataType.value=='day'){
    return date.format('YYYY-MM-DD') === moment().format('YYYY-MM-DD')
  }else if(currentdataType.value=='month'){
    return date.format('YYYY-MM') === moment().format('YYYY-MM')
  }
   
}

// 判断是否是当前月份
const isCurrentMonth = (month) => {
  
    return month === moment().month() && tempYear.value === moment().year()
}
</script>

<style scoped>
.calendar-panel {
	width: 100%;
	border-radius: 4px;
	background: #fff;
	display: flex;
	flex-direction: column;
	height: 100%;
	width: 100%;
}

.calendar-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 12px;
}
.calendar-content {
	flex: 1;
	display: flex;
  flex-direction: column;
}

.calendar-header button {
	border: none;
	background: none;
	cursor: pointer;
	padding: 4px 8px;
}

.calendar-weeks {
	display: grid;
	grid-template-columns: repeat(7, 1fr);
	text-align: center;
	margin-bottom: 8px;
}

.week-item {
	height: 32px;
	line-height: 32px;
	color: #606266;
}

.calendar-days {
	display: grid;
	grid-template-columns: repeat(7, 1fr);
	gap: 2px;
}
.calendar-months {
	display: grid;
	flex: 1;
	padding: 10px;
	grid-template-columns: repeat(4, 1fr);
	gap: 2px;
}

.day-item {
	height: 32px;
	line-height: 32px;
	text-align: center;
	cursor: pointer;
	border-radius: 4px;
}
.month-item {
	display: flex;
	justify-content: center;
	align-items: center;
	text-align: center;
	cursor: pointer;
	border-radius: 4px;
}

.day-item:hover {
	background-color: #f5f7fa;
}
.month-item:hover {
	background-color: #f5f7fa;
}

.day-item.other-month {
	color: #c0c4cc;
}

.day-item.selected {
	background-color: #409eff;
	color: #fff;
}
.month-item.selected {
	background-color: #409eff;
	color: #fff;
}

.day-item.today {
	color: #409eff;
	font-weight: bold;
}
.month-item.today {
	color: #409eff;
	font-weight: bold;
}

.day-item.selected.today {
	color: #fff;
}
.month-item.selected.today {
	color: #fff;
}
</style>

在页面中使用:

//日期格式的
<penlCaneldar v-model="selectedDate" type="day"/>
const selectedDate = ref(moment().format('YYYY-MM-DD'))

月份格式的
 <penlCaneldar v-model="selectedDate" type="month" />
const selectedDate = ref(moment().format('YYYY-MM-DD'))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值