开局看demo
代码块中用到的
函数在最底下
数据结构设计
- 日期数组
dateList
// 获取日期列表
const dateList = getMonthDateList(2024, 12)
- 事件数组
eventList
// 事件列表
const eventList = ref([
{
start: new Date('2024-11-30 8:00').getTime(),
end: new Date('2024-12-05 17:00').getTime(),
title: '测试事件0',
id: 0,
color: 'pink'
},
{
start: new Date('2024-12-05 8:00').getTime(),
end: new Date('2024-12-07 17:00').getTime(),
title: '测试事件1',
id: 1,
color: '#69C0FF'
},
{
start: new Date('2024-12-05 8:00').getTime(),
end: new Date('2024-12-06 17:00').getTime(),
title: '测试事件2',
id: 2,
color: '#FF9F7F'
},
{
start: new Date('2024-12-06 8:00').getTime(),
end: new Date('2024-12-06 17:00').getTime(),
title: '测试事件4',
id: 4,
color: '#B37FEB'
},
{
start: new Date('2024-12-26 8:00').getTime(),
end: new Date('2024-12-27 17:00').getTime(),
title: '测试事件3',
id: 3,
color: '#FFC069'
},
{
start: new Date('2024-11-01 8:00').getTime(),
end: new Date('2024-12-03 17:00').getTime(),
title: '测试事件5',
id: 5,
color: '#73D13D'
},
{
start: new Date('2024-12-05 8:00').getTime(),
end: new Date('2024-12-07 17:00').getTime(),
title: '测试事件6',
id: 6,
color: '#40A9FF'
},
{
start: new Date('2024-12-10 8:00').getTime(),
end: new Date('2024-12-12 17:00').getTime(),
title: '测试事件7',
id: 7,
color: '#FF85C0'
},
{
start: new Date('2024-12-15 8:00').getTime(),
end: new Date('2024-12-16 17:00').getTime(),
title: '测试事件8',
id: 8,
color: '#36CFC9'
},
{
start: new Date('2024-12-18 8:00').getTime(),
end: new Date('2024-12-19 17:00').getTime(),
title: '测试事件9',
id: 9,
color: '#597EF7'
},
{
start: new Date('2024-12-21 8:00').getTime(),
end: new Date('2024-12-22 17:00').getTime(),
title: '测试事件10',
id: 10,
color: '#FFB8B1'
},
{
start: new Date('2024-12-23 8:00').getTime(),
end: new Date('2024-12-24 17:00').getTime(),
title: '测试事件11',
id: 11,
color: '#87E8DE'
},
{
start: new Date('2024-12-28 8:00').getTime(),
end: new Date('2024-12-29 17:00').getTime(),
title: '测试事件12',
id: 12,
color: '#ADC6FF'
},
{
start: new Date('2024-12-30 8:00').getTime(),
end: new Date('2024-12-31 17:00').getTime(),
title: '测试事件13',
id: 13,
color: '#FFE58F'
},
{
start: new Date('2024-12-13 8:00').getTime(),
end: new Date('2024-12-14 17:00').getTime(),
title: '测试事件14',
id: 14,
color: '#9254DE'
}
])
- 预期结果
字段注释已添加
// eventDistribution
{
'2024-12-01': [
{
id: 1, // 事件唯一标识
title: '测试事件1', // 事件标题
start: 1701388800000, // 事件开始时间戳
end: 1701475200000, // 事件结束时间戳
color: '#FF4D4F', // 事件颜色
days: 2, // 当前周内事件持续天数
index: 0, // 事件在当天的显示层级
isFirstDay: true // 是否为事件的第一天或当周第一天
}
],
'2024-12-02': [
{
id: 1,
title: '测试事件1',
start: 1701388800000,
end: 1701475200000,
color: '#FF4D4F',
days: 1,
index: 0,
isFirstDay: false
}
]
}
数据处理
- 将日期列表按周分割
// 将日期列表按周分割
const splitDateList = splitDatesByWeek(dateList)
- 对
eventList进行排序。
排序的规则:
先按开始时间排序,其次开始时间相同时按结束时间排序。
// 按时间戳排序
const sortList = sortByTimeStamp(eventList.value)
- 其次按日期分配事件
将事件按日期分配到每一天,并记录当前事件的前一天的标记位
index
// 按日期分配事件
/* 示例
{
'2024-12-01': [event1, event2],
'2024-12-02': [event3],
}
*/
const eventDistribution = {}
// 遍历每周
splitDateList.forEach((week, weekIndex) => {
const weekStart = week[0];
const weekEnd = week[week.length - 1];
week.forEach((currentDate, dayIndex) => {
const dateIndex = weekIndex * 7 + dayIndex;
const currentDateEvents = getCurrentDateEvents(currentDate, weekStart, weekEnd, sortList);
currentDateEvents.forEach(event => {
setEventDisplayProperties(event, currentDate, dayIndex, dateIndex, dateList, eventDistribution, currentDateEvents);
});
eventDistribution[currentDate] = currentDateEvents;
});
});
以上代码块用到的方法util.js
// 按时间戳排序
export function sortByTimeStamp(eventList) {
return eventList.sort((a, b) => {
// 先按开始时间排序
const startDiff = a.start - b.start;
if (startDiff !== 0) {
return startDiff;
}
// 开始时间相同时按结束时间排序
return b.end - a.end;
})
}
// 将日期列表按周分割
export function splitDatesByWeek(dates) {
const result = [];
for (let i = 0; i < dates.length; i += 7) {
result.push(dates.slice(i, i + 7));
}
return result;
}
// 获取日期列表
export const getMonthDateList = (year, month) => {
// 获取当月第一天是星期几
const firstDayOfMonth = new Date(`${year}-${String(month).padStart(2, '0')}-01`).getDay()
// 获取当月最后一天
const lastDayOfMonth = new Date(year, month, 0).getDate()
// 获取上月最后一天
const lastDayOfLastMonth = new Date(year, month - 1, 0).getDate()
// 计算年月
const prevYear = month === 1 ? year - 1 : year
const prevMonth = month === 1 ? 12 : month - 1
const nextYear = month === 12 ? year + 1 : year
const nextMonth = month === 12 ? 1 : month + 1
const dateList = []
// 添加上月日期
for (let i = firstDayOfMonth - 1; i >= 0; i--) {
dateList.push(`${prevYear}-${String(prevMonth).padStart(2, '0')}-${String(lastDayOfLastMonth - i).padStart(2, '0')}`)
}
// 添加本月日期
for (let i = 1; i <= lastDayOfMonth; i++) {
dateList.push(`${year}-${String(month).padStart(2, '0')}-${String(i).padStart(2, '0')}`)
}
// 添加下月日期,补齐到42天(6周)
for (let i = 1; dateList.length < 42; i++) {
dateList.push(`${nextYear}-${String(nextMonth).padStart(2, '0')}-${String(i).padStart(2, '0')}`)
}
return dateList
}
// 获取日期的ISO格式字符串(YYYY-MM-DD)
const getISODateString = (date) => {
return new Date(date).toISOString().split('T')[0];
}
// 计算两个日期之间的天数
export const getDaysBetweenDates = (startDate, endDate) => {
return Math.floor((new Date(endDate) - new Date(startDate)) / (24 * 60 * 60 * 1000)) + 1;
}
// 获取当天的事件列表
export const getCurrentDateEvents = (currentDate, weekStart, weekEnd, sortList) => {
return sortList.filter(event => {
const eventStartDate = getISODateString(event.start);
const eventEndDate = getISODateString(event.end);
return eventStartDate <= currentDate && eventEndDate >= currentDate;
}).map(event => {
const eventStartDate = getISODateString(event.start);
const eventEndDate = getISODateString(event.end);
const startDate = eventStartDate < weekStart ? weekStart : eventStartDate;
const endDate = eventEndDate > weekEnd ? weekEnd : eventEndDate;
const days = getDaysBetweenDates(startDate, endDate);
return { ...event, days };
});
}
// 设置事件的显示属性
export const setEventDisplayProperties = (event, currentDate, dayIndex, dateIndex, dateList, eventDistribution, currentDateEvents) => {
const previousDate = dateIndex > 0 ? dateList[dateIndex - 1] : null;
const previousEvent = previousDate ? eventDistribution[previousDate]?.find(item => item.id === event.id) : null;
event.index = previousEvent?.index ??
(currentDateEvents[0]?.index ?? 0) + currentDateEvents.findIndex(item => item.id === event.id);
event.isFirstDay = dayIndex === 0 ||
getISODateString(event.start) === currentDate;
}
// 处理颜色透明度
export const handleColorOpacity = (color, opacity = 1) => {
// 处理rgba格式
if (color.startsWith('rgba')) {
const values = color.match(/[\d.]+/g);
return `rgba(${values[0]}, ${values[1]}, ${values[2]}, ${opacity})`;
}
// 处理rgb格式
if (color.startsWith('rgb')) {
const values = color.match(/\d+/g);
return `rgba(${values[0]}, ${values[1]}, ${values[2]}, ${opacity})`;
}
// 处理十六进制格式
if (color.startsWith('#')) {
let hex = color.replace('#', '');
// 处理简写的十六进制
if (hex.length === 3) {
hex = hex.split('').map(char => char + char).join('');
}
const r = parseInt(hex.slice(0, 2), 16);
const g = parseInt(hex.slice(2, 4), 16);
const b = parseInt(hex.slice(4, 6), 16);
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
}
return color;
}
未完成...