面试题要求用vue3+uniapp写一个日程组件?--5/1000
- 相关代码github:github.com/tinlee/1000…
背景
众所周知,我最近在找工作,然后就遇到了一道面试题(需要面试题和简历一起提交)。具体要求如下:
需求分析
- 这是一个日程管理程序, 所以需要一个日历,需要可以录入日程
- 需要有月度和天的展示,月度用一个日历,天用时间线
- 日程可以录入标题,时间,备注等,可以删除
看着这些需求,鉴于我有限的审美能力,我决定还是抄借鉴一个吧。所以目光锁定了ios的系统日程表,审美在线。
页面需求
这里暂时就定为2个页面和一个弹窗
- 一个月显示的页面。显示当月所有日期,如果当前日期有日程,则显示一个红点。激活的当天,显示为红色背景。
- 一个日显示的页面。以时间轴显示当天所有日程,按照0:00-24:00分布。
- 一个新建日程页面,为了简化步骤,先以类似腾讯会议的形式,只允许添加某一天的时间。同时这个弹窗也是新增/编辑/删除/查看四合一的页面。这样就大大简化了所需的书写代码。
相关依赖
- uni-app
- pinia
- dayjs
- uni-ui
核心编码部分
日历部分
这里的日历计算方式,就是先拿到我们的月份,然后获取第一天。因为日历显示的是周日开始,所以根据第一天是周几,然后向前减去几天。
// date 为当前需要计算的日期
const dateObj = dayjs(date);
const monthStart = dateObj.startOf("month");
const dayOfWeek = monthStart.day();
const fistDay = monthStart.subtract(dayOfWeek, "day");
这样我们就拿到了日历的开始第一天的日期。然后进行遍历,一般情况下,日历显示42天,开始不足的部分由上月补足,结尾不足的部分由下月补足。补足的部分要用灰色显示。
// 需要生成一个6*7的数组
const days: CurrentDate[][] = new Array(6).fill(0).map(() => []);
for (let i = 0; i < 42; i++) {
const currentDate = fistDay.add(i, "day");
// 每7天即添加到下一个数组
days[Math.floor(i / 7)].push({
date: currentDate,
showDate: currentDate.date(),
formatDate: currentDate.format("YYYY-MM-DD"),
isCurrtentMonth: currentDate.month() === dateObj.month(),
isToday: currentDate.isSame(dayjs(), "day"),
});
}
整体的数据结构如下
export type CurrentDate = {
date: dayjs.Dayjs; // 当前时间的原始时间
showDate: number; // 显示在日历中的1-31
isCurrtentMonth?: boolean; //是否为当月
isToday: boolean; // 是否为今天
formatDate: string; // 年月日的完整展示,这里用来跟后面的是否有日程做比对,如果有会在日历中展示一个小红点
};
渲染数据,并做如下判断:
- 如果isCurrtentMonth为false,则不是当月,用灰色显示
- 如果isToday为true,则为今天,用背景红色展示
- 如果时间列表中有formatDate的数据,则展示一个小点,代表今天有日程
数据组织部分
核心的pinia store,包括以下几个state
- viewStatus:'mouth'|'day' 代表了视图的切换,目前就两个视图,一个月,一个日
- day:dayjs.Dayjs 代表当前所在的时间,在月页面即哪个月,在日页面为哪一周
- list:List 代表了所有事件存储的列表,这个部分下面再单独说一下
- editInfo:Data 代表了编辑所使用的数据
list根据日期来进行分类 整体结构为
{
"2024-05-15": {
"10:00-12:00": [
{
title: "Meeting",
startTime: "10:00",
date: "2024-04-15",
endTime: "12:00",
remark: "Discuss the plan for the next quarter",
},
{
title: "Interview",
startTime: "10:00",
endTime: "12:00",
date: "2024-04-15",
remark: "Interview candidate for the front-end position",
},
],
}
这里根据日期对整体做一个初步的map,然后根据每个日程的时间范围,做二次map,这样相同高度的日程就可以聚合在一起,而不同时间的日程,就可以显示在不同的位置。
每组数据,跟日常中的相关字段对应
日的渲染部分
根据list进行遍历,对于具体日程,根据"开始时间-结束时间"这个key进行具体的划分。然后计算出当前这个时间段的高度,以及相对于顶部的位置。
const dateList = computed(() => {
const { list, day } = store
const dayText = dayjs(day).format('YYYY-MM-DD')
const dateList = list[dayText] // 获取当天日程信息
return Object.keys(dateList).map(key => {
const item = dateList[key]
const [startHour, endHour] = key.split('-') //开始时间结束时间拆分
return {
list: item,
top: getTop(startHour) + '%', //顶部top
height: (getTop(endHour) - getTop(startHour)) + '%' 时间差的高度
}
})
})
function getTop(time, isEnd = false) {
const [hour, minute] = time.split(':')
const top = (hour * 60 + minute * 1) / 1440 * 100 // 根据时和分,转化后,除以24小时的时间,算出百分比
return top
}
- 相关代码github:github.com/tinlee/1000…
我是天元,立志做
1000个有趣的项目
的前端,公众号:cssandjs
如果你喜欢的话,请
点赞,收藏,转发
。
评论
领取永不言败
勋章
历史文章
转载自:https://juejin.cn/post/7363108549592023103