重新用ts+v3写了一下,简化了一些功能,需要的自取
功能:
1.左右滚动切换月历周历
2.下面活动事项支持轮播,根据选中天自动更新当天事项
月历
周历
<template>
<div class="calender-container">
<div class="calender-content" :style="{minHeight:isWeek ? '180px' : '400px'}">
<div class="calender-title">
<div class="calender-title-left">{{ checkedDay }}div>
<div class="calender-title-right" @click="toggleMove">{{ isWeek ? '按周' : '按月' }}div>
div>
<div class="week-head-con">
<div class="week-head-item" v-for="(item, index) in WEEK_LIST" :key="index">{{ item.text }}div>
div>
<transition name="fade">
<div
class="month-container"
@touchstart="handleMoveStart"
@touchend="handleMoveEnd"
@touchmove="handleMove"
:class="{ transition: transition }"
:style="{ transform: 'translate3d(' + calenderMove.x + 'px,' + calenderMove.y + 'px,0px)', height: isWeek ? '70px' : '300px' }"
>
<div v-for="(month, index) in monthList" :key="index" class="month-item">
<div v-for="(week, weekindex) in month" :key="weekindex" class="month-week">
<div
v-for="(day, dayindex) in week"
:class="{ ischecked: checkedDay == day.date, istoday: day.istoday, }"
@click.stop="chooseDay(day)"
:key="dayindex"
class="month-week-item"
>
<div
class="week-day"
:class="{ ischecked: checkedDay == day.date, othermonth: day.othermonth, istoday: day.istoday, }"
>
<span class="one-day">
<i class="day" :class="day.istoday ? 'today' : ''">{{ day.day }}i>
span>
<div class="thing" v-if="day.thing && day.thing.infos && day.thing.infos.length > 0">
<a>a>
div>
div>
div>
div>
div>
div>
transition>
div>
<div class="things-content" v-if="dateThing && dateThing.length > 0">
<Swipe :autoplay="5000" indicator-color="#7687E9">
<SwipeItem v-for="(item, index) in dateThing" :key="index">
<div class="mb-20">
<p>
<span class="title thing-title">今日事项:span><span class="dis-in-block">{{
item.title }}span>
p>
<p>
<span class="title">地点:span><span class="dis-in-block">{{ item.address }}span>
p>
<p>
<span class="title">时间:span><span class="dis-in-block">{{ item.date }}span>
p>
div>
SwipeItem>
Swipe>
div>
<div v-else class="things-content">暂无事项div>
div>
template>
<script setup lang="ts">
import { ref, onMounted, Ref } from 'vue';
import { Swipe, SwipeItem,Popup,DatetimePicker } from 'vant';
const isShowDatePicker = ref<boolean>(false);//是否显示时间选择弹窗
// 头部星期列表
const WEEK_LIST = [
{
text: '一'
},
{
text: '二'
},
{
text: '三'
},
{
text: '四'
},
{
text: '五'
},
{
text: '六'
},
{
text: '日'
}
];
const dateThing = ref([]);//某天事项
// 全部事项,用来插入到日历中
const things = ref([
{
date: '2023-04-11',
infos: [
{
title: '人才招聘001',
address: '北京紫荆城',
date: '2020-11-11 09:00-18:00'
},
{
title: '人才招聘002',
address: '上海外滩',
date: '2020-11-11 09:00-18:00'
}
]
},
{
date: '2023-03-15',
infos: [
{
title: '人才招聘会人才',
address: '苏州市昆山市',
date: '2020-11-15 09:00-18:00'
}
]
},
{
date: '2023-03-14',
infos: [
{
title: '人才招聘004',
address: '苏州市吴中区',
date: '2020-11-14 09:00-18:00'
},
{
title: '人才招聘005',
address: '苏州市工业园区',
date: '2020-11-14 09:00-18:00'
}
]
},
{
date: '2023-03-29',
infos: [
{
title: '人才招聘004',
address: '苏州市吴中区',
date: '2020-11-18 09:00-18:00'
},
{
title: '人才招聘005',
address: '苏州市工业园区',
date: '2020-11-18 09:00-18:00'
}
]
},
{
date: '2023-02-11',
infos: [
{
title: '人才招聘004',
address: '苏州市吴中区',
date: '2020-12-11 09:00-18:00'
},
{
title: '人才招聘005',
address: '苏州市工业园区',
date: '2020-12-11 09:00-18:00'
}
]
}
]);
const dispDate = ref<Date>(new Date());//当前时间
type DayType = {
date?: string | number;
istoday?: boolean;
othermonth?: boolean;
thing?: {
infos: any[]; // 替换任何具体的类型,如果有具体的事件信息类型
};
}
type MonthList = DayType[];
const monthList = ref<MonthList>([]);
const today = ref<Date>(new Date());//当前时间
const checkedDay = ref('');//选中时间
const currentDay = ref<Date>(new Date());//当前时间
const transition = ref<boolean>(true);//是否显示动画
const calenderHeight = ref<number>(-100); //日历的高度
const calenderMove: Ref<{ x: number, y: number }> = ref({ x: 0, y: 0 });
const moveStartX = ref<number>(0); //开始移动的位置x轴
const moveStartY = ref<number>(0); //开始移动的位置y轴
const moveStartCalenderHeight = ref<number>(0); //开始移动的高度初始值
const itemWidth = ref<number>(0); //窗口的宽度
const moveIndex = ref<number>(0); // 左右移动 1 向右移动,-1向左移动,点击天0
const isWeek = ref<boolean>(false); //是否是周历模式
onMounted(() => {
todayDate();
get3month();
initCalenderInfo();
});
const selectDay = ref<Date>(new Date());
/**
* 获取今天日期
*/
const todayDate = () => {
checkedDay.value = formatDateTime(today.value);
selectDay.value = new Date(checkedDay.value);
};
/**
* 初始化当天事项
*/
const initCalenderInfo = () => {
const todayThing = monthList.value.flat(2).find(item => item.date === checkedDay.value)?.thing;
dateThing.value = todayThing?.infos || [];
};
/**
* 转换时间格式
* @param date 标准时间
*/
const formatDateTime = (date: Date): string => {
let 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 get3month = () => {
let year = dispDate.value.getFullYear();
let month = dispDate.value.getMonth();
monthList.value = [];
monthList.value.push(getMonth(year, month - 1));
monthList.value.push(getMonth(year, month));
monthList.value.push(getMonth(year, month + 1));
};
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 => {
let monthArr = [];
let dtFirst = new Date(year, month, 1); //每个月第一天
let dtLast = new Date(year, month + 1, 0); //每个月最后一天
let monthLength = dtLast.getDate() - dtFirst.getDate() + 1;
let space = (dtFirst.getDay() - 1 + 7) % 7; //月历前面空格
for (let i = -space; i < 36; i += 7) {
let week = [];
for (let j = 0; j < 7; j++) {
let day = i + j + 1;
if (day > 0 && day <= monthLength) {
let weekItem: weekParams = {
mode: 'month',
day: day,
year: year,
month: month,
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,
};
week.push(weekItem);
} else {
//其它月份
let newdt = new Date(year, month, day);
let years = newdt.getFullYear();
let months = newdt.getMonth();
let days = newdt.getDate();
let 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 year 年
* @param month 月
* @param day 日
*/
const ifOrder = (year: number, month: number, day: number) => {
let dateTime = format(year, month, day);
let dateItem = {};
things.value.map(item => {
if (dateTime === item.date) {
dateItem = item;
}
});
return dateItem;
};
/**
* 转换时间
* @param year 年
* @param month 月
* @param day 日
*/
const format = (year: number, month: number, day: number | string) => {
month++;
let m = month < 10 ? '0' + month : month;
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; }
const chooseDay = ({ year, month, day, othermonth, mode, thing }: chooseDayParams): void => {
currentDay.value = new Date(year, month, day);//标准时间
checkedDay.value = format(year, month, day);//"2020-11-11"
if (othermonth && mode === 'month') {
let tmpDt = new Date(
dispDate.value.getFullYear(),
dispDate.value.getMonth() - othermonth,
0
);
let maxday = tmpDt.getDate();
let 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?.infos || [];
};
/**
* 获取三周
*/
const get3week = () => {
let year = dispDate.value.getFullYear();
let month = dispDate.value.getMonth();
let 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) => {
let dt = new Date(year, month, day);
let weekArr = [];
let dtFirst = new Date(year, month, day - (dt.getDay() + 6) % 7);
let week = [];
//循环选中当天所在那一周的每一天
for (let j = 0; j < 7; j++) {
let newdt = new Date(
dtFirst.getFullYear(),
dtFirst.getMonth(),
dtFirst.getDate() + j
);
let years = newdt.getFullYear();
let months = newdt.getMonth();
let days = newdt.getDate();
let weekItem: weekParams = {
mode: 'week',
day: days,
year: years,
month: months,
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;
};
/**
* 左右移动
* @param index 月的index
* @param isWeek 是否显示周
* @param isClick 移动不可点击
*/
const changeIndex = (index: number, isClick = false) => {
if (isWeek.value) {
dispDate.value = new Date(
dispDate.value.getFullYear(),
dispDate.value.getMonth(),
dispDate.value.getDate() + 7 * index
);
checkedDay.value = format(
dispDate.value.getFullYear(),
dispDate.value.getMonth(),
dispDate.value.getDate()
);
currentDay.value = dispDate.value;
get3week();
} else {
let tmpDt = new Date(
dispDate.value.getFullYear(),
dispDate.value.getMonth() + index,
0
);
let maxday = tmpDt.getDate();
let 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();
}
initCalenderInfo();
};
/**
* 手机端端开始移动
* @param e event
*/
const handleMoveStart = (e: any) => {
let touch = e?.changedTouches[0] || e;
moveStartX.value = touch.clientX;
moveStartY.value = touch.clientY;
moveStartCalenderHeight.value = calenderHeight.value;
moveIndex.value = 0;
};
/**
* 手机端端移动
* @param e event
*/
const handleMove = (e: any) => {
let touch = e?.changedTouches[0] || e;
calenderMove.value.x = touch.clientX - moveStartX.value;
};
/**
* 手机端端结束移动
* @param e event
*/
const handleMoveEnd = (e: any) => {
let touch = e?.changedTouches[0] || e;
if (moveStartX.value < touch.clientX) {
if (moveStartX.value - touch.clientX < -150) {
calenderMove.value.x = itemWidth.value;
moveIndex.value = -1;
} else {
calenderMove.value.x = 0;
}
} else {
if (moveStartX.value - touch.clientX > 150) {
calenderMove.value.x = -itemWidth.value;
moveIndex.value = 1;
} else {
calenderMove.value.x = 0;
}
}
changeIndex(moveIndex.value, false);
};
/**
* 切换月或周
* @param e event
*/
const toggleMove = () => {
isWeek.value = !isWeek.value;
if (isWeek.value) {
get3week();
} else {
get3month();
}
};
</script>