NewsNow 完整部署与扩展指南:优雅实时新闻聚合平台的缓存、登录、MCP 与数据源架构解析
前端后端网页爬虫【免费下载链接】newsnowElegant reading of real-time and hottest news项目地址https://gitcode.com/GitHub_Trending/ne/newsnow点击查看免费下载NewsNow 是一个主打优雅阅读实时热门新闻的开源 Web 应用前端基于 React Vite UnoCSS后端基于 Nitroh3构建内置 30 分钟缓存、GitHub OAuth 登录与跨设备数据同步、按来源更新频率自适应的抓取间隔并原生支持 MCPModel Context ProtocolServer 接入。本指南以仓库根目录的 README.md 为主线结合 server 与 shared 目录的源码实现完整讲解从零部署Cloudflare Pages / Docker、GitHub OAuth 与数据库配置、本地开发到新增数据源抓取器的全流程并深入剖析缓存与自适应抓取机制的底层代码逻辑。说明当前版本为 DEMO仅支持中文内容正式版将提供更好的定制化功能与英文内容支持见 README.md 顶部 NOTE。本指南所引用的路径均为当前仓库根目录下的相对路径。核心功能特性根据 README.md 的功能清单并结合源码逐一印证优雅的阅读界面多专栏卡片式布局顶部提供「更多 / 关注 / 最热 / 实时」等分类视图支持来源搜索与自定义专栏界面见 screenshots/preview-1.png、screenshots/preview-2.png。实时获取最新热点新闻内置数十个内容源抓取器分布在 server/sources/ 目录涵盖微博热搜、V2EX、知乎、IT 之家、财联社、Hacker News、GitHub Trending、联合早报等。GitHub OAuth 登录与数据同步登录后可将自定义的专栏元数据PrimitiveMetadata同步到服务端数据库跨设备保持一致。默认 30 分钟缓存缓存 TTL 定义于 shared/consts.ts即TTL 30 * 60 * 1000登录用户可通过latest参数强制刷新获取最新数据。自适应抓取间隔最快每 2 分钟每个来源可在配置中声明自己的interval避免频繁抓取导致 IP 被封禁详见下文缓存与自适应抓取机制。支持 MCP Server可将 NewsNow 作为 MCP Server 接入 Claude 等支持 MCP 的客户端。缓存与自适应抓取机制的源码级解析这是本项目最具技术价值的设计值得先于部署深入理解。相关常量定义在 shared/consts.tsexport const TTL 30 * 60 * 1000 // 缓存过期时间30 分钟 export const Interval 10 * 60 * 1000 // 默认刷新间隔10 分钟来源级自适应间隔不同来源的内容更新频率差异巨大热搜每分钟都在变而部分博客可能一天才更新一次因此 shared/pre-sources.ts 定义了五档间隔常量const Time { Test: 1, // 测试用 Realtime: 2 * 60 * 1000, // 实时类最快每 2 分钟 Fast: 5 * 60 * 1000, // 快速类每 5 分钟 Default: Interval, // 默认 10 分钟 Common: 30 * 60 * 1000, // 常规类每 30 分钟 Slow: 60 * 60 * 1000, // 慢速类每 60 分钟 }例如 shared/pre-sources.ts 中微博配置了interval: Time.Realtime2 分钟联合早报配置了interval: Time.Common30 分钟。该配置经过 scripts/source.ts 预处理后写入 shared/sources.json供服务端运行时读取。缓存表与读写缓存底层是一个简单的 SQLite 风格数据表通过db0访问可平滑切换到 Cloudflare D1实现在 server/database/cache.tsCREATE TABLE IF NOT EXISTS cache ( id TEXT PRIMARY KEY, updated INTEGER, data TEXT );set用INSERT OR REPLACE写入序列化后的新闻数组并记录updated时间戳getEntire还兼容了 Cloudflare D1 返回{ results: [] }结构的差异说明该实现刻意适配了 CF Worker 环境。命中缓存的判定逻辑核心判定逻辑位于 server/api/s/index.ts这也是对外提供单来源数据的GET /api/s?idsourceId接口若now - cache.updated sources[id].interval直接返回缓存status: success。注释明确说明interval 是刷新间隔即使缓存未失效也要遵守因为该来源本身内容更新就很慢若缓存已超过 interval 但仍在 TTL30 分钟内则区分两种情况返回status: cache请求未带latest参数请求带了latest但服务器未配置登录或用户未登录匿名用户无法强制刷新防止缓存被绕过导致对上游的频繁请求只有登录用户携带latest参数时才会真正调用抓取器getters[id]()拉取最新数据截取前 30 条slice(0, 30)后回写缓存若抓取失败则回退返回旧缓存无缓存可回退时才抛出 500。从源码结构可以推断这一设计同时兼顾了上游站点压力控制interval 限频 TTL 复用 匿名用户不可强制刷新与用户体验登录用户可手动获取最新。值得注意的一个细节是Date.now()在 Cloudflare Worker 整个运行期内不会更新代码中也对此做了注释说明。抓取器的统一入口所有来源抓取器通过 glob 自动收集见 server/getters.tsimport * as x from glob:./sources/{*.ts,**/index.ts}将每个文件导出的defineSource结果合并为一个getters映射这也是新增数据源无需修改路由代码即可生效的原因。接入 MCP ServerNewsNow 原生支持作为 MCP Server 被 Claude Desktop 等 MCP 客户端调用配置方式直接取自 README.md写入客户端的 MCP 配置文件中{ mcpServers: { newsnow: { command: npx, args: [ -y, newsnow-mcp-server ], env: { BASE_URL: https://newsnow.busiyi.world } } } }npx -y newsnow-mcp-server会临时拉取并运行官方 MCP 服务端包通过BASE_URL指定新闻数据接口的域名。部署到自己的域名后请将BASE_URL替换为你的域名例如https://your-domain.com这样 LLM 便能通过 MCP 协议实时检索你部署实例上的热点新闻。部署指南基础部署无需登录与缓存如果不需要登录、同步和缓存功能这是最快的上线方式Fork 本仓库导入到 Cloudflare Pages 或 Vercel 等平台平台会自动识别构建配置。Cloudflare Pages 配置在 Cloudflare Pages 的项目设置中填写构建命令pnpm run build输出目录dist/output/publicbuild脚本定义在 package.jsonbuild: npm run presource vite build其中presource会先执行 scripts/favicon.ts 与 scripts/source.ts 生成图标清单和来源配置文件再执行 Vite 构建配合vite-plugin-with-nitro输出 Nitro 服务端产物。GitHub OAuth 配置开启登录功能前需要先创建 GitHub OAuth 应用在 GitHub 的 Applications 页面创建一个 GitHub App无需申请任何特殊权限回调 URL 设置为https://your-domain.com/api/oauth/github将your-domain替换为实际域名获取 Client ID 和 Client Secret填入下方环境变量。登录的完整实现见 server/api/oauth/github.ts服务端用code换取 access_token 后请求 GitHub 用户信息将用户写入user表再使用jose的SignJWT签发 60 天有效期的 HS256 JWTpayload 含id与type: github最后重定向回首页并把jwt与用户头像昵称以 query 参数带回前端。Nitro 在 Cloudflare 环境设置 Cookie 存在已知问题因此代码采用 URL 参数方式传递源码中有对应注释。环境变量配置本地运行时参考 example.env.server将其重命名为.env.server并填写# Github Client ID G_CLIENT_ID # Github Client Secret G_CLIENT_SECRET # JWT Secret, 通常就用 Client Secret JWT_SECRET # 初始化数据库, 首次运行必须设置为 true之后可以将其关闭 INIT_TABLEtrue # 是否启用缓存 ENABLE_CACHEtrue各变量的实际用途与源码对应关系如下G_CLIENT_ID/G_CLIENT_SECRETGitHub OAuth 凭证在 server/api/oauth/github.ts 中用于换取 access_tokenJWT_SECRET登录态签名密钥server/api/oauth/github.ts 用它签发 JWTserver/middleware/auth.ts 用jwtVerify校验请求头Authorization: Bearer token并写入event.context.user。从 server/middleware/auth.ts 可看到若未配置这三个变量服务端会禁用登录并对/api/me等需要认证的接口返回 506若 JWT 校验失败访问/api/me会返回 401INIT_TABLE首次运行必须为true用于自动建表cache表见 server/database/cache.tsuser表见 server/database/user.ts初始化成功后建议关闭ENABLE_CACHE是否启用缓存关闭时 server/database/cache.ts 的getCacheTable()会直接返回空PRODUCTHUNT_API_TOKEN额外变量example.env.server 中还存在该变量供 Product Hunt 等需要 token 的来源抓取使用可按需填写。数据库支持本项目通过db0统一访问数据库支持其全部 connector可在 db0 官方 connectors 文档中查询本项目主推 Cloudflare Pages 与 Docker 部署Vercel 需自行搞定数据库。官方推荐使用 Cloudflare D1。以 D1 为例配置步骤在 Cloudflare Worker 控制面板创建 D1 数据库在wrangler.toml中配置database_id和database_name若仓库中没有wrangler.toml可将 example.wrangler.toml 重命名并修改配置其模板为name newsnow pages_build_output_dir dist/output/public compatibility_date 2024-10-03 [[d1_databases]] binding NEWSNOW_DB database_name newsnow-db database_id 重新部署即可生效。Docker 部署对于 Docker 部署只需使用项目根目录的 docker-compose.yml在项目根目录执行docker compose up镜像为ghcr.io/ourongxing/newsnow:latest默认映射宿主机4444端口并通过命名卷newsnow_data持久化数据库数据。同样可以通过docker-compose.yml中的environment段配置G_CLIENT_ID、G_CLIENT_SECRET、JWT_SECRET、INIT_TABLE、ENABLE_CACHE、PRODUCTHUNT_API_TOKEN等环境变量模板中已预留这些字段。本地开发前提需要 Node.js 20。corepack enable pnpm i pnpm devcorepack enable启用包管理器仓库通过 package.json 固定了packageManager: pnpm10.30.3pnpm i安装依赖注意项目对dayjs应用了补丁 patches/dayjs.patch并在pnpm.overrides中锁定了h3、nitropack等关键依赖版本请勿随意改动pnpm dev启动开发服务器命令为npm run presource cross-env NODE_OPTIONS--use-env-proxy vite dev会先执行预处理脚本再启动 Vite含 Nitro 服务端。其他常用脚本见 package.jsonpnpm build生产构建产物位于dist/output/publicpnpm startnode --env-file .env.server dist/output/server/index.mjs以本地 Node 方式运行构建产物需.env.serverpnpm test运行vitest测试现有测试见 server/utils/date.test.ts 与 test/common.test.tspnpm typecheck分别对 Node 侧与 App 侧执行tsc --noEmit类型检查pnpm preview/pnpm deploy在CF_PAGES1下构建并用 wrangler 本地预览 / 部署到 Cloudflare Pages。添加新数据源README 明确说明添加数据源请关注shared/sources即 shared 目录下的来源配置核心为 shared/pre-sources.ts与 server/sources/ 目录项目类型完备、结构简单。详细的逐步教程见 CONTRIBUTING.md核心流程如下1. 注册来源配置在 shared/pre-sources.ts 中注册来源。若给已有来源添加子来源如给 Bilibili 增加热门视频在其sub字段下新增子项若是全新来源则新增顶层条目newsource: { name: New Source, color: blue, home: https://www.example.com, column: tech, // 选择合适专栏 type: hottest // 或 realtime }可选字段还包括interval刷新间隔默认 10 分钟、desc、disable等完整定义见 shared/types.ts 中的Source接口。2. 实现抓取器在 server/sources/ 目录下新建或修改文件如newsource.ts使用项目提供的defineSource与myFetch辅助函数。myFetch定义于 server/utils/fetch.ts内置了浏览器 UA、10 秒超时与 3 次重试可显著降低被上游站点拒绝的概率。以 GitHub Trending 抓取器 server/sources/github.ts 为例const trending defineSource(async () { const html: any await myFetch(https://github.com/trending?spoken_language_code) const $ cheerio.load(html) const news: NewsItem[] [] // ... 解析 DOM 并构造 NewsItem return news }) export default defineSource({ github: trending, github-trending-today: trending, })一个来源可同时导出多个 source id如github与github-trending-today共用同一抓取逻辑defineSource的聚合逻辑见 server/getters.ts。返回的数据必须符合NewsItem结构定义于 shared/types.tsinterface NewsItem { id: string | number // 唯一标识 title: string // 标题 url: string // 原文链接 mobileUrl?: string // 可选移动端链接 pubDate?: number | string // 可选发布时间 extra?: { hover?: string // 悬停提示文本 date?: number | string // 格式化日期 info?: false | string // 附加信息如✰ 12.3k diff?: number // 时间差 icon?: false | string | { url: string; scale: number } // 图标 } }3. 重新生成来源文件修改配置或抓取器后运行npm run presource该命令会重新生成 shared/sources.json 等产物文件使新来源在前端与GET /api/s接口中生效。4. 测试与提交启动pnpm dev后在浏览器中确认新来源正常展示然后提交变更并创建 Pull Requestgit checkout -b feature-name→git commit→git push origin feature-name。注意README 的贡献章节已声明当前版本即将被新版取代暂时不再接受外部贡献此流程仅供理解架构与自行扩展参考。GitHub 登录与数据同步机制登录态的完整链路可以概括为GitHub OAuth 换取 JWT → 前端存储 → 请求携带 Bearer Token → 中间件校验 → 读写用户数据表。登录触发server/api/login.ts 负责发起 OAuth 跳转server/api/oauth/github.ts 处理回调并签发 JWT有效期 60 天认证校验server/middleware/auth.ts 对所有/api/*路径生效对/api/s、/api/me解析Authorization头中的 JWT 并注入event.context.user未配置密钥时对非白名单接口返回 506用户存储server/database/user.ts 维护user表id、email、data、type、created、updatedaddUser支持幂等插入setData/getData用于读写用户的自定义专栏元数据同步接口server/api/me/sync.ts 提供GET /api/me/sync拉取同步数据与POST /api/me/sync写入同步数据服务端会调用verifyPrimitiveMetadata校验结构前端对应的状态管理见 src/atoms/primitiveMetadataAtom.ts 与 hooks 目录下的 useSync.ts。路线图与扩展方向根据 README.md 的 Roadmap项目后续计划包括添加多语言支持英语、中文更多语言即将推出改进个性化选项基于分类的新闻、保存的偏好设置扩展数据源以覆盖多种语言的全球新闻。开源协议本项目基于 MIT 协议开源版权归 © ourongxing 所有。赞分享前端后端网页爬虫【免费下载链接】newsnowElegant reading of real-time and hottest news项目地址https://gitcode.com/GitHub_Trending/ne/newsnow点击查看免费下载相关推荐x64dbg 的 eStepInto/esti 命令详解Trap-Flag 单步与首次异常传递策略x64dbg 的 eStepInto/esti 命令详解Trap Flag 单步与首次异常传递策略 eStepInto别名 esti是 x64dbg 调试前端后端网页爬虫NewsNow终极指南构建高效新闻聚合系统的完整方案NewsNow终极指南构建高效新闻聚合系统的完整方案 在信息爆炸的时代新闻阅读效率成为现代专业人士的核心竞争力。NewsNow作为一款基于现代化技术栈构建的前端后端网页爬虫如何快速构建新闻数据聚合平台Newscatcher完全指南如何快速构建新闻数据聚合平台Newscatcher完全指南 Newscatcher是一款强大的Python工具能够帮助开发者和数据爱好者轻松从几乎任何网站以上一篇【亲测免费】 Intouch驱动_DAServer_DASSIDirect3.0工业自动化通讯的强大助力下一篇Ethereal Style for Zotero从混乱到有序文献管理的新范式创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

