作为iphone用户,系统自带的日历实在不太合我意(对农历展示不友好之类的),第三方安装的app广告多内容杂,所以就想着花一点点时间,基于trae,写个自己的日历。
日历是个相对来说比较常用,又比较简单的应用,是个练手、消磨时光的好项目,用不了几天就出结果了:
mobile: www.10d.asia/m/rili/
而且,再加上点pwa的能力,还可以做到缓存提速,离线可访问,免下载直接安装:
pc:浏览器地址栏上面点直接安装,后续就可以像应用一样双击打开了
mobile:以safari为例,添加到主屏幕后就可以像应用那样使用了
pc端
先试用trae开发pc版,毕竟pc版本会相对简单些。 不要企图一步到位,写一堆的提示词,不然会有各种奇怪的问题,建议还是自己分好步骤一步一步来,例如可以先初始化一个项目:
利用现有脚手架,初始化一个react、ts、rsbuild的前端项目
如果不说脚手架,trae有时候会自己一个一个的创建文件,然后生成一个半吊子的项目。
然后,再提示添加日历功能并能切换月份,添加农历展示,添加回今天,添加pwa的能力等,一步一步来,一步一步调。
慢慢的一个丑陋的基本的日历框架就出来了,这一块还是能省挺多时间的,这里就不发出来了,可能每个人做出来,丑的都不一样,看了意义也不大。
作为技术文章,代码多少还是要讲一讲的,日历的核心代码其实并不复杂。
日历的绘制是一个月一个月进行绘制,切换也是,所以核心逻辑便是找到你要绘制的那个月的第一天和最后一天,然后遍历,生成一个二维数组,这个二维数组里面放的便是每周周一到周日的日期数据。最后基于这个二维数据绘制出一个grid的网格,便是日历了:
const { days, weeks } = useMemo(() => {
// date为绘制月中的任一天
const startOfMonth = date.startOf('month');
// pc的屏幕大,可以多显示一个星期的数据,不想要的话,把add去掉就是
const endOfMonth = date.endOf('month').add(1, 'week')
// isoWeek,星期一为第一天,否则会是周期日为第一天
const startDate = startOfMonth.startOf('isoWeek');
const endDate = endOfMonth.endOf('isoWeek');
const days: dayjs.Dayjs[] = [];
let currentDate = startDate;
while (currentDate.isBefore(endDate)) {
days.push(currentDate);
currentDate = currentDate.add(1, 'day');
}
const weeks = Array.from(
{ length: Math.ceil(days.length / 7) },
(_, i) => days.slice(i * 7, (i + 1) * 7)
);
return { days, weeks };
}, [date.valueOf()]);
相信对于很多前端开发来说,到这一步并不难,不如动手一试。然后接下来的细节调整和ui交互优化ai的帮助不大,就各凭本事了。
pwa
这里我并不准备讲service-worker.ts里面的代码,网上很多资料,给点提示词,ai基本也能帮你生成。我要讲的是trae没办法帮你实现的。
icon
网站需要一个icon,安装成桌面app,更需要一个icon。这要是在以前,我们还需要找个ui设计师帮忙设计,现在我们只是练练手的话,其实ai帮忙生成的也已经不错了,例如某克首页就有很多ai能力:
老不给我生成背景透明的,没事我有例如某图的抠图;
还给我的图片加了水印,没事我有消除笔;
以上纯举例,具体凭实力自由发挥。
部署
pwa是要在https下才能生效的。
首先你要有个服务器,用来部署代码;然后需要申请个域名,用来访问服务器;然后还需要申请个https证书,部署到服务器,证明我们服务的安全性。大概花个几十块(100以下)。
如果是大陆的服务器,要备案,否则没办法访问。非大陆虽然说是没有这个限制,但是某些运营商会限制访问。
作者一开始就是部署在香港服务器上面,但是pc可以访问,手机端用移动网络的情况下就访问不了了。后来又买了个大陆服务器,直接pc和手机端都不能访问了,因为没备案!
移动端
有了pc端后,可以基于pc端的代码开发移动端。本人的做法是新建新的移动端文件,然后提取公共(例如日历的核心代码部分就是pc和移动端可以复用的)。一般不习惯做一个文件然后多端适配,除非区别不大,否则徒增难度和复杂度。
移动端,由于屏幕变小了,ui调整是必然的。除了常规的整体界面尺寸变化,还有一些特殊地方需要各种进行定制化,例如多节日:
pc(看一下2026年6月21日):
移动端(看一下2026年6月21日):
而且移动端是手指滑动,所以除了保留pc的点击头部箭头切换月份外,还要做左右滑动切换。而这应该算是比较大的改动,而且ai只能帮点小忙,帮不上什么大忙,主要还是要自己实现。
这里有点像图片轮播的那种,滑一下,切换下个或者上个月份,滑一下,切换下个或者上个月份。这也是老生常谈的一个功能了,甚至也有现成的很多组件库。
但是还是有一些区别,日历的滑动需要做虚拟列表滑动,因为用户是可以无限左滑或者无限右滑的。
逻辑也不复杂:列表中,每次实际绘制的就是3个月的内容(当前月、上个月、下个月),切换后,再次绘制当前月、上个月,下个月。这样可以保证每次滑动交互的完整性体验,还能保证性能。
下面截图便是第一次打开的时候,0是当前月,-1是上个月,1是下个月。
随意切换后,依然还是只绘制3个月。13是当前月,12是上个月,14是下个月。这个序号是基于第一次打开时候的那个月份进行计算的。