在 Uppy 仓库的 Angular 示例中掌握 @uppy/angular:从 CLI 开发到 Dashboard 集成实战
前端UI组件后端【免费下载链接】uppyThe next open source file uploader for web browsers :dog:项目地址https://gitcode.com/gh_mirrors/up/uppy点击查看免费下载导读本文以 Uppy 开源仓库中 examples/angular 示例项目为主体系统讲解如何利用 Angular CLI 完成ng serve本地开发、ng generate代码脚手架、ng build生产构建与ng test单元测试的完整工作流并深入剖析该示例如何通过uppy/angular的DashboardComponent与DashboardModalComponent将 Uppy Dashboard 以「内联面板 模态弹窗」两种形态集成进 Angular 应用。读完本文你将掌握一套可直接复用的 Angular Uppy 文件上传集成方案以及 Angular CLI 命令与 Uppy 插件声明式用法背后的实现原理。1. 项目定位Uppy 仓库中的 Angular 现代化示例examples/angular是 Uppy 官方仓库中的 Angular 示例应用其package.json将项目命名为example-angular见 examples/angular/package.jsonREADME 中标注该项目由 Angular CLI 19.2.6 生成。不过从 examples/angular/package.json 的依赖版本看当前仓库实际升级到了angular/core22.x 与angular/cli22.x同时通过workspace:*协议直接引用仓库内 monorepo 的uppy/core、uppy/dashboard、uppy/tus、uppy/webcam与uppy/angular包——这意味着该示例始终与 Uppy 最新源码保持同步是验证 Angular 官方组件的“活文档”。从源码结构看这是一个采用Standalone 组件架构的现代 Angular 应用入口文件 src/main.ts 直接调用bootstrapApplication(AppComponent)引导应用而非传统NgModule模式根组件 app.component.ts 以standalone: true声明并在imports中直接引入CommonModule、DashboardComponent与DashboardModalComponent。该示例的核心价值在于同时演示了 Uppy Dashboard 的两种主流挂载方式内联 Dashboard通过uppy-dashboard标签常驻页面随时可见模态 Dashboard通过uppy-dashboard-modal标签与open输入绑定点击按钮后以浮层形式弹出。两者共享同一个Uppy实例是理解「一个 Uppy 核心、多个 UI 挂载点」的绝佳范例。2. Angular CLI 基础工作流原 README 核心内容本节完整继承 examples/angular/README.md 的 CLI 操作指引并补充与仓库实际配置相符的细节。2.1 启动本地开发服务器ng serve原 README 明确指出启动本地开发服务器的命令为ng serve服务器启动后在浏览器中访问http://localhost:4200/即可看到应用。Angular 的 dev server 具备自动热重载能力——只要修改任意源文件页面会立即自动刷新无需手动重启。结合仓库配置ng serve的实际行为由 angular.json 中projects.angular-modern-examples.architect.serve决定默认走development配置对应buildTarget: angular-modern-examples:build:development该配置在build选项中关闭了optimization、开启sourceMap便于调试你也可以通过ng serve --configuration production切到生产模式验证最终表现。此外 package.json 还提供了等价脚本npm start内部执行ng serve。2.2 代码脚手架ng generateAngular CLI 内置强大的代码生成scaffolding能力。生成一个新组件的命令为ng generate component component-name如果想查看所有可用的 schematics包括components、directives、pipes等运行ng generate --help仓库层面有一个值得注意的细节当前示例的 angular.json 在schematics节点中将组件、指令、管道都显式配置为standalone: false。也就是说在本项目内用ng generate component生成的新组件默认属于传统 NgModule 体系需手动声明到某个 module 中。这与示例根组件自己手写standalone: true形成对照——你可以按需选择两种架构风格这也是 CLI 脚手架行为与手写代码灵活共存的体现。2.3 生产构建ng build执行ng buildCLI 会编译整个项目并将构建产物输出到dist/目录。按 angular.json 的配置具体输出目录为dist/angular-modern-examples使用的 builder 是angular/build:application。默认配置为production包含代码压缩与 tree-shakingoptimization默认开启生产配置未显式覆盖即生效outputHashing: all为产物文件名追加内容哈希以支持长效缓存资源体积预算校验初始包超过500kB发出警告、超过1MB直接报错任何组件样式超过4kB警告、超过8kB报错见 angular.json 的budgets配置。原 README 强调生产构建会针对性能与速度做优化仓库的budgets正是这套质量门槛的可视化体现。2.4 单元测试ng test运行单元测试的命令为ng test仓库为该项目配置了基于 Karma 的测试基建architect.test使用angular/build:karmabuilder并引入了zone.js/testingpolyfill见 angular.json。测试代码位于 src/app/app.component.spec.ts包含三个用例应能成功创建AppComponent实例组件title属性应为Uppy Dashboard Angular Example渲染出的h1文本应包含该标题。这些用例同时验证了 Standalone 组件的导入TestBed.configureTestingModule({ imports: [AppComponent] })与模板渲染链路。2.5 端到端测试ng e2e对于端到端e2e测试原 README 说明运行命令为ng e2e并特别提醒Angular CLI默认并不捆绑任何 e2e 测试框架你可以自行选择如 Playwright、Cypress 等并按需接入。当前仓库的angular.json中也确实没有预置 e2e builder这与 README 描述完全一致。3. 深入示例一个 Uppy 实例两种 Dashboard 挂载形态examples/angular的页面布局见 app.component.html分为两个 section上半部分是常驻的内联 Dashboard下半部分是「打开/关闭」按钮驱动的模态 Dashboard。两者通过模板语法绑定到同一个uppy实例这正是理解uppy/angular组件模型的最佳切入点。3.1 根组件Uppy 实例的初始化与插件装配在 app.component.ts 中组件以readonly风格初始化了一个 Uppy 实例uppy new Uppy({ debug: true, autoProceed: false, restrictions: { maxFileSize: 1000000, maxNumberOfFiles: 3, allowedFileTypes: [image/*, video/*], }, })debug: true在控制台输出 Uppy 内部日志便于开发期排查autoProceed: false文件添加后不自动上传等待用户显式点击上传按钮Dashboard 内联视图的典型交互restrictions限制单文件不超过 1 MB、最多 3 个文件、仅允许图片与视频类型。随后在ngOnInit()生命周期中装配插件ngOnInit(): void { this.uppy .use(Webcam) .use(Tus, { endpoint: https://tusd.tusdemo.net/files/ }) .on(complete, (result) { console.log(Upload complete! Weve uploaded these files:, result) }) }这里注册了Webcam摄像头拍照/录像与Tus基于 tus 协议的可断点续传上传器endpoint 指向公开测试服务https://tusd.tusdemo.net/files/并监听complete事件在控制台输出上传结果。组件还为两种 Dashboard 分别定义了属性对象dashboardProps { plugins: [Webcam], height: 470, showProgressDetails: true, note: Images and video only, 2-3 files, up to 1 MB, restrictions: { /* 与 Uppy 实例一致的限制 */ }, } dashboardModalProps { target: document.body, onRequestCloseModal: (): void { this.showModal false }, closeModalOnClickOutside: true, animateOpenClose: true, }其中dashboardProps.plugins: [Webcam]表示在 Dashboard 内显示 Webcam 标签页模态版则额外声明了关闭行为点击遮罩关闭、开合动画与onRequestCloseModal回调用于同步组件状态showModal。3.2 模板绑定uppy-dashboard与uppy-dashboard-modal页面模板app.component.html的核心片段如下uppy-dashboard [uppy]uppy [props]dashboardProps /uppy-dashboard button classtoggle-button (click)toggleModal() {{ showModal ? ✕ Close Modal Dashboard : Open Modal Dashboard }} /button uppy-dashboard-modal [uppy]uppy [open]showModal [props]dashboardModalProps /uppy-dashboard-modal三个关键绑定[uppy]传入共享的Uppy实例两个组件都指向同一个实例因此内联面板中选中的文件在模态面板中同样可见[props]传入对应形态的 Dashboard 配置对象[open]仅模态组件由showModal布尔状态驱动toggleModal()方法负责翻转该状态。这种「组件输入属性 模板事件」的用法让 Uppy 的挂载完全声明式化开发者无需手动操作 DOM。4. 源码剖析uppy/angular 组件如何工作uppy/angular是 Uppy 官方维护的 Angular 组件包装层公共 API 导出三个组件见 public-api.tsDashboardComponent、DashboardModalComponent与StatusBarComponent。本示例用到了前两者其实现细节值得深入。4.1 统一的 Angular 包装基类两个 Dashboard 组件都继承自 utils/wrapper.ts 中的UppyAngularWrapper抽象类该类封装了插件生命周期管理的核心逻辑onMount(defaultOptions, plugin)将组件默认选项如id、inline、target与用户传入的props合并调用this.uppy.use(plugin, options)注册插件并通过this.uppy.getPlugin(id)拿到插件实例handleChanges(changes, plugin)响应 Angular 的OnChanges——若uppy输入属性被替换为新的实例先uninstall旧实例上的插件再挂载到新实例若props发生变化则调用this.plugin.setOptions(...)热更新配置uninstall(uppy)调用uppy.removePlugin(this.plugin)完成卸载实现组件销毁时的资源清理。这一基类正是uppy/angular组件「声明式绑定、响应式更新」的底层保证。4.2 DashboardComponent内联挂载dashboard.component.ts 以Component({ selector: uppy-dashboard, template: , changeDetection: ChangeDetectionStrategy.OnPush, standalone: true })声明暴露出两个Input()Input() uppy: UppyM, B new Uppy(); Input() props: DashboardOptionsM, B {};在ngOnInit()中调用onMount({ id: angular:Dashboard, inline: true, target: this.el.nativeElement }, Dashboard)——注意inline: true表示渲染为页内面板target指向组件宿主元素。随后ngOnChanges负责响应输入变化ngOnDestroy负责卸载插件。4.3 DashboardModalComponent模态挂载dashboard-modal.component.ts 额外暴露了第三个输入属性Input() open: boolean false并在ngOnChanges中针对open的翻转做了专门处理if (changes[open] this.open ! changes[open].previousValue) { if (this.open !changes[open].previousValue) { this.plugin!.openModal(); } if (!this.open changes[open].previousValue) { this.plugin!.closeModal(); } }即open从false变为true时调用openModal()反向则调用closeModal()从而把 Angular 的输入绑定翻译成 Uppy Dashboard 原生的模态 API。这也解释了为何示例模板中只需绑定[open]showModal即可驱动浮层开合。从源码结构可以推断UppyAngularWrapper的响应式设计setOptions热更新、uppy实例替换时的重挂载使得 Angular 的变更检测与 Uppy 的插件系统得以无缝衔接ChangeDetectionStrategy.OnPush则保证了只在输入真正变化时触发更新避免不必要的渲染开销。5. 配置文件全景从 package.json 到 tsconfig 与 angular.json原 README 只交代了 CLI 命令本节将相关配置文件串联起来帮助读者理解每个命令背后的工程设定。5.1 依赖与脚本package.json运行时依赖angular/core、angular/common、angular/forms、angular/router等 Angular 22.x 系以及uppy/angular、uppy/core、uppy/dashboard、uppy/tus、uppy/webcam均以workspace:*指向本仓库包外加rxjs、tslib、zone.js开发依赖angular/cli、angular/build、angular/compiler-cli、typescript脚本映射start→ng serve、build→ng build、watch→ng build --watch --configuration development、test→ng test。5.2 TypeScript 编译配置tsconfig.app.json应用编译配置基于仓库根tsconfig.json扩展关键点module: es2022、moduleResolution: bundler适配现代打包器、resolveJsonModule: true允许直接导入 JSON入口文件为src/main.ts。5.3 Angular 构建配置angular.json核心要点已在第 2 节分散说明这里汇总配置项取值作用builderangular/build:application现代应用构建器outputPathdist/angular-modern-examples构建产物目录polyfills[zone.js]Zone.js 运行时styles[src/styles.css]全局样式入口assetspublic目录静态资源拷贝budgetsinitial ≤ 500kB(警告)/1MB(报错)组件样式 ≤ 4kB(警告)/8kB(报错)体积质量门禁生产配置outputHashing: all哈希文件名6. 改造为本项目最小可复用的 Angular Uppy 集成模板基于本示例可以提炼出一个最小集成模板这正是uppy/angularREADME 中的官方范式见 packages/uppy/angular/README.mdimport { Component, type OnDestroy } from angular/core import { DashboardComponent } from uppy/angular import Uppy from uppy/core Component({ selector: app-uploader, standalone: true, imports: [DashboardComponent], template: uppy-dashboard [uppy]uppy/uppy-dashboard, }) export class UploaderComponent implements OnDestroy { readonly uppy new Uppy() ngOnDestroy(): void { this.uppy.destroy() } }两个实践要点安装依赖npm install uppy/angular uppy/core uppy/dashboard在 monorepo 内则以workspace:*引用与本示例一致资源释放在ngOnDestroy()中调用this.uppy.destroy()避免组件销毁后 Uppy 实例残留事件监听与资源这一点与本示例中DashboardComponent通过UppyAngularWrapper.uninstall()自动清理插件的思路一脉相承。若需要 Tus 断点续传、Webcam 采集等能力参照 app.component.ts 的ngOnInit模式通过this.uppy.use(...)依次装配插件即可。7. 小结与进一步探索examples/angular展示了现代 AngularStandalone bootstrapApplication与 Uppy 的最佳整合方式CLI 层面ng serve/ng generate/ng build/ng test/ng e2e构成了完整的开发、脚手架、构建与测试闭环组件层面uppy/angular通过统一的UppyAngularWrapper基类把 Uppy 插件的安装、热更新与卸载封装为声明式输入绑定开发者只需维护uppy、props、open三个属性即可获得完整的上传能力。若想继续深入可以从以下仓库路径入手组件公共 APIpackages/uppy/angular/src/public-api.ts以及StatusBarComponentstatus-bar.component.ts包装器实现packages/uppy/angular/src/utils/wrapper.ts底层 Uppy 核心与 Dashboard 插件packages/uppy/core/src/Uppy.ts 与 packages/uppy/dashboard/src/Dashboard.tsx单元测试范式examples/angular/src/app/app.component.spec.ts官方组件文档uppy/angular包说明见 packages/uppy/angular/README.md。把 examples/angular 作为起点结合上述源码路径即可在自己的 Angular 应用中快速落地一套可维护、可断点续传、支持摄像头采集的现代化文件上传方案。赞分享前端UI组件后端【免费下载链接】uppyThe next open source file uploader for web browsers :dog:项目地址https://gitcode.com/gh_mirrors/up/uppy点击查看免费下载相关推荐深入解析 composer/xdebug-handlerCLI 进程无 Xdebug 自动重启机制及 Rector 中的实战应用深入解析 composer/xdebug handlerCLI 进程无 Xdebug 自动重启机制及 Rector 中的实战应用 本篇技术指南以开源仓库中 c前端UI组件后端在 Turborepo with-angular 示例仓库中使用 Angular CLI 的完整开发指南在 Turborepo with angular 示例仓库中使用 Angular CLI 的完整开发指南 导读 examples/with angular 是构建工具开发工具CLI在 Vercel 仓库中基于 Angular 17 模板工程掌握 Angular CLI 全流程开发在 Vercel 仓库中基于 Angular 17 模板工程掌握 Angular CLI 全流程开发 导读 本文以 Vercel 开源仓库 packages/sCLI后端云原生上一篇TRL架构深度解析现代大语言模型微调的技术基石下一篇FastAPI Best Architecture入门教程从安装到第一个API接口创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Ubuntu 18.04安装NVIDIA驱动、CUDA 10.2与cuDNN完整指南