kaggle在线训练深度学习模型

kaggle在线训练深度学习模型

kaggle https://www.kaggle.com/ code 通过jupyter notebook上传代码,执行训练 dataset 支持手动上传本地资源文件到input /kaggle/input,dataset通过input访问,input目录是只读的 /kaggle/working,保存文件到working&#…

2026/10/1 1:54:43 阅读更多 →
S32系列芯片如何从外置flash进行Boot启动?

S32系列芯片如何从外置flash进行Boot启动?

《S32系列芯片——Boot详解》系列——S32系列芯片如何从外置flash进行Boot启动? 一、概述 二、基于QuadSPI的boot 2.1 基于QuadSPI的boot方式概述 2.2 IO配置 2.3 时钟配置 2.4 QuadSPI具体配置参数 2.5 系统重置后BootROM对闪存的要求 2.6 应用程序对闪存配置的影响 三、基于…

2026/10/1 1:53:43 阅读更多 →
YOLOv9在医学影像分析中的落地:从数据准备到部署避坑

YOLOv9在医学影像分析中的落地:从数据准备到部署避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 1:53:43 阅读更多 →

最新新闻

JMeter压力测试从入门到进阶:安装配置、脚本编写、结果分析与分布式压测

JMeter压力测试从入门到进阶:安装配置、脚本编写、结果分析与分布式压测

