Kafka-King 开发与构建实战指南:Wails v2 + franz-go 跨平台 Kafka GUI 客户端的工程实践
开发工具数据库客户端桌面应用【免费下载链接】Kafka-KingA modern and practical kafka GUI client Kafka-King 是一款现代化、实用的 Kafka GUI 客户端旨在通过直观的桌面界面简化 Apache Kafka 管理。作为一款跨平台应用程序它为开发人员和管理员提供了强大的工具可与 Kafka 集群交互无需依赖命令行界面或基于 Web 的解决方案。项目地址https://gitcode.com/gh_mirrors/ka/Kafka-King点击查看免费下载本文基于 Kafka-King 仓库的开发者指引 AGENTS.md系统梳理这款跨平台 Kafka GUI 客户端的开发、测试与构建全流程。读完本文你可以掌握 Kafka-King 的 Wails v2Go 后端 Vue 3 前端 Naive UI工程结构、热重载开发命令、构建期版本注入方式以及其“单次消费/流式消费客户端隔离”“分区策略兼容”等关键工程约定能够独立完成本地开发、单测验证与 CI 级别的发布构建。项目概览与技术栈Kafka-King 是一款跨平台的 Kafka GUI 客户端技术底座由三部分构成Wails v2桌面应用框架负责窗口管理、前后端绑定与资产嵌入Go 后端基于 franz-gogithub.com/twmb/franz-go作为 Kafka 客户端库封装连接、主题、生产、消费、ACL、SCRAM 等核心操作Vue 3 前端配合 Vite、Naive UI 组件库与 vue-i18n 多语言方案通过 Wails 自动生成的 JS 绑定调用 Go 方法。从 app/go.mod 可以看到后端还引入了kadm、kmsg、sasl/kerberosKerberos/GSSAPI 认证、klauspost/compressSnappy/zstd、pierrec/lz4/v4LZ4以及go-resty/resty/v2更新检查、ping、Webhook 告警的 HTTP 客户端等依赖与官方指引中的“Key libraries”清单一一对应。开发命令以下命令均来自 AGENTS.md且都假设当前工作目录是app/Wails 项目根目录不是仓库根目录原因见下文“Go module root”一节cd app # 开发模式前端 后端热重载 wails dev # 构建生产二进制 wails build # 带版本注入的构建CI 的构建方式 wails build -ldflags-X app/backend/common.Versionv1.0.0 # 仅前端开发Vite 开发服务器 npm --prefix frontend run dev # Go 测试部分集成测试需要运行中的 Kafka 集群 go test ./...几点实操说明首次使用前先安装 Wails CLIgo install github.com/wailsapp/wails/v2/cmd/wailslatest并安装好 Go、Node.js 与 npm见 readme.md 的“Participate in development”一节。前端开发服务器端口官方指引中写的是http://localhost:5174但从仓库实际配置看app/wails.json 的frontend:dev:serverUrl与 app/frontend/vite.config.js 均将端口定为5734以仓库当前配置为准。Linux 上构建前需要安装系统依赖libgtk-3-dev libwebkit2gtk-4.0-dev build-essentialCI 中的 Linux 构建正是通过apt-get install完成这一步的。版本注入-ldflags-X app/backend/common.Version...会在编译期改写 app/backend/common/vars.go 中的Version变量开发模式下该变量为空字符串。目录结构与模块职责AGENTS.md 给出的目录布局是整个后端的“地图”下面结合仓库实际文件逐条说明各模块职责repo-root/ app/ # -- Go module appWails 项目根目录 main.go # 入口注册 Wails 绑定 wails.json # Wails 配置应用名、开发服务器地址 frontend/ # Vue 3 Vite Naive UI src/ App.vue # 根布局、主题/语言切换 components/ # 功能组件Conn、Topics、Consumer 等 utils/eventBus.js # 基于 mitt 的全局事件总线 i18n/ # vue-i18n 翻译zh-CN、en-US、ja-JP、ko-KR、ru-RU backend/ app.go # App 生命周期Start、DomReady、Shutdown common/vars.go # 常量、GitHub URL、Version构建期注入 config/app.go # 配置读写~/.kafka-king/config.yaml、文件对话框 service/kafka.go # 核心 Kafka 操作连接、主题、生产、消费、ACL、SCRAM service/stream.go # 多实例流式消费者事件consumer-start/msg/err/end service/offsets.go # 消费组 offset 重置、DeleteRecords service/cluster.go # LogDirs、分区重分配、客户端配额 service/sr.go # Schema Registry浏览 subject/schema、Avro/JSON/PB 解码 service/partitioner.go # autoPartitioner显式分区或 sticky-key 兜底 system/update.go # GitHub release 更新检查器 types/resp.go # 请求/响应结构体、Connect、Config、AlertConfig utils/ # 压缩gzip/lz4/snappy/zstd、Ternary 工具对应到仓库中的真实路径均相对仓库根目录模块文件核心职责入口app/main.go创建App、AppConfig、Update、KafkaService并绑定到 Wails常量与版本app/backend/common/vars.goAppName、ConfigDir、GitHub API URL、构建期注入的Version配置app/backend/config/app.goYAML 配置读写~/.kafka-king/config.yamlKafka 核心app/backend/service/kafka.go连接管理、单次消费客户端缓存oneShotCache流式消费app/backend/service/stream.go多流实例、consumer-*事件推送分区策略app/backend/service/partitioner.goautoPartitioner二合一分区器类型定义app/backend/types/resp.goResultResp/ResultsResp、Connect、Config、AlertConfig前端事件总线app/frontend/src/utils/eventBus.jsmitt全局 emitter应用是如何“接线”的How the app is wired官方指引给出了 4 条接线规则逐条结合源码印证main.go创建结构体并绑定到 Wails。在 app/main.go 中main()依次创建backend.NewApp()、config.AppConfig{}、system.Update{}、service.NewKafkaService()并通过Bind: []any{app, appConfig, update, kafkaService}暴露给前端OnStartup回调中依次调用四者的Start(ctx)OnBeforeClose绑定kafkaService.Close用于退出前清理资源。前端通过自动生成的绑定调用 Go 方法。.gitignore排除了app/frontend/wailsjs/见 .gitignore这些绑定在wails dev或wails build时生成于frontend/wailsjs/go/首次拉取代码后需先跑一次 Wails 命令补齐。所有绑定的 Go 方法返回*types.ResultResp或*types.ResultsResp其中带Err字符串字段。从 app/backend/types/resp.go 可见ResultResp{Result map[string]any; Err string}与ResultsResp{Results []any; Err string}前端统一通过err字段判断操作是否成功。后端方法以结构体方法的形式暴露Wails 从方法签名自动生成 JS 绑定——这也是为什么方法必须挂在结构体上如func (k *Service) Consumer(...)而不是包级函数的原因。此外后端向前端主动推送事件走的是 Wails 运行时通道app/backend/service/stream.go 中的emitEvent封装了runtime.EventsEmit并对非 Wails 环境单元测试做了 recover 保护前端则在 Consumer.vue 中通过EventsOn(consumer-msg, ...)/EventsOff(consumer-msg)订阅与退订。关键开发约定Important conventionsGo module root 是app/不是仓库根目录app/go.mod 声明module app因此所有go命令go test、go run、go build都必须从app/目录执行import 路径也以此为准如app/backend/common。版本变量在构建期注入app/backend/common/vars.go 中Version 是空字符串占位仅在编译时通过-ldflags-X app/backend/common.Versionv1.0.0注入实际值wails dev开发模式下它就是空串。CI 则直接注入 release tag见下文 Build/CI 一节。配置持久化于~/.kafka-king/config.yaml从 app/backend/config/app.go 的getConfigPath()看配置目录由os.UserHomeDir()拼接common.ConfigDir即.kafka-king得到配置文件为config.yaml目录不存在时自动创建。GetConfig()在文件缺失或 YAML 解析失败时回退到默认配置窗口 1180x760、dark 主题、空连接列表。安全注意Config.Connects字段保存了所有已保存的集群连接其中包含明文密码——对应结构体 Connect 中的SaslPwd、SshPassword等字段。官方指引明确要求永远不要把config.yaml提交到仓库。单次消费与流式消费使用彼此隔离的客户端这是 Kafka-King 最重要的并发约定。从源码结构看app/backend/service/kafka.go 中Consumer单次拉取维护一个oneShot *oneShotCache缓存 key 由所有影响行为的参数拼接而成group、topic、isolationLevel以及startTimestamp|isLatest|startOffset组成的 reset key。相同 key 直接复用缓存 client可以继续上次的进度key 变化则关闭旧 client 重建。流式消费则完全另一套Service.streams是map[string]*StreamInstance每个流实例独占自己的kgo.Client。核心原因绝不能在并发的 poll 循环之间共享同一个kgo.Client——kgo 的PollRecords不是多 goroutine 安全的轮询入口共享会导致记录被不同逻辑瓜分甚至竞态。分区策略显式分区与自动分配的二合一生产消息时partition 0表示自动分配key hash / stickypartition 0表示显式指定。这里的背景是kgo 的默认分区器会忽略record.Partition字段而ManualPartitioner又要求必须设置分区二者都无法单独满足需求。因此 app/backend/service/partitioner.go 实现了autoPartitioner// record.Partition 0 时直接使用该分区否则退回 StickyKey // 按 key hash无 key 时粘性随机。 func (p *autoTopicPartitioner) Partition(r *kgo.Record, numPartitions int) int { if r.Partition 0 int(r.Partition) numPartitions { return int(r.Partition) } return p.fallback.Partition(r, numPartitions) }兜底分区器是kgo.StickyKeyPartitioner(nil)有 key 按 key 哈希无 key 时在一段时间内粘性固定到同一分区避免无 key 消息在分区间抖动。前端跨组件通信走 mitt 事件总线app/frontend/src/utils/eventBus.js 导出一个全局mitt()实例emitter并在模块级维护了当前连接名setConnectName/getConnectName供所有组件共享。主题变更、菜单选择、语言切换等跨组件事件都通过它传递而“后端 → 前端”的流式数据消费消息则走 Wails 的EventsOn通道两条通道职责分离。测试策略kfake srfake 实现无集群单测Kafka-King 的测试分两层均可在 app/backend/service/ 下找到进程内假集群测试—— kafka_kfake_test.go 使用 franz-go 的kfakein-process fake broker加srfake假 Schema Registry无需任何真实 Kafka 集群直接go test ./...即可运行。测试通过kfake.NewCluster(kfake.NumBrokers(1))启动假集群、可选SeedTopics预置主题再直接调用Service的方法断言结果。覆盖了连接、主题、生产消费、gzip 压缩往返、offset 重置、DeleteRecords、LogDirs/配额/分区重分配、ACL、多实例流式消费、提交 offset、Schema Registry Avro 解码、不支持的 SASL 机制、OAuth 校验等场景例如TestFakeConnectAndTopics、TestFakeProduceConsume、TestFakeStreamMulti、TestFakeSchemaRegistryAndAvro等。真实集群集成测试—— kafka_test.go 其中硬编码了 broker 地址默认跳过只有设置环境变量KAFKA_KING_INTEGRATION1才会执行// 集成测试需要真实 Kafka 集群默认跳过设置 KAFKA_KING_INTEGRATION1 才运行 if os.Getenv(KAFKA_KING_INTEGRATION) { t.Skip(set KAFKA_KING_INTEGRATION1 to run integration tests (require a live Kafka cluster)) }运行单个测试go test -run TestFakeProduceConsume ./backend/service/构建与 CIBuild/CICI 定义在 .github/workflows/build.yaml要点如下触发条件仅在release: created时触发push 或 PR 不触发构建版本注入将 release tag 注入版本变量与本地构建命令形式一致wails build -ldflags-X app/backend/common.Version${{ github.ref_name }}工具链版本Go1.24、Node22.xGO_VERSION/NODE_VERSION环境变量见 build.yaml三平台产物Windowswindows-latestwails build -o Kafka-King.exe后用 7-Zip 打包.7z附带 readme 与 LICENSEmacOSmacos-latestApple Silicon-platform darwin/universal构建通用二进制再用create-dmg生成 dmgLinuxubuntu-22.04先apt-get install libgtk-3-dev libwebkit2gtk-4.0-dev build-essential构建后打包tar.gz。本地手工构建时Linux 依赖与上述 CI 步骤完全一致。关键依赖库一览以下表格继承自 AGENTS.md 的“Key libraries”一节并与 app/go.mod、app/frontend/package.json 中的实际依赖对应库用途github.com/twmb/franz-goKafka 客户端github.com/wailsapp/wails/v2桌面应用框架vue-i18n前端国际化naive-uiVue 3 组件库vicons/material图标集mitt轻量事件总线echarts图表监控页go-resty/resty/v2HTTP 客户端更新检查、ping、Webhook 告警github.com/jcmturner/gokrb5/v8Kerberos/GSSAPI SASLgithub.com/klauspost/compressSnappy 与 zstd 压缩github.com/pierrec/lz4/v4LZ4 压缩常见坑Gotchasfrontend/dist/与frontend/wailsjs/是构建期生成物.gitignore 明确排除了app/frontend/dist/和app/frontend/wailsjs/。首次拉取代码后需先执行一次wails build或wails dev才能补齐这两个目录。无边框窗口拖动应用使用frameless窗口app/main.go 中Frameless: true侧边栏作为自定义标题栏靠--wails-draggable:dragCSS 实现拖动。Connect结构体中tls/sasl是字符串比较而非布尔tlsenable、saslenable。原因是 Wails 将 JS 到 Go 的对象序列化为map[string]any从 app/backend/types/resp.go 的Connect定义可见Tls、Sasl、SkipTLSVerify等字段全部是string类型——阅读连接逻辑时不要误以为是 bool 判断。启动时会上报匿名 ping应用启动时请求 app/backend/common/vars.go 中定义的PingUrlhttps://ysboke.cn/api/kingTool/ping用于匿名版本统计。若你的网络环境无法访问该地址属预期行为不影响功能。小结Kafka-King 的开发者指引围绕一条主线展开以app/为 Go module 与命令执行根目录用wails dev/wails build驱动前后端一体化开发用 ldflags 注入版本用 kfake 支撑无集群单测用release: created触发的 CI 产出三平台安装包。在此基础上理解“单次消费与流式消费客户端隔离”“autoPartitioner 二合一分区”“配置中连接串含明文凭据”这三条约定基本就掌握了在本仓库中安全、高效地贡献代码所需的核心知识。赞分享开发工具数据库客户端桌面应用【免费下载链接】Kafka-KingA modern and practical kafka GUI client Kafka-King 是一款现代化、实用的 Kafka GUI 客户端旨在通过直观的桌面界面简化 Apache Kafka 管理。作为一款跨平台应用程序它为开发人员和管理员提供了强大的工具可与 Kafka 集群交互无需依赖命令行界面或基于 Web 的解决方案。项目地址https://gitcode.com/gh_mirrors/ka/Kafka-King点击查看免费下载相关推荐Kafka-King现代化Kafka GUI客户端工具完全指南Kafka King现代化Kafka GUI客户端工具完全指南 Kafka King是一款专为简化Apache Kafka集群管理而设计的现代化图形用户界面工开发工具数据库客户端桌面应用终极指南Confluent Kafka Go客户端跨平台构建全攻略终极指南Confluent Kafka Go客户端跨平台构建全攻略 Confluent Kafka Go客户端是Apache Kafka在Golang生态系统消息队列后端如何快速上手Kafka-King现代Kafka GUI客户端的完整指南如何快速上手Kafka King现代Kafka GUI客户端的完整指南 Kafka King是一款现代化且实用的Kafka GUI客户端专为新手和普通用户设开发工具数据库客户端桌面应用上一篇D2DX高帧率原理揭秘运动预测如何优雅突破暗黑2的25帧上限下一篇opencodex 自动上下文auto-context机制解析条件式 [1m] 标记与 CLAUDE_CODE_AUTO_COMPACT_WINDOW 的审计实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