Ubuntu 18.04安装NVIDIA驱动、CUDA 10.2与cuDNN完整指南

/* 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:00:58 阅读更多 →
大麦抢票脚本完整教程:3 步装好环境,开票瞬间自动监控下单

大麦抢票脚本完整教程:3 步装好环境,开票瞬间自动监控下单

大麦抢票脚本完整教程:3 步装好环境,开票瞬间自动监控下单 【免费下载链接】Automatic_ticket_purchase 大麦网抢票脚本 项目地址: https://gitcode.com/GitHub_Trending/au/Automatic_ticket_purchase 页面还显示"即将开抢"&#xff0…

2026/9/30 1:56:27 阅读更多 →
用 Llama 4 Maverick 构建网页信息提取器:SerpAPI + Firecrawl 的智能 URL 筛选与结构化提取实战

用 Llama 4 Maverick 构建网页信息提取器:SerpAPI + Firecrawl 的智能 URL 筛选与结构化提取实战

网页爬虫后端AI 应用 【免费下载链接】firecrawl The web data API to search, scrape, and interact at scale. 🔥 项目地址: https://gitcode.com/GitHub_Trending/fi/firecrawl 点击查看 免费下载 本篇文章以 Firecrawl 官方仓库 examples/llama-4-m…

2026/9/30 1:56:27 阅读更多 →

最新新闻

C++自定义字面量:把单位焊进类型,编译期拦住低级bug

C++自定义字面量:把单位焊进类型,编译期拦住低级bug

“五月病”还没好利索,手头项目又因为单位混用爆了个低级 bug。领导拍桌子问“这 30 到底是秒还是毫秒”的时候,我盯着代码里光秃秃的setTimeout(30),脑子里只有一个念头:这锅要是早点上自定义字面量,根本走不到测试那…

2026/10/1 4:42:08 阅读更多 →
C++自定义字面量全解析:operator““机制、实战场景与避坑指南

C++自定义字面量全解析:operator““机制、实战场景与避坑指南

自定义字面量这五个字,我第一次听到的时候也觉得是什么高深魔法。实际上它干的事特别朴素:让你在代码里写出1_km、"192.168.1.1"_ip、3_min这种带单位的数字,并且让编译器把它认成一个你想要的对象,而不是一串裸奔的魔法…

2026/10/1 4:42:07 阅读更多 →
Python异步编程入门:Asyncio核心概念与实战解析

Python异步编程入门:Asyncio核心概念与实战解析

异步这块内容,我平时在团队里没少给人讲。刚开始接触 Python 异步编程的小伙伴,十个里有八个先被各种概念绕晕:协程、事件循环、Task、Future、await、async……然后打开 Asyncio 官方文档,看了两页就关掉了。真正能让你入门的东西…

2026/10/1 4:42:07 阅读更多 →
模型调用实战指南:PB模型与LM Studio本地大模型接入方法

模型调用实战指南:PB模型与LM Studio本地大模型接入方法

做开发这些年,一个特别深的体会是:模型训练出来只是第一步,真正让它在业务里发挥价值的,是“模型调用”这最后一公里。最近社区里聊得最热的也是这个方向——有人折腾怎么调用pb模型做推理,有人研究让Claude Code调用L…

2026/10/1 4:42:07 阅读更多 →
嵌入式C++内存管理实战:从堆栈分配到内存池与排查技巧

嵌入式C++内存管理实战:从堆栈分配到内存池与排查技巧

嵌入式开发里,C 的内存管理问题,十个项目九个会在这里翻车。我见过不少人把桌面端的new/delete习惯直接带进 MCU 工程,结果上电跑不了几天就 HardFault,或者设备在客户现场运行三天后莫名死机。这一篇不聊空泛的理论,就…

2026/10/1 4:42:07 阅读更多 →
Mistral微调实战:用LoRA/QLoRA打造专属模型

Mistral微调实战:用LoRA/QLoRA打造专属模型

把模型变成自己的,Mistral也能“调教”出专属风格Mistral 系列写到这里,前面几篇聊了基础认知、本地部署、API 调用、推理优化,基本上你已经能把 Mistral 7B、Mixtral 这类模型跑起来了。但跑起来只是第一步,真正让它在你的业务场…

2026/10/1 4:41:07 阅读更多 →

日新闻

我发现了一个新思路:用 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 阅读更多 →