一个零依赖、可嵌入、实时聚合全球 AI 资讯的单文件 Web 应用。 暗灰 + 翠绿配色,情报终端视觉风格,专为个人网站嵌套与对外展示设计。
- 1. 项目简介
- 2. 文件清单
- 3. 整体架构
- 4. 设计系统(Design System)
- 5. 页面结构与 DOM 树
- 6. 功能模块详解
- 7. 数据模型
- 8. localStorage 键清单
- 9. 部署指南(Cloudflare Worker)
- 10. 嵌入个人网站
- 11. 二次开发扩展点
AI 新闻追踪是一个纯前端(HTML + CSS + 原生 JS,无任何框架/构建步骤)的 AI 资讯聚合终端。它能从 14 个中英权威 RSS 源实时抓取 AI 相关新闻,提供情报面板(图表/趋势/热词/排行)、收藏、已读、批量管理、全文翻译、自动刷新等能力。
核心特性:
| 特性 | 说明 |
|---|---|
| 🟢 单文件 | 所有 HTML/CSS/JS 内联,约 1694 行,122 KB,零依赖 |
| 🔌 可嵌入 | 作用域限定在 #ai-news-app,可安全 iframe 嵌套进个人网页 |
| 🌐 实时抓取 | 5 级容错抓取策略链,离线也能用缓存/备用数据 |
| 🎨 情报终端风 | 暗灰底 + 翠绿强调,等宽字体承载数据,7 种主题色可选 |
| 🌏 中英翻译 | 三级翻译容错(MyMemory → Niutrans → Google),智能中文识别 |
| 💾 历史保留 | 每次刷新合并旧新闻,重开页面历史仍在(localStorage,上限 800 条) |
| ⏱ 自动刷新 | 可选 1/5/15/30 分钟间隔,状态栏实时倒计时 |
| 📊 情报面板 | 分类分布、7 日趋势、热词云、热度 TOP10、来源质量、覆盖雷达 |
| 文件 | 行数 | 作用 |
|---|---|---|
LICENSE |
— | MIT 开源协议(Copyright © 2026 hua) |
README.md |
本文档 | 项目解构与使用说明 |
CONTRIBUTING.md |
— | 贡献指南(本地运行 / 提交规范) |
.gitignore |
— | Git 忽略规则(排除本地/备份/密钥文件) |
ai-news-web.html |
~1694 | 主应用:UI + 样式 + 全部逻辑,单文件交付 |
embed-preview.html |
~40 | iframe 嵌入预览页,验证嵌入态体验 |
worker/cloudflare-worker.js |
~90 | 服务端 RSS 网关(边缘节点批量抓取 14 源,5 分钟缓存) |
worker/deploy-worker.html |
~280 | Worker 部署图文指南(含「复制代码」按钮) |
.gitattributes |
— | 统一行尾配置(跨平台一致) |
SECURITY.md |
— | 安全漏洞披露策略 |
CHANGELOG.md |
— | 版本变更记录 |
.github/ |
— | Issue / PR 模板目录 |
仓库根目录放置
ai-news-web.html、README.md、LICENSE、.gitignore、CONTRIBUTING.md、SECURITY.md、CHANGELOG.md、.gitattributes、embed-preview.html;Worker 网关与部署指南统一收纳于worker/子目录,社区模板位于.github/。
尽管是单文件,内部逻辑清晰分为三层(以注释分隔):
┌─────────────────────────────────────────────────────────┐
│ <head> <style> 设计令牌 + 全局/组件 CSS(约 1–300 行) │
├─────────────────────────────────────────────────────────┤
│ <body> DOM 结构(约 307–470 行) │
│ #ai-news-app[data-theme][data-color] │
│ ├─ header 头部操作栏 │
│ ├─ .tabs 标签页切换 │
│ ├─ #tab-news 主视图 │
│ ├─ #tab-express 时间线视图 │
│ ├─ #tab-favorites收藏视图 │
│ ├─ .modal-overlay 详情/配置弹窗 │
│ └─ #toast-container 提示 │
├─────────────────────────────────────────────────────────┤
│ <script> 应用逻辑(约 472–1694 行) │
│ 常量 → 状态 → 工具函数 → 抓取 → 渲染 → 交互 → 初始化 │
└─────────────────────────────────────────────────────────┘
┌──────────── 5 级抓取策略链 ────────────┐
启动/init ──▶ │ ① 本地 Node 服务 (/api/news) │
│ ② Cloudflare Worker (/all) │──▶ allNews[]
│ ③ CORS 代理逐个 RSS (rss2json) │ │
│ ④ benzhi.online API 补充 │ │ 去重+排序
│ ⑤ 天行数据 API 补充(可选 Key) │ │
└──────────────────────────────────────┘ ▼
mergeNews()
saveHistory() ──▶ localStorage
│
┌────────────────────────────────┼────────────────────────┐
▼ ▼ ▼
renderNews() renderCharts() renderTimeline()
(网格/列表) (4 图表) (时间线)
所有颜色/字体/间距均通过 CSS 变量管理,根作用域在 :root(第 9 行起),覆盖层在 #ai-news-app[data-theme] / [data-color]。
| 令牌 | 浅色值 | 暗色值(默认) | 用途 |
|---|---|---|---|
--bg |
#f7f8fa |
#0d1117 |
页面背景 |
--card |
#ffffff |
#151b23 |
卡片/面板 |
--surface-2 |
#f3f5f8 |
#1b2230 |
次级表面 |
--border |
#e3e8ef |
#232b36 |
边框 |
--text |
#1a1a2e |
#e6edf3 |
主文字 |
--text-sub |
#6b7280 |
#8b98a9 |
次级文字 |
--p(主色) |
#0ea371 |
#10b981 |
翠绿强调(green 主题) |
--font-ui |
system-ui 栈 | 同左 | UI 字体(含中文回退) |
--font-mono |
ui-monospace 栈 | 同左 | 等宽(数据/时间/代码) |
--radius |
12px |
同左 | 圆角 |
通过 data-color 属性提供 7 种强调色(第 27–32 行):
green(默认翠绿)、purple、blue、red、orange、pink,以及暗色下统一的 --p 覆盖。深浅由 data-theme="dark" 固定(已在交互层面移除切换,由宿主网页适配)。
全部以纯 CSS 实现,无组件框架:
- 按钮:
.btn(.btn-primary/.btn-secondary)、.icon-btn、.view-btn、.action-btn - 卡片:
.news-card(含.read/.pinned/.fav状态)、.stat-card、.dash-card、.skeleton-card - 徽标:
.news-source(5 类:research/industry/policy/product/technology,第 233–237 行暗色专用色板) - 标签/胶囊:
.source-pill、.interest-chip、.tag - 弹窗:
.modal-overlay/.modal(居中、最大 80vh 滚动) - 提示:
.toast(右下角滑入) - 右键菜单:
.context-menu(置顶/收藏/已读/复制链接/打开)
:focus-visible焦点环、触控靶 ≥ 40px、语义化标签、ARIA 属性(aria-expanded/aria-label)- 嵌入式自动识别(第 1526 行
applyEmbedMode):window.self !== window.top(iframe)、URL 含?embed=1、或父级含ai-news-embed类 → 切换为 flex 纵向 + 内部滚动,绝不撑破宿主页。
- 左侧:Logo + 「情报终端」徽标
- 右侧操作:导出收藏、⚙️ 数据源(设置)、自动刷新下拉(
.auto-refresh-select,1/5/15/30 分钟)、刷新按钮
AI新闻追踪(主)|时间线(express)|收藏(favorites)
- 分类筛选:全部 / 研究 / 产业 / 政策 / 产品(第 326–330 行)
- 搜索框(
.search-box,300ms 防抖) - 来源状态条(
.source-status-bar) - 视图切换:网格 / 列表(第 336–339 行)
- 批量模式开关 + 已读计数
- 批量操作条(收藏/取消/已读/未读/取消)
新闻总数 / 今日更新 / 热门话题 / 我的收藏
- 第一排:分类分布柱状图、7 日趋势图、热词云
- 第二排:热度 TOP10、来源质量评分、分类覆盖雷达图
- 折叠状态持久化于 localStorage(
ai-news-intel)
- 加载态:4 张骨架屏(
.skeleton-card) - 卡片模板(第 1014 行)含:来源徽标 + 时间(
.news-time,翠绿等宽)、标题、摘要(3 行截断)、标签、收藏星、已读勾
来源 + 时间、标题、中文翻译区、摘要、标签、收藏/阅读原文/翻译按钮
Worker URL、天行 Key(可选)、清除缓存新闻、关注领域、隐藏来源、自定义 RSS 源、主题色
按优先级逐层降级,任一成功即采用,全部失败回退备用数据:
| 级别 | 名称 | 端点 | 说明 |
|---|---|---|---|
| ① | 本地 Node 服务 | origin + /api/news |
最稳定,需本地 server.js 运行 |
| ② | Cloudflare Worker | WorkerURL + /all |
推荐线上路径,边缘批量抓取 14 源 |
| ③ | CORS 代理逐个 RSS | rss2json + 备用代理 | 单源失败不影响其他源 |
| ④ | benzhi.online API | /api/news |
关键词(ai/大模型/芯片…)补充 |
| ⑤ | 天行数据 API | api.tianapi.com/ai |
可选,需免费 Key,补中文源 |
Worker 路径细节(第 591–620 行):请求 WorkerURL/all 获得 {ok, data:{hostname: rawXML}},遍历 14 源按 hostname 匹配 parseRss 解析,按 URL 去重合并进 allNews。
CORS 代理链(第 488–492 行 PROXIES):allorigins → codetabs → corsproxy.io,每个源经 fetchRssFeed(第 719 行)先试 rss2json、失败再试原始 XML + 代理。
| 源 | 分类 | 地区 |
|---|---|---|
| IT之家 | technology | 中 |
| 36氪 | industry | 中 |
| Ars Technica | technology | 英 |
| The Verge (AI) | product | 英 |
| InfoQ 中国 | research | 中 |
| 少数派 | technology | 中 |
| Hacker News (AI) | research | 英 |
| OpenAI Blog | product | 英 |
| MIT Tech Review | research | 英 |
| VentureBeat (AI) | industry | 英 |
| DeepMind | research | 英 |
| arXiv cs.AI | research | 英 |
| Google AI Blog | product | 英 |
| 量子位 | industry | 中 |
支持自定义 RSS(设置面板添加,合并进抓取,第 627 行)。
translateText(text)
└─ 依次尝试 provider 数组:[tMyMemory, tNiutrans, tGoogle]
• MyMemory 免 Key,国内可用(实测正常,返回"OpenAI发布新模型")
• Niutrans 需配置 NIUTRANS_KEY(第 480 行,已内置)
• Google gtx 接口兜底
- 智能中文识别(第 1419 行
isMostlyChinese):中文占比 > 25% 直接显示原文,避免中英混翻 - 标题、摘要分开翻译再拼接(第 1464 行起),单段失败不影响另一段
- 入口:详情弹窗「翻译」按钮
- 头部下拉选择间隔(0/1/5/15/30 分钟),默认 5 分钟(第 519 行
autoRefreshMs) - 状态栏实时倒计时(
auto-refresh-indicator,如自动 5m · 下次 04:32,第 971 行) - 到点静默调用
fetchAllNews→ 合并 → 重渲染,无闪屏 - 选择持久化于
ai-news-autorefresh
saveHistory()(第 891 行):抓取后写入ai-news-history,最多 800 条,剥离函数引用防序列化错误loadHistory()(第 901 行):init启动时读回(第 556 行),旧新闻立即可见mergeNews(base, incoming)(第 882 行):按url去重合并,刷新只追加新条目clearHistory()(第 1490 行):设置面板「清除缓存新闻」,不影响收藏/已读
| 状态 | 存储键 | 交互 |
|---|---|---|
| 收藏 | ai-news-favorites |
卡片星标 / 弹窗按钮 / 批量 |
| 已读 | ai-news-read |
卡片标题后缀 ✓ / 右键 / 批量 |
| 置顶 | ai-news-pinned |
右键菜单,sortByPinned 置顶排序 |
勾选卡片 → 批量收藏/取消、标记已读/未读,工具栏见第 343–349 行。
- 分类筛选(第 1342 行
filterCategory)+ 来源筛选(第 1362 行filterSource) - 关键词搜索(第 1368 行
debounceSearch,300ms 防抖)+ 标签点击搜索(第 1369 行searchTag) - 无限滚动加载(
setupInfiniteScroll+loadMore,每批 8 条)
safeDate(input)(第 868 行):健壮日期解析,多重兜底,永远返回合法Date,修复少数 RSS 异常日期导致卡片无时间的问题- 显示规则:近 1 小时
MM-DD HH:mm · N分钟前;近 24 小时· N小时前;更早仅MM-DD HH:mm title属性悬停显示完整 ISO 时间
- 网格 / 列表双视图(第 1309 行
setView,持久化ai-news-view) - 键盘快捷键(第 1544 行
setupKeyboard):方向键导航卡片、Enter 打开、Esc 关闭、F 收藏等
每条新闻对象字段:
{
id: Number|String, // 唯一标识(去重键之一)
title: String, // 标题
summary: String, // 摘要(≤300 字)
source: String, // 来源名(如 'IT之家')
category: String, // research|industry|policy|product|technology
tags: Array<String>, // 关键词标签(extractTags 提取)
url: String, // 原文链接(去重主键)
time: String, // ISO 时间字符串
rawTime: Date, // 解析后的 Date 对象(safeDate 保证有效)
}| 键 | 内容 | 读写位置 |
|---|---|---|
ai-news-worker-url |
Cloudflare Worker 域名 | WORKER_KEY(第 482 行) |
ai-news-rss2json-key |
rss2json API Key(可选) | 第 486 行 |
ai-news-tianapi-key |
天行数据 Key(可选) | 第 685 行 |
ai-news-favorites |
收藏新闻 id 数组 | 第 514 行 |
ai-news-read |
已读 id 数组 | 第 527 行 |
ai-news-pinned |
置顶 id 数组 | 第 528 行 |
ai-news-view |
视图模式 grid/list | 第 526 行 |
ai-news-color |
主题色 green/purple… | 第 532 行 |
ai-news-autorefresh |
自动刷新间隔(ms) | 第 519 行 |
ai-news-interests |
关注领域数组 | 第 533 行 |
ai-news-hidden-sources |
隐藏来源名数组 | 第 534 行 |
ai-news-custom-rss |
自定义 RSS 数组 | 第 535 行 |
ai-news-history |
历史新闻缓存(≤800条) | HISTORY_KEY(第 889 行) |
ai-news-intel |
情报面板折叠状态 | loadIntelState(第 1518 行) |
推荐线上使用 Worker 作抓取网关,规避浏览器 CORS 限制,国内可绑自定义域名(勿用
*.workers.dev,部分网络会被墙)。
步骤:
- Cloudflare 控制台 →
Workers 和 Pages→ 创建 →从 Hello World! 开始 - 命名(如
ai-news-gateway)→ 部署默认代码 - 进入编辑器 →
Ctrl+A全选删除 → 粘贴cloudflare-worker.js全部内容(保留export default)→保存并部署 设置→域→+ 添加域名→ 填子域名(如ainews.你的域名.com,需主域名已在 Cloudflare 托管 DNS)- 等待 SSL 证书签发(1–5 分钟)
- 浏览器访问
https://ainews.你的域名.com/all验证返回{"ok":true,"sources":N,"data":{...}} - 打开应用 → ⚙️ 数据源 → Worker URL 填
https://ainews.你的域名.com(不带/all)→ 保存 → 刷新
详见同包 deploy-worker.html(含图文与一键复制代码)。
Worker 结构:cloudflare-worker.js 为 ES Module,export default { async fetch(request, env, ctx) },对 /all 路由并行抓取 14 源、边缘缓存 5 分钟(cache-control: max-age=300),返回 {ok, sources, data} 并带 access-control-allow-origin: *。
两种嵌入方式:
① iframe(推荐)
<iframe src="ai-news-web.html?embed=1"
style="width:100%;height:800px;border:none"></iframe>应用自动识别 iframe 环境,内部独立滚动,不撑破宿主页。
② 组件化引入
将 #ai-news-app 整块复制进你的页面,CSS 作用域已限定 #ai-news-app,不会污染全局样式;深浅由宿主页面统一控制(应用固定 data-theme="dark")。
可用 embed-preview.html 预览嵌入效果。
| 想改什么 | 改哪里 |
|---|---|
| 增删 RSS 源 | RSS_SOURCES 数组(第 495 行) |
| 换翻译供应商 | translateText 的 providers 数组(第 1454 行) |
| 调抓取优先级 | fetchAllNews 内 5 级策略顺序(第 569 行起) |
| 改配色 | :root / [data-color] / [data-theme] 令牌(第 9–32 行) |
| 加图表 | renderCharts 系列(第 1084–1190 行) |
| 改刷新默认 | autoRefreshMs 初值(第 519 行) |
| 历史上限 | HISTORY_MAX(第 890 行) |
| 自定义源持久 | ai-news-custom-rss 键逻辑(第 535/1625 行) |
技术栈: 纯原生 JS(无框架、无打包)、内联 SVG 图标(无图标库)、localStorage 持久化、Fetch + AbortSignal 超时控制。
本项目为个人学习/展示用途。RSS 源版权归各原始媒体所有,新闻转载请遵守各源许可协议。