uniapp----微信小程序 日历组件(周日历&& 月日历)【Vue3+ts+uView】

文章来源:CSDN 发布日期:2024-04-12 分类:小程序博客 阅读( )

uniapp----微信小程序 日历组件(周日历&& 月日历)【Vue3+ts+uView】

  1. 用Vue3+ts+uView来编写日历组件;
  2. 存在周日历和月日历两种显示方式;
  3. 高亮显示当天日期,红点渲染有数据的日期,点击显示数据

1. calendar-week-mouth组件代码

<template>    <view class="calender-container">        <view class="calender-content">            <!-- 头部 -->            <view class="calender-title" v-if="isWeek">                <view class="calender-title-left">{{ checkedDay }}</view>                <view class="calender-title-morebtn" v-if="isMorebtn" @click="toggleMove">更多</view>                <view class="calender-title-right" @click="popupShowBtn" v-if="ispopupShow"></view>            </view>            <view class="calender-title" v-if="!isWeek">                <view class="calender-title-chevronl" @click="changeMonth(-1)">                    <text class="iconfont icon-back text-[28rpx]"></text>                </view>                <view class="calender-title-mouth">{{ MoutnTitle }}</view>                <view class="calender-title-chevronr calender-title-chevronr-right">                    <text class="iconfont icon-right text-[28rpx]" @click="changeMonth(1)"></text>                </view>            </view>            <!-- 星期头部 -->            <view class="calender-week-head">                <view class="calender-week-head-item" v-for="(item, index) in WEEK_LIST" :key="index">                    {{ item.text }}                </view>            </view>            <transition name="fade">                <view class="calender-month-container" :class="{ transition: transition }" :style="{                    height: isWeek ? '120rpx' : '540rpx'                }">                    <view v-for="(month, index) in monthList" :key="index" class="calender-month-item">                        <view v-for="(week, weekindex) in month" :key="weekindex" class="calender-month-week">                            <!--   :class="{ ischecked: checkedDay == day.date, istoday: day.istoday }" -->                            <view v-for="(day, dayindex) in week" :class="{ ischecked: checkedDay == day.date }"                                @click.stop="chooseDay(day)" :key="dayindex" class="calender-month-week-item">                                <view class="calender-week-day" :class="{                                    ischecked: checkedDay == day.date,                                    othermonth: day.othermonth                                }">                                    <span class="calender-one-day">                                        <i class="day">{{                                            day.othermonth === -1 || day.othermonth === 1                                            ? ''                                            : day.day                                        }}</i>                                    </span>                                    <!-- 有事项标记 -->                                    <view class="thing" v-if="day.thing.task_time != null">                                        <i class="dot"></i>                                    </view>                                </view>                            </view>                        </view>                    </view>                </view>            </transition>        </view>        <slot></slot>    </view>    <!-- 日历问号提示弹出框 -->    <w-calender-popup :popupShow="popupShow"></w-calender-popup></template><script setup lang="ts">import { ref, onMounted, watch, nextTick } from 'vue'const props = withDefaults(    defineProps<{        isWeek: boolean        things: Array<any> //日期对应的相关数据 数据格式 一维数组        ispopupShow: boolean        isMorebtn: boolean    }>(),    {        isWeek: true, // true周 false 月        ispopupShow: true, // 是否显示?问号弹窗 默认显示        isMorebtn: false //是否显示日历更多按钮 默认不显示    })const emits = defineEmits(['chooseDay', 'toggleMove']) //组件传递数据const popupShow = ref<boolean>(false) //是否显示日历问号提示// 打开提示框const popupShowBtn = () => {    popupShow.value = !popupShow.value}// 头部星期列表const WEEK_LIST = [    {        text: '日'    },    {        text: '一'    },    {        text: '二'    },    {        text: '三'    },    {        text: '四'    },    {        text: '五'    },    {        text: '六'    }]const dateThing: any = ref([]) //某天事项// const things: any = ref([]) // 全部事项,用来插入到日历中const dispDate = ref<Date>(new Date()) //当前时间type DayType = {    date?: string | number    istoday?: boolean    othermonth?: boolean    thing?: []}type MonthList = DayType[]const monthList: Record<string, any> = ref<MonthList>([])const today = ref<Date>(new Date()) //当前时间const MoutnTitle = ref('') //当前月份 x-x格式const checkedDay = ref('') //选中时间const currentDay = ref<Date>(new Date()) //当前时间const transition = ref<boolean>(true) //是否显示动画const get3FullYear = ref(dispDate.value.getFullYear()) //定义当前年const get3Monthz = ref(dispDate.value.getMonth()) //定义当前月onMounted(() => {    setTimeout(() => {        todayDate()        props.isWeek ? get3week() : get3month(get3FullYear.value, get3Monthz.value)        initCalenderInfo()    }, 200)})watch(    () => props.things,    async () => {        await nextTick()        todayDate()        props.isWeek ? get3week() : get3month(get3FullYear.value, get3Monthz.value)        initCalenderInfo()    },    { immediate: true })const selectDay = ref<Date>(new Date())/** * 转换时间格式 * @param date 标准时间 */const formatDateTime = (date: Date): string => {    const y = date.getFullYear()    let m: string = date.getMonth() + 1 + ''    m = Number(m) < 10 ? '0' + m : m    let d = date.getDate() + ''    d = Number(d) < 10 ? '0' + d : d    return y + '-' + m + '-' + d}/** * 获取今天日期 */const todayDate = () => {    checkedDay.value = formatDateTime(today.value)    selectDay.value = new Date(checkedDay.value)    MoutnTitle.value = formatDateTime(today.value).substring(0, 7)}/** * 初始化当天事项 */const initCalenderInfo = () => {    const todayThing = monthList.value        .flat(2)        .find((item: any) => item.date === checkedDay.value)?.thing    dateThing.value = todayThing || []}/** * 返回该天事项 * @param year 年 * @param month 月 * @param day 日 */const ifOrder = (year: number, month: number, day: number) => {    const dateTime = format(year, month, day)    let dateItem = {}    props.things.map((item: any) => {        if (dateTime === item.task_time) {            dateItem = item        }    })    return dateItem}/** * 转换时间 * @param year 年 * @param month 月 * @param day 日 */const format = (year: number, month: number, day: number | string) => {    month++    const m = month < 10 ? '0' + month : month    Number(day) < 10 && (day = '0' + day)    return year + '-' + m + '-' + day}/** * 选中某一天 * @param year 年 * @param month 月 * @param day 日 * @param othermonth 其他月份,当前月前面空值 * @param mode 类型,'month','week' * @param thing 事项 */interface chooseDayParams {    year: number    month: number    day: number    othermonth: number    mode: string    thing: Thing[]}interface Thing {    date: string    infos?: ThingInfo[]}interface ThingInfo {    title: string    address: string    dates: string}/** * @description: 选中日期 * @param {*} year * @param {*} month * @param {*} day * @param {*} othermonth * @param {*} mode * @param {*} thing * @return {*} */const chooseDay = ({ year, month, day, othermonth, mode, thing }: chooseDayParams): void => {    currentDay.value = new Date(year, month - 1, day) //标准时间    checkedDay.value = format(year, month - 1, day) //"2020-11-11"    if (othermonth && mode === 'month') {        const tmpDt = new Date(dispDate.value.getFullYear(), dispDate.value.getMonth() - othermonth)        const maxday = tmpDt.getDate()        const days = maxday < day ? maxday : day        dispDate.value = new Date(year, month - othermonth, days)        changeIndex(othermonth || 0, true)    } else {        dispDate.value = currentDay.value    }    dateThing.value = thing || []    emits('chooseDay', checkedDay.value)}/** * 获取三周 */const get3week = () => {    const year = dispDate.value.getFullYear()    const month = dispDate.value.getMonth()    const day = dispDate.value.getDate()    monthList.value = []    monthList.value.push(getWeek(year, month, day - 7))    monthList.value.push(getWeek(year, month, day))    monthList.value.push(getWeek(year, month, day + 7))}/** * 获取星期 * @param year 为选中当天的年 * @param month 为选中当天的月 * @param day 为选中当天的日 */const getWeek = (year: number, month: number, day: number) => {    const dt = new Date(year, month, day)    const weekArr = []    const dtFirst = new Date(year, month, day - ((dt.getDay() + 7) % 7))    const week = []    //循环选中当天所在那一周的每一天    for (let j = 0; j < 7; j++) {        const newdt = new Date(dtFirst.getFullYear(), dtFirst.getMonth(), dtFirst.getDate() + j)        const years = newdt.getFullYear()        const months = newdt.getMonth()        const days = newdt.getDate()        const weekItem: weekParams = {            mode: 'week',            day: days,            year: years,            month: months + 1,            date: format(years, months, days),            //日历要显示的其他内容            thing: ifOrder(years, months, days),            istoday:                today.value.getFullYear() === years &&                    today.value.getMonth() === months &&                    today.value.getDate() === days                    ? true                    : false,            ischecked: false,            othermonth: months !== month        }        week.push(weekItem)    }    weekArr.push(week)    return weekArr}/** * 获取三个月(上月,本月,下月) */const get3month = (year: any, month: any) => {    monthList.value = []    monthList.value.push(getMonth(year, month - 1))    monthList.value.push(getMonth(year, month))    monthList.value.push(getMonth(year, month + 1))}const MonthType = ref(0) //0 当前月 -1上一个月 1下一个月let Mnum = 1 //计数let Ynum = 0// 点击上一个月 或者下一个月const changeMonth = (type: number) => {    MonthType.value = type    const date = new Date()    const year = date.getFullYear()    const month = date.getMonth()    let nextYear = year - Ynum    let chMonth = month + Mnum    if (type === -1) {        // 上一个月        Mnum -= 1        chMonth = month + Mnum        Ynum = chMonth <= 0 ? Ynum - 1 : Ynum        chMonth = chMonth <= 0 ? 12 + chMonth : chMonth    }    if (type === 1) {        // 下一个月        Mnum += 1        chMonth = month + Mnum        Ynum = chMonth > 12 ? Ynum + 1 : Ynum        chMonth = chMonth > 12 ? chMonth - 12 : chMonth    }    nextYear = year + Ynum    get3FullYear.value = nextYear //修改当前年    get3Monthz.value = chMonth - 1 //修改当前月    get3month(get3FullYear.value, get3Monthz.value)    const newMonthTitle = `${nextYear}-${chMonth < 10 ? '0' + chMonth : chMonth}`    MoutnTitle.value = newMonthTitle}interface weekParams {    mode: string    day: number    year: number    month: number    date: string    //日历要显示的其他内容    thing: ReturnType<typeof ifOrder>    istoday: boolean    ischecked: boolean    othermonth?: number | boolean}/** * 创建单月历 顺序是从周日到周六 * @param year 年 * @param month 月 */const getMonth = (year: number, month: number): DayType => {    const monthArr = [] as any    const dtFirst = new Date(year, month, 1) // 每个月第一天    const dtLast = new Date(year, month + 1, 0) // 每个月最后一天    const monthLength = dtLast.getDate() // 月份天数    const firstDayOfWeek = dtFirst.getDay() // 第一天是星期几    const rows = Math.ceil((monthLength + firstDayOfWeek) / 7) // 表格显示行数    for (let i = 0; i < rows; i++) {        const week = []        for (let j = 0; j < 7; j++) {            const day = i * 7 + j + 1 - firstDayOfWeek            if (day > 0 && day <= monthLength) {                const weekItem: weekParams = {                    mode: 'month',                    day: day,                    year: year,                    month: month + 1,                    date: format(year, month, day),                    // 日历要显示的其他内容                    thing: ifOrder(year, month, day),                    istoday:                        today.value.getFullYear() === year &&                            today.value.getMonth() === month &&                            today.value.getDate() === day                            ? true                            : false,                    ischecked: false,                    othermonth: 0                }                week.push(weekItem)            } else {                // 其它月份                const newDt = new Date(year, month, day)                const years = newDt.getFullYear()                const months = newDt.getMonth()                const days = newDt.getDate()                const weeksItem: weekParams = {                    mode: 'month',                    day: days,                    year: years,                    month: months,                    date: format(year, month, day),                    thing: ifOrder(year, month, day),                    istoday:                        today.value.getFullYear() === years &&                            today.value.getMonth() === months &&                            today.value.getDate() === days                            ? true                            : false,                    ischecked: false,                    othermonth: day <= 0 ? -1 : 1                }                week.push(weeksItem)            }        }        monthArr.push(week)    }    return monthArr}/** * 左右移动 * @param index 月的index * @param isWeek 是否显示周 * @param isClick 移动不可点击 */const changeIndex = (index: number, isClick = false) => {    if (props.isWeek) {        dispDate.value = new Date(            dispDate.value.getFullYear(),            dispDate.value.getMonth(),            dispDate.value.getDate() + 7 * index        )        currentDay.value = dispDate.value        get3week()    } else {        const tmpDt = new Date(dispDate.value.getFullYear(), dispDate.value.getMonth() + index, 0)        const maxday = tmpDt.getDate()        const days = maxday < dispDate.value.getDate() ? maxday : dispDate.value.getDate()        dispDate.value = new Date(            dispDate.value.getFullYear(),            dispDate.value.getMonth() + index,            days        )        if (!isClick) {            checkedDay.value = format(                dispDate.value.getFullYear(),                dispDate.value.getMonth(),                dispDate.value.getDate()            )        }        get3month(get3FullYear.value, get3Monthz.value)    }    initCalenderInfo()}/** * 切换月或周 * @param e event */const toggleMove = () => {    emits('toggleMove')}</script><style scoped lang="scss">.calender {    &-container {        width: 100%;    }    &-content {        color: #666666;    }    &-title {        display: flex;        &-left {            width: 70%;        }        &-right {            position: absolute;            right: 60rpx;            width: 50rpx;            height: 50rpx;            border: 1px solid #e51c15;            color: #e51c15;            line-height: 44rpx;            text-align: center;            border-radius: 50%;            font-size: 32rpx;            padding-left: 14rpx;        }        &-morebtn {            border: 2rpx solid #e51c15;            // padding: 10rpx 40rpx;            width: 120rpx;            height: 46rpx;            line-height: 46rpx;            text-align: center;            color: #e51c15;            box-sizing: border-box;            font-size: 24rpx;            margin-right: 20rpx;            border-radius: 10rpx;        }        &-chevronl text,        &-chevronr text {            color: #e51c15;            font-size: 28rpx;            font-weight: 400;            &-right {                text-align: right;            }        }        &-mouth {            width: 92%;            text-align: center;            font-size: 32rpx;            color: #666666;        }    }    &-week-head {        width: 100%;        display: flex;        align-items: center;        padding-top: 20px;        font-size: 24rpx;        font-weight: bold;        &-item {            // width: 14.2%;            flex: 1;            text-align: center;        }    }    &-month {        &-container {            display: flex;            position: relative;            height: 460rpx;        }        &-item {            position: absolute;            width: 100%;            min-height: 128rpx;            padding: 30rpx 0;            box-sizing: border-box;        }        &-item:nth-child(1) {            left: -110%;        }        &-item:nth-child(2) {            left: 0;        }        &-item:nth-child(3) {            left: 110%;        }        &-week {            display: flex;            align-items: center;            &-item {                // width: 14.2%;                flex: 1;                text-align: center;                position: relative;            }        }    }    &-week-day {        display: block;        text-align: center;        font-style: normal;        padding: 2rpx;        line-height: 60rpx;        height: 80rpx;        width: 80rpx;    }    &-one-day {        font-size: 24rpx;    }}.istoday .day,.ischecked .day {    width: 60rpx;    height: 60rpx;    color: #fff;    background: #e51c15;    border-radius: 50%;    line-height: 60rpx;    text-align: center;}// .ischecked {//     border-radius: 50px;//     color: #fff !important;//     background: #7687e9;// }.thing {    position: absolute;    left: 34%;    // bottom: 2px;    transform: translateX(-50%);    color: #e51c15;}.thing .dot {    display: block;    width: 12rpx;    height: 12rpx;    word-break: break-all;    line-height: 12rpx;    color: #e51c15;    background: #e51c15;    border-radius: 50%;    margin-top: 6rpx;}</style>

2. 在页面引用组件

<template><calendar-week-mouth :things="things" @chooseDay.stop="chooseDay" :isMorebtn="true" @toggleMove="toggleMove" ispopupShow :isWeek="isWeek"></calendar-week-mouth></template><script setup lang="ts">import { ref, watch, nextTick, shallowRef } from 'vue'import { onLoad, onShow } from '@dcloudio/uni-app'onLoad(async (options) => {    tag.value = Number(options.tag) || 1    isWeek.value = tag.value === 1 || false})const tag = ref(1) //tag 1是周日历显示 2是月日历显示const isWeek = ref(true)/** * @description: 点击单个日期获取选中的日期 * @param {*} date:选中的日期 xxxx-xx-xx * @return {*} */const chooseDay = (date: string) => {    checkedDay.value = date}// 点击更多const toggleMove = () => {    uni.navigateTo({ url: '/package-legal/task-list/task-list?tag=2' })}/**things数据结构重要的是task_time字段[{id: 4,status: 3,task_time: "2023-07-26",task_title: "",time: "222",}]*/</script>

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最新文章:

二维码