微信小程序 TDesign Navbar 导航栏组件实战:从引入配置到源码级自适应原理(miniprogram-demo)

微信小程序 TDesign Navbar 导航栏组件实战:从引入配置到源码级自适应原理(miniprogram-demo)

示例工程小程序前端 【免费下载链接】miniprogram-demo 微信小程序组件 / API / 云开发示例 项目地址: https://gitcode.com/gh_mirrors/mi/miniprogram-demo 点击查看 免费下载 t-navbar 是 TDesign 小程序组件库中位于页面内容区上方、系统状态栏下方的导航栏组件…

2026/10/15 3:49:43 阅读更多 →
Git 常用操作文档

Git 常用操作文档

一、修改用户名 & 邮箱(全局 / 当前仓库) 修改后下一次 commit 生效,已经提交的历史记录不会自动改变,不需要提交代码就能查看配置。 1. 全局(所有 git 项目生效,推荐) git config --global user.name "xxxx" git config --global user.email "你的…

2026/10/15 3:49:43 阅读更多 →
Dhizuku 设备所有者权限共享工具:架构原理、激活流程与 API 接入实践

Dhizuku 设备所有者权限共享工具:架构原理、激活流程与 API 接入实践

移动开发 【免费下载链接】Dhizuku A tool that can share DeviceOwner permissions to other application. 项目地址: https://gitcode.com/gh_mirrors/dh/Dhizuku 点击查看 免费下载 Dhizuku 是一款借鉴 Shizuku 设计思想的开源 Android 工具,其核心能…

