简言
分享一下自己基于uniapp写的日历组件。如果不太满足你的需求,可以自己改造。
日历
实现分析:
- 页面显示 - 分为顶部显示和日历显示,我这里做了多行和单行显示两种情况,主要是当时看着手机的日历做的,手机上的日历单行和多行显示切换特别丝滑,但是我没实现出来。(我觉得限制原因是当时水平不够,再加上滚动用的uniapp的swipper组件,不能定制化实现)。
- 分屏滚动 - 使用 uniapp的swipper组件,我这里,单行使用这个月周+上个月最后一周+下个月最后一周数据,多行使用这个月+上个月+下个月数据;这样处理的原因是在进行月份切换的时候可以先显示数据然后进行数据更新,实现无感无限切换滚动。
- 各种事件 - 点击日期发送选中日期的数据。
- 数据逻辑 - 主要是先确定你想要的数据结构,然后以这个为单位组装成行(周)数组或多行(月)数组。
没有自己实现滚动,也算是取了巧。感觉难点就是日期的数据处理 和 滚动,已经单多行切换了。
代码: uniapp写的 vue2和vue3应该都能用,样式注意使用了sass。
<template>
<view class="calendar">
<view class="wrapper">
<slot
name="top"
:nowMonthText="nowMonthText"
:pickerMonth="pickerMonth"
:prevMonth="prevMonth"
:nextMonth="nextMonth"
>
<view class="top">
<view class="month-box">
<view class="month-text">
<view class="uni-input" @tap="pickerMonth">{
{
nowMonthText
}}</view>
</view>
<view class="back-today" @tap="goToday">回到今天</view>
</view>
<view class="top-left">
<view class="icon-arrow arrow-left" @tap="previousFn"></view>
<view class="icon-arrow arrow-right" @tap="nextFn"></view>
</view>
</view>
</slot>
<view class="calender-box">
<view class="head-title">
<view
class="head-title-item"
v-for="v in calenderTitleList"
:key="v"
>{
{ v }}</view
>
</view>
<!-- 一行显示 -->
<swiper
v-if="showType === 1"
class="row-swiper"
circular
:disable-programmatic-animation="true"
:duration="duration"
:current="swiperCurrent"
@change="swipereChangFn"
>
<swiper-item
v-for="(v, index) in calenderRowDaysList"
:key="index"
:item-id="v.label"
>
<view class="row-days-list">
<view
class="days-list-item"
v-for="(item, i) in v.value"
:key="`${index}-${i}`"
:class="{
used: item.used,
}"
>
<view
class="label"
v-if="(isNowMonth && item.isNowMonth) || !isNowMonth"
:class="{
disabled: item.disabled,
}"
@tap="clickDay(item)"
>
<view
class="text"
:class="{
'active-item':
nowSelectDay && nowSelectDay['time'] === item.time,
'active-item--disabled':
nowSelectDay &&
nowSelectDay['time'] === item.time &&
item.disabled,
'today-text':
item.label === '今' &&
nowSelectDay &&
nowSelectDay['time'] !== item.time &&
!item.disabled,
}"
>
{
{ item.label }}
</view>
<view
v-show="!item.disabled && item.state"
class="state-item text-state-item"
>
</view>
<view
class="item-adjust"
v-if="!item.disabled && item.adjust && item.adjust.value"
:class="{ 'text-state-leave': item.adjust.value == '1' }"
>
{
{ item.adjust.value == "1" ? "休" : "课" }}
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
<!-- 全行显示 -->
<swiper
v-else
class="all-swiper"
circular
:disable-programmatic-animation="true"
:duration="duration"
@change="swipereChangFn"
:current="swiperCurrent"
:class="{
'six-height':
swiperDaysList[0] && swiperDaysList[0].value.length / 7 === 6,
}"
>
<swiper-item
v-for="(v, index) in swiperDaysList"
:key="index"
:item-id="v.label"
>
<view class="days-list">
<view
class="days-list-item"
v-for="(item, i) in v.value"
:key="`${index}-${i}`"
:class="{
used: item.used,
}"
>
<view
class="label"
v-if="(isNowMonth && item.isNowMonth) || !isNowMonth"
:class="{
disabled: item.disabled,
}"
@tap="clickDay(item)"
>
<view
class="text"
:class="{
'active-item':
nowSelectDay && nowSelectDay['time'] === item.time,
'active-item--disabled':
nowSelectDay &&
nowSelectDay['time'] === item.time &&
item.disabled,
'today-text':
item.label === '今' &&
nowSelectDay &&
nowSelectDay['time'] !== item.time &&
!item.disabled,
}"
>
{
{ item.label }}
</view>
<view
v-show="!item.disabled && item.state"
class="state-item"
></view>
<view
class="item-adjust"
v-if="!item.disabled && item.adjust && item.adjust.value"
:class="{ 'text-state-leave': item.adjust.value == '1' }"
>
{
{ item.adjust.value == "1" ? "休" : "课" }}
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
<view v-if="!hideArrow" class="arrow-wrapper" @click="showTypeChange">
<view
class="arrow-left"
:class="{ 'arrow-left--up': showType === 0 }"
></view>
<view
class="arrow-right