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

2023-09-18 13:51:15

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>

在这里插入图片描述

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

更多推荐

60+开源数据集资源大合集(医学图像、卫星图像、语义分割、自动驾驶、图像分类等)

1.医学图像疟疾细胞图像数据集下载链接:http://suo.nz/2VQTUt皮肤癌MNIST:HAM10000下载链接:http://suo.nz/33n6Xy该数据集收集了来自不同人群的皮肤镜图像,通过不同的方式获取和存储。最终数据集包含10015张皮肤镜图像,可用作学术机器学习目的的训练集。案例包括色素病变领域

记一次 Java Testcontainers CPU 100% 问题排查过程

以为代码进入了死循环,结果并没有!文章目录背景与问题排查过程代码路经确认内存分析咨询okio社区等等,好像并没有死循环能否从内存快照发现其他问题?背景与问题本问题来源于ShardingSphereissue:Integrationtestsoccasionallystuckinwaitingforcontainerre

C++之template可变模板参数应用总结(二百二十八)

简介:CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀人生格言:人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.更多原创,欢迎关注:Android系统攻城狮1.前言本篇目的:C++之

步步为营,如何将GOlang引用库的安全漏洞修干净

文章目录引场景构建第一步、直接引用的第三方库升级修复策略1.确认是否为直接引用的第三方库2.找到需要升级的版本是否为release版本第二步、间接引用的第三方库升级修复策略那么问题来了,我们这么间接引用库的对应的直接引用库是哪个呢?(一)没有release版本,但直接引用库有最新的代码可升级(1)将最新代码下载到项目某

Redis 集合(Set)快速指南 | Navicat

Redis支持通过多种数据类型来存储项目集合。其中,包括列表、集合和哈希。上周的博文介绍了列表(List)数据类型并重点介绍了一些用于管理列表(List)的主要命令。在今天的文章中,我们将转向关注集合(Set)数据类型。在Redis中,集合(Set)与列表(List)相似,但是,集合(Set)中的元素是无序的,并且每个

skywalking入门

参考:https://www.jianshu.com/p/ffa7ddcda4ab参考:https://developer.aliyun.com/article/1201085skywalking(APM)调用链路分析以及应用监控分析工具Skywalking主要由三大部分组成:agent、collector、webap

行为型模式-策略模式和责任链模式对比

一、区别:目的和问题解决方式:策略模式的主要目的是将一组算法或行为封装成独立的策略对象,并使客户端能够在运行时选择其中一个策略来执行。这种模式通常用于实现相同操作的不同算法或策略之间的切换和替换。责任链模式的主要目的是将请求的发送者和接收者解耦,允许多个对象依次处理请求,直到其中一个对象能够处理请求为止。责任链模式通常

opencv dnn模块 示例(16) 目标检测 object_detection 之 yolov4

博客【opencvdnn模块示例(3)目标检测object_detection(2)YOLOobjectdetection】测试了yolov3及之前系列的模型,有在博客【opencvdnn模块示例(15)opencv4.2版本dnn支持cuda加速(vs2015异常解决)】说明了如何使用dnn模块进行cuda加速推理。

Android 混淆使用及其字典混淆(Proguard)

1.使用背景ProGuard能够通过压缩、优化、混淆、预检等操作,检测并删除未使用的类,字段,方法和属性,分析和优化字节码,使用简短无意义的名称来重命名类,字段和方法。从而使代码更小、更高效、更难进行逆向工程。Android代码混淆,又称Android混淆,是一种AndroidAPP保护技术,用于保护APP不被破解和逆

css知识学习系列(2)-每天10个知识点

目录1.基础知识CSS中的伪元素和实际元素有什么区别?2.动画与过渡CSS中的transition和animation有何区别?在什么情况下使用哪种动画?3.Flexbox在Flexbox布局中,“flex-wrap”属性有什么作用?4.Grid请解释CSS中的网格线(gridlines)和轨道(tracks)是什么?

Docker 容器生命周期:创建、启动、暂停与停止

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

热文推荐