Avatar

CaiCai

INITIALIZING SYSTEM

封面

✈️ 旅·行 页面技术总结

写作时间:2026-07-13 10:06:04
# 新增页面
👁 次阅读

本页面是 XinghuisamaBlogs 的旅行足迹功能,包含交互式中国地图、时间线卡片、省市筛选联动、旅行详情弹窗、右侧数据面板与计划卡片。

Next.js 16React 19TypeScriptTailwind CSS 4Framer MotionSVG 手绘地图Gitalk 留言

1. 架构与数据流

📁 Markdown 文件

data_storage/travels/*.md
YAML frontmatter + 正文

🧱 Server Component

app/travel/page.tsx
构建时 fs 读取 + gray-matter

⚡ Client Component

TravelClient.tsx
状态中枢 + 三向联动

🗺️ 地图 · 时间线 · 面板

FootprintSVG
TravelNode/Card/Modal
TravelStats/Plan

2. 组件全貌(10 个)

组件文件职责TravelClientcomponents/travel/TravelClient.tsx状态中枢:三向筛选联动(filterCity/filterProvince/resetKey)、回调绑定、固定面板布局FootprintSVGcomponents/travel/FootprintSVG.tsx 499行交互式中国地图 SVG + HTML 标签覆盖层。支持滚轮缩放进省、点击省份高亮、城市圆点/名字渲染。核心动画模型 t∈[0,2] 双段缩放TravelNodecomponents/travel/TravelNode.tsx时间线节点:左右交替布局、滚动浮现动画(framer-motion whileInView)、链接时间线纵轴TravelCardcomponents/travel/TravelCard.tsx游记卡片:封面 + 城市/日期/心情/正文摘要、毛玻璃背景、hover 放大TravelModalcomponents/travel/TravelModal.tsx 249行游记详情弹窗:左栏(封面+文字) · 右栏(照片灯箱+GitHub Gitalk 留言) · 独立滚动 · 照片点击放大TravelStatscomponents/travel/TravelStats.tsx右侧数据面板:城市数 · 省份点亮进度环(34省SVG) · 旅途段数 · 最近去过(可点击筛选)TravelPlancomponents/travel/TravelPlan.tsx旅行计划卡:粉色时间·季节标签列表,数据来自 data/travel-plans.tsTravelManagerapp/travel/TravelManager.tsx 管理端后端管理界面:含新增入口 · 编辑/删除按钮 · 计划编辑弹窗 · 销毁确认page.tsxapp/travel/page.tsx服务端入口:getAllTravelRecords() 读盘,渲染 Navbar + TravelClienttravel/editorapp/travel/editor/page.tsx 管理端独立编辑页:新增/修改游记表单,保存到 Python 后端

3. 地图组件 · FootprintSVG(核心)

3.1 坐标系 · 数据层

统一坐标系 600×494,从 data/china.json(DataV GeoJSON) 通过仿射投影生成:

数据文件内容生成方式china-provinces.ts35 省 SVG pathgencity.mjs · 仿射拟合cities.ts382 地级市坐标 + 省会标记gencity.mjs · 省会用 center / 其他用 centroidbeijing-districts.ts北京 16 区边界 + 区名坐标genbeijing.mjsshanghai-districts.ts上海各区边界同法

data/travel.ts 从 cities.ts 派生 5 张查找表:CITY_PROVINCE · CITY_COORDS · PROVINCE_CITIES · CAPITALS · CITY_OPTIONS

3.2 核心动画模型 t ∈ [0, 2]

  • 第一段 t∈[0,1]「淡出隔离」:整图不缩放,其他省份随 otherOpacity=1-t 淡出
  • 第二段 t∈[1,2]「缩放」:viewBox 从全国框 {47,-8,516,425} 几何插值到选中省的真实外框
  • 真实外框计算:从 path 坐标按 M 拆子路径,只取面积最大的主体陆地(忽略离岛)
  • 逆缩放 currentScale:线宽、滤镜、字号除以当前缩放比,视觉恒定

3.3 交互体系

  • 滚轮缩放:选中省后拦截滚轮;步长自适应(小省分更多格);滚到底退出该省
  • 点省份:选中并高亮金色虚线,停在全国大图,由滚轮放大
  • 点城市圆点:进省后才可点选筛选;全国态穿透点击落到底层省份
  • 三向联动:父级筛选选中城市 → 地图跨省重定位(省会除外);点当前省内城市地图不动

3.4 HTML 标签覆盖层

城市名/点是绝对定位的 HTML div,按 viewBox 实时算 left/top% → 跟随缩放移动但字号恒定。

  • 全国态:只显示省会;pointer-events:none 穿透
  • 进省后 cityReveal:t>1.5 开始淡入其他城市
  • 北京/上海专属:放大后展示区界 + 区名(districtReveal: currentScale 14→24)
  • 特殊标记:黄冈永远黄色房子 · 北京放大后省会黄点→红色五角星

3.5 渲染分层(SVG)

墨绿陆地 #1a3a2a → 已访问省荧光青 #00e5ff(cyanGlow高斯模糊) → 省界灰线 #475569
→ 选中省金色虚线 #fbbf24 → 京沪区界粉线 → 图例(缩放时淡出)

4. 标签定位体系

层作用单位常用城市cx/cy 坐标微调移动点的真实坐标坐标空间新疆/东北/四川省内城市dotAnchor决定"点钉坐标点"还是"整块居中"—已访问省会整块居中;其余钉点markerNudgeX/Y整块(点+名)像素位移屏幕 px北京/上海/杭州/哈尔滨/重庆/西安/广州(省会)name transform只挪名字不挪点屏幕 px巴音郭楞/铁门关/西安等一长串

**关键规则:坐标随缩放放大,像素固定不变。**深度放大才可见的省内城市用坐标微调(0.5~4单位);全国图看的省会用像素位移。

5. 游记详情弹窗(双栏 + 灯箱 + 留言)

5.1 布局

  • 左栏 2/3(独立滚动):封面 + 📍城市/日期 + 心情 + 正文(dangerouslySetInnerHTML)
  • 右栏 1/3(独立滚动):照片网格(grid-cols-4) + GitHub Gitalk 留言板
  • 弹窗尺寸w-[calc(100vw-4.75rem)] h-[calc(100vh-5.625rem)](比默认各大10px、高6px)
  • 滚动穿透防护:弹窗打开时 body overflow:hidden + 栏内 overscroll-contain

5.2 照片灯箱

点击任意照片 → 全屏黑色遮罩(z-[300]) + 图片 max-w-[95vw] max-h-[95vh] object-contain,再点击关闭。有淡入 + 缩放动画(framer-motion)。

5.3 留言板

基于 Gitalk,通过 /api/github 代理 OAuth。每条旅行记录独立评论线程 id=travel-${record.id}}。需要 GitHub OAuth App 的 callback URL 正确配置。

6. 右侧数据面板 + 旅行计划

TravelStats城市数(大数字) · 省份点亮进度环(SVG 圆环) · 旅途段数 · 最近去过(缩略图+可点击筛选)TravelPlan计划列表(粉色圆点+地点+时间+季节标签)。数据来自 data/travel-plans.ts,管理端可编辑(增/改/删)

面板固定右侧 hidden xl:block,宽度自适应右侧留白。点击数据卡的"旅途回忆"=全部城市、"最近去过"=按该城市筛选。

7. 进场动画体系

对象机制距离时长缓动地图/数据/计划固定面板各自 motion.div y:20→020px0.35seaseOut正文块(标题 + 时间线)PageTransition 包裹20px0.35seaseOut时间线卡片TravelNode motion.div whileInView24px0.4seaseOut

修复"闪现"问题:固定面板不待在 PageTransition 里(否则祖先 transform 清除时重新锚定导致flash),各自独立动画 → 始终平滑到位。

8. 特殊处理清单

  • 北京五角星偏移随缩放淡入bjNudgeFactor = Math.min(1, Math.max(0, t-1))——放大没到位时偏移=0(星在形状内),放到最大才过渡到调好的位置
  • 上海偏移随缩放平滑过渡shNudgeX = shActive ? 14 - 37×(t-1) : 14——全国+14不跳,放大滑到−23
  • 已访问省会不跳位:dotAnchor 只在 inSel && !(visited && isCapitalCity) 触发 → 省会始终整块居中
  • 选中省会不切省地图:activeCity 副作用对 CAPITALS 提前 return
  • 卡片磨砂闪变修复:TravelNode initial opacity 0→1,保留 Y 轴滑入

9. 关键数据

项目数值中国地图省份35 省地级市坐标382 城省份点亮总数34 省(大陆省级行政区)组件文件数10 个(含管理端3个)数据文件数7 个(cities/provinces/districts/travel/travel-plans/china.json)FootprintSVG 代码量499 行逐城市坐标微调~90 行


10. 生产环境注意事项

  • 旅行记录存储data_storage/travels/*.md(管理端撰写→Python 后端写入→同步到博客)
  • 旅行计划存储data/travel-plans.ts(管理端编辑→Python 后端覆盖写入→同步到博客)
  • 地图代码/坐标不同步:地图组件和数据层不在 sync 列表,两端需手动对齐
  • GitHub OAuth:Gitalk 留言需要 GitHub OAuth App 的 callback URL 正确配置(含当前域名)