console
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>备忘录</title>
<style>
:root {
--green: #66bb6a;
--green-soft: #81c784;
--card: #f1f8f1;
--bg: #fbfdfb;
--text: #2c3e50;
--muted: #6b7f6f;
--line: rgba(102, 187, 106, 0.3);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
background: var(--bg);
color: var(--text);
min-height: 100vh;
display: flex;
justify-content: center;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
}
#app {
width: 100%;
max-width: 640px;
padding: 28px 16px 60px;
position: relative;
overflow-x: hidden;
}
/* ===== 列表页 ===== */
#listPage, #detailPage {
transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.35s;
}
.page-hidden-right {
transform: translateX(100%);
opacity: 0;
pointer-events: none;
position: absolute;
top: 28px;
left: 16px;
right: 16px;
}
.page-hidden-left {
transform: translateX(-100%);
opacity: 0;
pointer-events: none;
position: absolute;
top: 28px;
left: 16px;
right: 16px;
}
h1.title {
font-size: 24px;
font-weight: 600;
margin-bottom: 4px;
letter-spacing: 0.5px;
}
.subtitle {
color: #a3b3a3;
font-size: 12px;
margin-bottom: 24px;
}
.memo-card {
background: var(--card);
border-radius: 14px;
padding: 15px 17px;
margin-bottom: 11px;
cursor: pointer;
transition: background 0.15s ease;
user-select: none;
-webkit-user-select: none;
}
.memo-card:active { background: #e3efe3; }
.memo-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.memo-title { font-weight: 600; font-size: 15px; flex-shrink: 1; }
.memo-date { color: var(--muted); font-size: 12px; flex-shrink: 0; }
.memo-preview {
color: var(--muted);
font-size: 13px;
margin-top: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* ===== 详情页 ===== */
.back-btn {
display: inline-flex;
align-items: center;
gap: 6px;
color: var(--muted);
font-size: 15px;
cursor: pointer;
margin-bottom: 14px;
padding: 8px 2px;
border: none;
background: none;
}
.back-btn:active { color: var(--text); }
.detail-card {
background: var(--card);
border-radius: 16px;
padding: 22px 18px;
position: relative;
}
.detail-date { color: var(--muted); font-size: 12px; }
.detail-title { font-size: 19px; font-weight: 600; margin: 6px 0 16px; padding-right: 100px; }
.detail-body { line-height: 1.75; font-size: 15px; color: var(--text); }
.detail-body p { margin-bottom: 11px; }
.real-btn {
position: absolute;
top: 18px;
right: 16px;
display: inline-flex;
align-items: center;
gap: 6px;
background: var(--green);
color: #fff;
border: none;
border-radius: 999px;
padding: 8px 15px;
font-size: 13px;
cursor: pointer;
transition: background 0.15s;
z-index: 5;
}
.real-btn:active { background: #57a75b; }
.real-btn svg { width: 15px; height: 15px; }
/* ===== 表格 ===== */
table.obs {
width: 100%;
border-collapse: collapse;
margin: 10px 0;
font-size: 13px;
}
table.obs th, table.obs td {
border: 1px solid var(--line);
padding: 8px 10px;
text-align: left;
vertical-align: top;
}
table.obs th {
background: rgba(102, 187, 106, 0.08);
font-weight: 600;
white-space: nowrap;
font-size: 12px;
}
table.obs td.time { white-space: nowrap; color: var(--muted); font-size: 12px; }
/* ===== 待办 ===== */
.todo-item {
display: flex;
align-items: flex-start;
gap: 11px;
margin: 12px 0;
cursor: pointer;
user-select: none;
-webkit-user-select: none;
}
.todo-circle {
width: 21px;
height: 21px;
border: 1.6px solid var(--green-soft);
border-radius: 50%;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
margin-top: 1px;
transition: all 0.15s;
background: transparent;
}
.todo-circle svg { width: 12px; height: 12px; opacity: 0; transition: opacity 0.15s; }
.todo-item.done .todo-circle {
background: var(--green);
border-color: var(--green);
}
.todo-item.done .todo-circle svg { opacity: 1; }
.todo-item.done .todo-text {
color: #9aa89a;
text-decoration: line-through;
}
.todo-text { font-size: 14px; line-height: 1.55; }
/* ===== 弹窗 ===== */
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(40, 60, 45, 0.25);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
opacity: 0;
pointer-events: none;
transition: opacity 0.25s;
padding: 20px;
}
.modal-overlay.show { opacity: 1; pointer-events: auto; }
.modal {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
border-radius: 18px;
max-width: 480px;
width: 100%;
padding: 24px 20px 20px;
transform: translateY(12px);
transition: transform 0.25s;
}
.modal-overlay.show .modal { transform: translateY(0); }
.modal-head {
display: flex;
align-items: center;
gap: 9px;
margin-bottom: 14px;
}
.modal-head svg { width: 20px; height: 20px; color: var(--green); flex-shrink: 0; }
.modal-head h2 { font-size: 16px; font-weight: 600; }
.modal-body {
font-size: 14px;
line-height: 1.8;
color: var(--text);
max-height: 55vh;
overflow-y: auto;
padding-right: 4px;
-webkit-overflow-scrolling: touch;
}
.modal-foot { text-align: right; margin-top: 16px; }
.modal-close {
background: var(--green);
color: #fff;
border: none;
border-radius: 999px;
padding: 9px 22px;
font-size: 14px;
cursor: pointer;
}
.modal-close:active { background: #57a75b; }
</style>
</head>
<body>
<div id="app">
<!-- 列表页 -->
<div id="listPage">
<h1 class="title">备忘录</h1>
<p class="subtitle">其实只是写给自己的,谁也不会看到。</p>
<div id="listContainer"></div>
</div>
<!-- 详情页 -->
<div id="detailPage" class="page-hidden-right">
<button class="back-btn" id="backBtn">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg>
返回
</button>
<div class="detail-card">
<button class="real-btn" id="realBtn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7 9a4 4 0 1 1 0-6 4 4 0 0 1 0 6z"/><path d="M8 20h-3.5A1.5 1.5 0 0 1 3 18.5V18a4 4 0 0 1 4-4h2a4 4 0 0 1 4 4v.5A1.5 1.5 0 0 1 11.5 20z"/><path d="M21 8l-6 6-2-2"/></svg>
真实想法
</button>
<div class="detail-date" id="detailDate"></div>
<div class="detail-title" id="detailTitle"></div>
<div class="detail-body" id="detailBody"></div>
</div>
</div>
</div>
<!-- 弹窗 -->
<div class="modal-overlay" id="modalOverlay">
<div class="modal">
<div class="modal-head">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>
<h2>真实想法</h2>
</div>
<div class="modal-body" id="modalBody"></div>
<div class="modal-foot">
<button class="modal-close" id="modalClose">我知道了</button>
</div>
</div>
</div>
<script>
const memos = [
{
title: "今日观察记录(4月12日)",
date: "4月12日",
preview: "一直假装在写题,其实余光都在看你和隔壁桌说话。",
inner: "今天从下午第二节课开始,我就完全没办法专心了。我坐在你旁边,手里明明拿着自动铅笔,卷子上却一个字都没写进去。你和前排那个男生聊天的时候,笑得特别自然,那种笑是我很少在你面对我时看到的样子。我居然在计数——你对他笑了四次,每次都会先微微偏一下头。我告诉自己这没什么,同学之间说句话而已,可我的手心一直在冒汗,连握笔都有点打滑。放学的时候我想叫住你一起回家,结果你已经先一步被她们叫走了。我站在原地,把想说的话咽了回去,最后一个人走到车站,耳机里放的歌一句都没听进去。我讨厌自己这样,像个只会躲在备忘录里生气的小孩子,可我真的、真的很在意。",
body: `<p>今天全程都在装成认真写题的样子,但笔尖根本没动过。</p>
<table class="obs">
<tr><th>时间</th><th>看到的事</th><th>我当时(假装)在做什么</th></tr>
<tr><td class="time">13:20</td><td>你递笔记给后排的男生,指尖碰到了</td><td>翻页,翻得很大声</td></tr>
<tr><td class="time">13:45</td><td>他讲了个并不好笑的笑话,你笑了两次</td><td>在草稿纸上无意识地画圈</td></tr>
<tr><td class="time">14:10</td><td>你借他橡皮,他说了一句“谢啦澄香芋”</td><td>捏断了手里的铅笔芯</td></tr>
<tr><td class="time">15:30</td><td>放学的路上他走在你旁边,离得很近</td><td>把围巾往上拉了拉,挡住半张脸</td></tr>
<tr><td class="time">16:00</td><td>你在校门口和一群人笑着告别</td><td>先一步走了,没有回头</td></tr>
</table>
<p style="color:#8aa08a;font-size:13px;">……差不多就是这样。也没什么,对吧。</p>`
},
{
title: "假想敌排除清单",
date: "4月11日",
preview: "一个一个记下来,然后……尽量不去想。",
inner: "写这份清单的时候,我其实特别想把它撕掉,因为写着写着我发现,需要“排除”的人越来越多了。我从来不知道,原来你身边可以有那么多人,而我只是其中一个,甚至不是离你最近的那个。每写下一个名字,心口就往下沉一点。我告诉自己这是在做一件很没出息的事,赤苇京治怎么会做这种事?可我还是一个一个记下来了,像在防御根本打不完的敌人。最可笑的是,我根本没有任何立场去“排除”任何人——我不是你的谁,我们没有那种可以正大光明吃醋的关系。所以这份清单更像是我在惩罚自己,逼自己看清楚:你对谁都能笑,对谁都能温柔,而我并不是特殊的那个。",
body: `<p style="color:#8aa08a;font-size:13px;">(打勾 = 暂时没问题,没打勾 = 需要继续观察)</p>
<div class="todo-item"><div class="todo-circle"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg></div><div class="todo-text">前排那个总找你借笔记的男生 —— 成绩明明不差</div></div>
<div class="todo-item"><div class="todo-circle"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg></div><div class="todo-text">体育课和你分一组、还递水给你的那家伙</div></div>
<div class="todo-item"><div class="todo-circle"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg></div><div class="todo-text">群里总 @ 你、发些无聊表情包的人</div></div>
<div class="todo-item"><div class="todo-circle"><svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg></div><div class="todo-text">座位离你最近、抬头就能看见你的那个……</div></div>
<p style="margin-top:16px;">——最后一条我没好意思写名字。因为那好像是我自己。</p>`
},
{
title: "还没回消息",
date: "4月10日",
preview: "消息发出去三小时了。大概在忙吧。",
inner: "消息发出去已经三个小时了。这三个小时里我看了手机七十三次,数得很清楚,因为每一次我都会短暂地以为震动是你的回复,结果只是群消息或者无关的推送。我甚至开始回想自己那句话是不是哪里说错,是不是太冷淡了,是不是我平时就不够有趣,所以你才不想回我。可是转念一想,你身边从来不缺比我更会说话、更会逗你笑的人,我又凭什么要你立刻回我。我知道你可能真的只是在忙,可我还是忍不住一遍遍刷新,把聊天框往上翻,反复看我们之前的对话,想从里面找出一点你其实也喜欢我的证据。找到一点点就开心几秒,然后又跌回更深的失落里。好难受。",
body: `<p>03:12 发了一条消息。</p>
<p>03:15 以为手机响了,是群聊。</p>
<p>04:40 刷新。把聊天记录从头看了一遍。</p>
<p>05:55 刷新。开始怀疑是不是自己说了不该说的。</p>
<p>06:37 刷新。突然很生气,又突然很委屈。</p>
<p style="color:#8aa08a;">——其实零点之后,我还是一直在等。</p>
<p style="color:#8aa08a;">(等等,明明是我自己记的时间,为什么写得像病患观察记录……)</p>`
},
{
title: "偷偷记下你的喜好",
date: "4月9日",
preview: "想比别人更懂你一点,哪怕一点点。",
inner: "我花了很多时间才记全这些。有些是你亲口告诉我的,有些是我自己观察来的——比如你喝东西时的习惯、走路时喜欢走在哪一侧。我做得这么刻意,就是为了在某个别人不了解你的瞬间,能装作不经意地递上你刚好需要的东西,然后听你惊讶地说一句“你怎么知道”。光是想象那个画面,我就有点开心了。可一想到这些事也许早就有人比我做得更周全,我就又泄了气。我不知道自己能为你做什么特别的事,我这个人本来就没什么表情,也不会说漂亮话,所以只能把这些冷冰冰的细节一条条记下来,当成我唯一能靠近你的方式。真希望能有一个人,是你想起“最懂我的人”时第一个想到的名字——我多希望那个人是我。",
body: `<p>· 喜欢拉面里的溏心蛋,会留到最后一口吃</p>
<p>· 喝饮料时习惯咬吸管</p>
<p>· 走路喜欢靠右侧,偶尔会不自觉哼歌</p>
<p>· 心情不好时会盯着窗外看很久</p>
<p>· 笑的时候眼睛会先弯起来</p>
<p>· ……记到这里突然觉得自己像个跟踪狂。</p>`
},
{
title: "一个糟糕的噩梦",
date: "4月8日",
preview: "梦到你和别人走了。醒来外套都湿了。",
inner: "那个梦太真实了,真实到我现在回想起来,手指还是凉的。梦里我们好像终于走得近了一点,可就在我想开口的时候,你被别人拉走了,你回头看了我一眼,然后就那样笑着走了,再也没有回来。我在后面喊你,声音却发不出来,像有一块很重的东西压在胸口。醒来的时候天还没亮,我摸了把脸,居然真的有眼泪,外套领口也湿了一块。我坐起来,把被子拉到下巴,觉得又丢人又难过。我从来没为谁哭过,更没想过会为一个还没确定关系的、连手都没牵过的你,在半夜里丢脸地醒过来。我多希望那真的只是一个梦,可我又隐隐害怕,怕它其实是某种预兆。",
body: `<p>凌晨四点多醒的。</p>
<p>梦的内容已经有点模糊了,只记得你走得很干脆。</p>
<p>我好像一大早就给你发了消息,问你在不在。</p>
<p>你回了一句“怎么啦”,我盯着那三个字傻看了很久。</p>
<p style="color:#8aa08a;">——很想跟你说“我做噩梦了”,但最后只回了个“没事,就问问”。</p>
<p style="color:#8aa08a;">也只会问问。</p>`
},
{
title: "放学路上",
date: "4月7日",
preview: "故意走慢想等你,结果看到别人先叫住你。",
inner: "今天放学我故意把动作放得很慢,慢到离谱,就是赌你会不会等我一起走。我本以为自己做得够自然,结果磨蹭了半天,最后等来的是看到别人先一步叫走了你。你回头笑嘻嘻地挥手说“明天见”,那个“明天见”都不是对我说的。我站在原地,突然觉得很没意思,连书包带都勒得胳膊疼。回家这一路我走得很慢也很难受,脑子里全是“如果刚才我先开口叫你,现在走在你旁边的人会不会就是我”。我明明每天都有机会,可每次都差那么一点,差在我不敢。我这个人就是这样,越喜欢越不敢开口,越想要越装作无所谓,最后只能看着你和别人并肩走,自己踩着自己的影子回家。",
body: `<p>计划:放学后“偶遇”你,一起走到车站。</p>
<p>结果:被三个人截胡。</p>
<p>补救:我走得很快,快到能追上你们,然后……绕远路走了。</p>
<p style="color:#8aa08a;">顺带一提,今天的天很好看,但没心情看。</p>`
},
{
title: "他送你回家了吧",
date: "4月6日",
preview: "听到有人说“澄香芋今天有人送”。",
inner: "听到那句话的时候,我正低头收拾书包,手上的动作一下僵住了。我告诉自己,送谁回家、被谁送,都跟我没关系,我没有立场去问,也没有资格去介意。可我的脑子根本停不下来,不停地在想那个人是谁、你们聊了什么、他是不是也在喜欢着你。我甚至开始嫉妒一个我连名字都不知道的人,嫉妒他能光明正大地走在你身边,而我只能坐在教室里,连一句“我送你”都开不了口。回家的路上我一直在想,如果是我先开口会怎样,你会不会答应,会不会笑着说“好啊”。可这些“如果”越想越空,像往很深很黑的井里扔石头,等不到回声。好烦,也好难过。",
body: `<p>下午课间,听到后排的人在说:“澄香芋今天有人送哦。”</p>
<p>我假装在戴耳机,其实一只都没塞进去。</p>
<p>之后一节课,老师讲的东西一个字都没进脑子。</p>
<p style="color:#8aa08a;">……所以到底是谁啊。可以的话,明天别让我看见。</p>`
},
{
title: "你似乎没注意到我",
date: "4月5日",
preview: "我今天穿了你说过好看的那件外套。",
inner: "我其实很少在意自己的穿着,但因为你很早以前随口夸过一句“这个颜色挺适合你的”,我今天就故意翻出了那件外套,出门前还在镜子前多看了两眼,整理了半天领子。我做这些,心里抱着一万个不可能实现的期待,想着你会不会注意到,会不会再夸我一次。结果你在走廊里从我身边经过,和别人说着话,连看都没往这边看一眼。我就像个傻子一样站在那里,对着一件外套和一颗期待的心,最后只能自己把拉链拉到最上面,把下巴埋进领子里。其实我也知道,你不可能发现,更不可能记得,那句话对你来说大概只是随口一说,只有我把它当成了了不起的纪念。真是……太可笑了。",
body: `<p>· 早上出门前,对着镜子整理了三次衣领。</p>
<p>· 在走廊遇到你,你在和别人说话。</p>
<p>· 你没有看这边。</p>
<p>· 我假装也在赶路,飞快地走过去了。</p>
<p style="color:#8aa08a;">(外套明明是你说过好看的颜色。你大概早忘了。)</p>`
},
{
title: "深夜的自我整理",
date: "4月4日",
preview: "我问自己:到底在生什么气?答案是不知道。",
inner: "深夜躺在床上,我难得认真地去想这件事:我到底在生气什么?越想越发现,我气的不是别人,全是我自己。气我明明在意得要命,却一句都说不出口;气我不够有趣、不够主动,只会把所有的情绪都藏起来,然后一个人在这里翻来覆去地熬到半夜。我也想变得像你身边那些人一样,能自然地跟你说话、自然地靠近你、自然地让你笑起来。可是我就是做不到,我这张脸、我这颗别扭的心,好像天生就不擅长表达喜欢。每次你靠近,我心跳得越快,表面上就装得越平静,平静到连我自己都觉得冷酷。我讨厌这样的自己,却不知道怎么改。喜欢一个人,原来能这么辛苦,又这么……莫名其妙地舍不得。",
body: `<p>· 今天你跟我说话,我只回了“嗯”。</p>
<p>· 其实我有好多话想说。</p>
<p>· 可你一笑,我就全忘了。</p>
<p>· 于是又变成那个面无表情的、讨厌的赤苇京治。</p>
<p style="color:#8aa08a;">如果哪天我敢把这份备忘录给你看,那一定是我最勇敢的一天。但是……不会有那一天的。</p>`
}
];
const listContainer = document.getElementById('listContainer');
const listPage = document.getElementById('listPage');
const detailPage = document.getElementById('detailPage');
const backBtn = document.getElementById('backBtn');
const realBtn = document.getElementById('realBtn');
const modalOverlay = document.getElementById('modalOverlay');
const modalBody = document.getElementById('modalBody');
const modalClose = document.getElementById('modalClose');
let currentIndex = 0;
function renderList() {
listContainer.innerHTML = '';
memos.forEach((m, i) => {
const card = document.createElement('div');
card.className = 'memo-card';
card.innerHTML = `<div class="memo-row"><span class="memo-title">${m.title}</span><span class="memo-date">${m.date}</span></div><div class="memo-preview">${m.preview}</div>`;
card.addEventListener('click', () => openDetail(i)); // 手机统一用'forward'
listContainer.appendChild(card);
});
}
function openDetail(index) {
const m = memos[index];
document.getElementById('detailDate').textContent = m.date;
document.getElementById('detailTitle').textContent = m.title;
document.getElementById('detailBody').innerHTML = m.body;
currentIndex = index;
document.querySelectorAll('.todo-item').forEach(item => {
item.addEventListener('click', () => item.classList.toggle('done'));
});
listPage.className = 'page-hidden-left';
detailPage.className = '';
detailPage.scrollTop = 0;
window.scrollTo(0, 0);
}
function closeDetail() {
listPage.className = '';
detailPage.className = 'page-hidden-right';
}
backBtn.addEventListener('click', closeDetail);
realBtn.addEventListener('click', () => {
modalBody.textContent = memos[currentIndex].inner;
modalOverlay.classList.add('show');
});
function closeModal() { modalOverlay.classList.remove('show'); }
modalClose.addEventListener('click', closeModal);
modalOverlay.addEventListener('click', (e) => {
if (e.target === modalOverlay) closeModal();
});
renderList();
</script>
</body>
</html>