1. JMeter压力测试工具的整体定位与选型思路做Java后端的朋友,逃不掉一个环节:接口上线前得压一压,看看服务在高并发下到底撑不撑得住。我最早接触压测是用ab(Apache Bench)跑个简单接口,后来遇到需要登录态…

2026/10/1 2:26:57 阅读更多 →
【风电功率预测】【多变量输入单步预测】基于TCN-BiGRU-Attention的风电功率预测研究(Matlab代码实现)

【风电功率预测】【多变量输入单步预测】基于TCN-BiGRU-Attention的风电功率预测研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 &#x1f381…

2026/10/1 2:26:57 阅读更多 →
developer-roadmap 中的 LLM 可观测性(LLM Observability)实战指南:监控 Prompt、响应、延迟与 Token 消耗

developer-roadmap 中的 LLM 可观测性(LLM Observability)实战指南:监控 Prompt、响应、延迟与 Token 消耗

文档教程知识库 【免费下载链接】developer-roadmap Interactive roadmaps, guides and other educational content to help developers grow in their careers. 项目地址: https://gitcode.com/GitHub_Trending/de/developer-roadmap 点击查看 免费下载 LLM 可观测…

2026/10/1 2:26:57 阅读更多 →
90DaysOfDevOps 第 10 天:Go Workspace 与代码编译运行实战

90DaysOfDevOps 第 10 天:Go Workspace 与代码编译运行实战

文档/教程 【免费下载链接】90DaysOfDevOps This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Pri…

2026/10/1 2:26:57 阅读更多 →
STM32CubeMX 6.14图形化配置指南:从时钟树到代码生成

STM32CubeMX 6.14图形化配置指南:从时钟树到代码生成

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 2:26:57 阅读更多 →
C#实现SECS/GEM通信:从HSMS到状态机全解析

C#实现SECS/GEM通信:从HSMS到状态机全解析

几年前我第一次把一台C#写的上位机接到半导体前道设备的SECS/GEM端口时,心里其实没底。对方是日本厂商的薄膜设备,EAP系统要求必须通过SECS/GEM联机才能跑Recipe,而我手里只有几百页英文SEMI规范PDF,和一台连IP都没配好的旧PC。后…

2026/10/1 2:25:56 阅读更多 →

日新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 0:00:30 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 0:00:30 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 1:01:17 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/30 13:14:22 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/30 18:13:06 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/9/30 13:14:49 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 0:00:30 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 0:00:30 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/1 1:01:17 阅读更多 →