2026/10/15 3:49:43 阅读更多 →

最新新闻

模板代码生成工具:从元数据到可用接口的完整实现

模板代码生成工具:从元数据到可用接口的完整实现

1. 为什么需要模板代码生成工具:一大半重复代码其实不该手写做后端开发的朋友应该都有过这种体验:新项目启动,建表、写实体、写Mapper、写Service接口和实现、写Controller,然后前端再把列表页、表单页、弹窗、状态标签挨个撸一遍…

2026/10/15 4:45:53 阅读更多 →
桶排序全解析:原理、复杂度与工程实践

桶排序全解析:原理、复杂度与工程实践

1. 从"把数据扔进格子里"说起:桶排序的第一性原理如果你接触排序算法有一阵子,大概率听说过这句话:"桶排序在数据分布均匀的时候能做到接近O(n)"。但很多人学完快排、归并之后,对桶排序的印象只剩下一个模糊的…

2026/10/15 4:45:53 阅读更多 →
ET 200MP模拟量输出模块AQ 4xU/I ST选型接线调试指南

ET 200MP模拟量输出模块AQ 4xU/I ST选型接线调试指南

简介:西门子SIMATIC S7-1500/ET 200MP模拟量输出模块AQ 4xU/I ST设备手册,面向工业自动化领域的工程技术人员、系统集成商与运维人员。内容聚焦模拟量输出模块在制造、能源、交通等场景下的选型、接线、参数设置与调试问题,帮助用户实现精准的…

2026/10/15 4:45:53 阅读更多 →
Windows开机自启全攻略:启动文件夹、注册表、任务计划与服务详解

Windows开机自启全攻略:启动文件夹、注册表、任务计划与服务详解

1. 开机自启这件事,远不止把快捷方式拖进启动文件夹那么简单很多人第一次接触开机自启,都是因为某个小工具每次重启后都要手动打开,烦得不行。于是上网一搜,看到最多的答案就是“把快捷方式拖进启动文件夹”,照做之后确…

2026/10/15 4:45:53 阅读更多 →
基于地点相似度的POI推荐与路径重组MATLAB实现

基于地点相似度的POI推荐与路径重组MATLAB实现

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

2026/10/15 4:45:53 阅读更多 →
延迟优化实战:从毫秒级到微秒级的系统性能提升路径

延迟优化实战:从毫秒级到微秒级的系统性能提升路径

1. 我为什么折腾到微秒级:被延迟拖垮的业务,往往都死得悄无声息很多人做性能优化,跑到“毫秒级”就收工了,觉得接口P99能压到5ms以内已经是了不起的成就。但如果你在真正的高并发业务链路里待过,就会明白:当…

2026/10/15 4:44:53 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →