历史上的今天:网站/App 每日历史卡片组件集成指南
# 历史上的今天:网站/App 每日历史卡片组件集成指南
> 接口:历史上的今天(apiCode=119,接入点 119-42)· 免费 · 适用人群:站长、产品运营、个人开发者 · 阅读时间:约 7 分钟
## 核心要点
- 一个可嵌入的"每日历史"小组件 = 后端按天缓存 + 前端卡片轮播。
- 不传 `date` 即"今天",配合本地缓存实现全天只调一次接口。
- 组件形态灵活:侧边栏小卡、首页 Banner、App 开屏一句史。
## Why:给站点加一点"每日感"
网站/App 想要 Daily 属性,"历史上的今天"是最轻量、零版权的切入点。一个小组件,每天自动换新,既增加停留,又适合分享。本文给出可直接抄的组件代码。
## What:组件架构
```
[定时/首次] 后端拉取"今天" → 按 date 缓存(见缓存篇)
↓
[前端组件] 读取今日缓存 → 渲染卡片 → 轮播/点击展开
```
## How:完整可运行组件
### 后端接口(Node.js,含缓存)
```javascript
const cache = new Map();
async function todayHistory() {
const d = new Date();
const date = `${String(d.getMonth()+1).padStart(2,"0")}${String(d.getDate()).padStart(2,"0")}`;
if (cache.has(date)) return cache.get(date);
const url = `https://route.showapi.com/119-42?appKey=YOUR_APPKEY`;
const body = new URLSearchParams({ needContent: "1" }); // 不传 date = 今天
const resp = await fetch(url, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, body });
const list = (await resp.json()).showapi_res_body.list;
cache.set(date, list);
const next = new Date(d); next.setHours(24,0,0,0);
setTimeout(() => cache.delete(date), next - d);
return list;
}
// Express 示例
app.get("/api/history-today", async (req, res) => res.json(await todayHistory()));
```
### 前端卡片(HTML/CSS/JS)
```html
<style>
.hw-card{width:280px;border:1px solid #eee;border-radius:10px;padding:12px;font-family:system-ui}
.hw-card img{max-width:100%;border-radius:6px;margin-top:8px}
.hw-card .c{color:#555;font-size:13px;margin-top:6px}
</style>
<div class="hw-card">
<div style="font-weight:600">📜 历史上的今天</div>
<h4 id="hw-title"></h4>
<img id="hw-img" alt="" style="display:none" onerror="this.style.display='none'">
<div class="c" id="hw-content"></div>
<div style="margin-top:8px;font-size:12px;color:#999" id="hw-nav"></div>
</div>
<script>
let list=[], i=0;
async function init(){
list = await (await fetch("/api/history-today")).json();
render(); setInterval(render, 8000); // 每 8 秒换一条
}
function render(){
const it = list[i % list.length]; i++;
document.getElementById("hw-title").textContent = it.title;
const img = document.getElementById("hw-img");
if (it.img){ img.src = it.img; img.style.display=""; } else img.style.display="none";
document.getElementById("hw-content").textContent = (it.content||"").slice(0,60) + "…";
document.getElementById("hw-nav").textContent = `第 ${i} / ${list.length} 条 · 点击展开全文`;
}
init();
</script>
```
### 移动端开屏一句史(最简)
```javascript
const list = await (await fetch("/api/history-today")).json();
showSplash(`💡 ${list[0].title}`); // 取第一条做开屏一句话
```
## 返回示例与解析
组件数据来自 `showapi_res_body.list`,每条 `title` 直接可用作卡片标题,`content` 截断展示,`img` 按需显示(无图隐藏,见[图片处理篇](https://www.showapi.com/guides/history-today-image-handle-119))。
## 进阶 / 边界
- **轮播而非全列**:单日可能几十条,全部铺开体验差;轮播/分页更友好。
- **缓存必做**:组件背后务必按天缓存(见[缓存篇](https://www.showapi.com/guides/history-today-cache-119)),否则每次刷新都调接口。
- **样式隔离**:组件用独立 class 前缀(如 `hw-`)避免污染宿主页面样式。
- **无图占位**:`img` 为 `""` 时隐藏图片元素,用文字卡也好看。
## FAQ
**Q1:组件会每天自动换内容吗?**
会。不传 `date` 默认查"今天",后端按天缓存后每天自然换新。
**Q2:几十个事件怎么不刷屏?**
轮播(如上每 8 秒一条)或分页,不要一次性全渲染。
**Q3:能放到别人网站吗?**
组件代码可直接嵌入你有权限的页面;调用走你自己的 AppKey。
**Q4:图片裂了怎么办?**
`img.onerror` 隐藏 + 无图占位,详见图片处理篇。
## 相关能力 / 下一步阅读
- [历史上的今天:免费接口下如何做本地缓存与更新频率设计?](https://www.showapi.com/guides/history-today-cache-119) — 组件背后的缓存。
- [历史上的今天:img 图片字段处理(空字符串、防盗链、懒加载)指南](https://www.showapi.com/guides/history-today-image-handle-119) — 图片落地。
- [历史上的今天:教育/课堂场景如何集成历史事件 API?](https://www.showapi.com/guides/history-today-education-119) — 教育场景变体。
- **本系列共 10 篇**:查看[历史上的今天指南总目录](https://www.showapi.com/guides/history-today-guides-119)