首页/新闻资讯/正文详情

从GTK计算器到真实项目:gnome-calculator源码编译实战

发布时间:2026/9/25 10:28:51 来源:云帆数科 栏目:资讯中心
从GTK计算器到真实项目:gnome-calculator源码编译实战
GTK入门书翻到第133页十有八九是个计算器练习等你真正把 GNOME 计算器 45.0.2 从源代码编译跑起来才会发现教材例子和真实项目之间隔着整个工程化世界。这篇文章记录的就是我从那个经典练习出发亲手编译 gnome-calculator-45.0.2 的完整过程依赖怎么理清、Meson 构建怎么跑、哪些坑货让我浪费了一整个晚上。适合正在学 GTK 开发、想深入了解 Linux 桌面应用构建机制的读者抄作业。1. 从一个经典练习理解真实项目1.1 第133页的GTK计算器到底教会了我们什么几乎所有 GTK 入门的教程在讲到中间章节时都会安排一个计算器应用。这个选择太经典了因为计算器麻雀虽小五脏俱全你需要处理网格布局、按钮事件、文本显示、状态管理还得对付“连续按运算符”这种逻辑边界。如果说 Hello World 只是让你知道窗口怎么开那计算器就是让你真正理解事件循环和控件交互的入门第一课。一个典型的教材计算器长这样顶部一个文本框下面若干按钮排成四行四列。每次按数字就往文本框追加按运算符就记录当前值按等号就把结果算出来。用 GTK 写起来核心就是g_signal_connect把按钮的clicked信号连到回调函数回调里维护一个简易状态机。// 教材风格的GTK计算器片段我自己的练手版本 static void on_digit_clicked(GtkWidget *widget, gpointer data) { const char *digit g_object_get_data(G_OBJECT(widget), digit); GtkEntry *entry GTK_ENTRY(data); const char *current gtk_entry_get_text(entry); char *new_text g_strdup_printf(%s%s, current, digit); gtk_entry_set_text(entry, new_text); g_free(new_text); }这个练习的价值在于它强迫你去查控件文档、理解回调机制、处理字符串拼接。但说实话写完之后我有一种“好像学会了又好像什么都不太行”的感觉。因为我只用了GtkEntry、GtkGrid、GtkButton这些只是 GTK 控件库最表层的几个类。回调函数里做的是算术没有解析器没有错误处理没有国际化跟真正的产品代码差着十万八千里。后来我意识到一件事教材练习是引子真正的学习材料其实一直在系统里躺着——那些 GNOME 默认应用就是最好的教科书。比如 gnome-calculator它就是“计算器”这个课题从入门小练上升到生产级实现的完整答案。所以我在啃完第133页之后决定直接去啃 gnome-calculator 的源码并且从零把它编译一遍。这件事不止是“跑一个软件”那么简单它把你在书上学到的构建、依赖、编译、调试知识全部串起来了。1.2 为什么源码编译和跑二进制完全是两种学习深度直接去软件商店点一下安装十分钟后你就能用上 GNOME 计算器但这本质上只是消费行为。从源代码编译则完全不同它逼着你回答一连串“为什么”为什么 GNOME 项目要用 Meson 而不是 CMake为什么源码包里还有subprojects目录为什么我明明装了 GTK4 还报说找不到包为什么编译过了运行时又说图标主题不存在每个问题背后都是一个知识点。当你手动解决完这些问题你对 Linux 桌面应用的全链路就建立了一个轮廓上游源码 → 构建系统 → 打包 → 依赖管理系统 → 桌面环境集成。这比任何博客教程都更有说服力因为报错是真实的排查路径是你自己一步步走出来的。实事求是地说gnome-calculator 45.0.2 作为首次尝试的编译对象非常合适。第一它是 GNOME 官方维护的真实项目代码结构清晰第二它的依赖数量在 GNOME 应用里算少的不需要编译整个 GNOME 平台第三它使用 GTK4 和 libadwaita正好对应现在 GNOME 桌面主流技术栈。编译它等于以一个真实案例完成一次 GTK 现代开发环境的完整实操。2. 编译前的准备工作依赖、工具链和版本选择2.1 依赖清单与版本版本之间的爱恨情仇gnome-calculator 45.0.2 虽然只是一个计算器但它站在这条依赖链的顶端直接依赖 GTK4、libadwaita、GLib、GMPGNU 多重精度算术库、MPFR多重精度浮点运算库、libsoup 3.x、gsettings-desktop-schemas。我整理了一下它要的正常工作条件方便你对照检查自己的系统。依赖用途45.0.2 的最低版本要求glib-2.0基础数据结构、事件循环2.56 以上实际建议系统自带最新版gtk4界面控件库项目用的是 GTK4 而非 GTK34.10 以上libadwaita-1GNOME 的现代视觉控件库1.0 以上libsoup-3.0HTTP 网络功能主要用在货币换算功能上3.0 以上gmp大整数和高精度算术底层库—mpfr高精度浮点运算配合 gmp 使用—gsettings-desktop-schemasGSettings 的桌面相关 schema—我第一次编译时犯的错误就是只装了gtk4-dev和libadwaita-dev结果meson setup在检测依赖阶段就报错找不到 libsoup找不到 gmp找不到 mpfr。这些库不是摆设它们保证了计算器的精度。普通人可能觉得0.1 0.2等于0.30000000000000004也没啥大不了但 gnome-calculator 是一门正经科学的计算器它的数学内核会用 mpfr 做任意精度运算确保工程计算和单位换算不出现浮点误差累积。这里有一个重要的判断逻辑编译这个项目时你的系统直接提供这些依赖的二进制包就够了不需要把这些依赖逐个源码编译。很多新手一听说“从源码编译”就以为要从 glib 开始把整条依赖栈全部编译一遍这是最大的误区。GNOME 项目的官方构建文档默认是让你使用系统发行版已经打包好的依赖只用源码编译目标项目本身。你自己编译 glib 和 gtk4 是另一项巨大的工程通常只有在做跨版本测试或者给特殊架构做适配时才需要。2.2 Meson 和 NinjaGNOME 世界的构建基石GNOME 项目从四十几个模块迁移到 Meson 构建系统是在 2017 到 2020 期间陆续完成的。现在新项目的标配就是 Meson Ninja。Meson 负责描述构建逻辑Ninja 负责实际编译执行。这个概念类比一下Meson 是项目经理告诉 Ninja 工人每块砖什么时候搬、搬到哪、谁先谁后Ninja 是干活的施工队只操心怎么最高效地完成任务。Gnome-calculator 45.0.2 的构建流程是标准的 Meson 三件套meson setup build ninja -C build meson test -C build如果你用 CMake 习惯了第一次接触 Meson 会觉得它格外“啰嗦”setup时要指定构建目录编译时要记得-C build因为 Meson 强制 out-of-source 构建。也就是所有中间文件、编译产物全部放到 build 目录里源目录始终保持干净。这一点在我看来是极大的美德。CMake 虽然也推荐 out-of-source 构建但在实践中总有人直接源码里跑 cmake留下一地的CMakeCache.txt。Meson 直接把这条路堵死了你想在源码根目录里编译它直接报错拒绝执行。写完这篇文章时我已经编译过 GNOME 45 周期内的好几个应用总结出一个规律Meson 的理解成本不高常用命令就那么几个。命令作用meson setup build配置构建目录检测依赖和生成构建规则meson configure build在已有构建目录上调整配置可以加参数meson compile -C build等同于ninja -C build重新编译meson test -C build跑项目的测试套件meson install -C build等同于ninja -C build install安装到系统我做首次编译时直接用的ninja -C build因为习惯上还是喜欢 Ninja 名后来发现新版 Meson 更推荐meson compile两者等价看个人习惯。需要留意的是 Ninja 的并行参数-j第一次我不限并行直接全核编译内存吃了三个多 G这个过程对于只有 8G 内存的机器来说有点紧张。建议控制在-j4左右功耗和稳定性都更好。3. 实操完整过程从 tar.xz 到桌面上的计算器图标3.1 下载源码和校验完整性我把编译对象定为gnome-calculator-45.0.2.tar.xz。这个版本对应的是 GNOME 45 代际周期45.0.2 属于维护修正版本。源码可以从 GNOME 官网的源码目录下载也可以在软件仓库里找对应的 release tarball。我习惯用命令行方式下载wget https://download.gnome.org/sources/gnome-calculator/45/gnome-calculator-45.0.2.tar.xz拿到压缩包之后第一件事是校验完整性。官网源码目录里通常会附带.sha256sum或者.sha256文件照着眼睛看哈希值是网络上最容易踩的坑之一。我第一次就是直接解压结果编译到一半才发现文件损坏白白浪费时间排查。正确的做法是sha256sum gnome-calculator-45.0.2.tar.xz把输出的哈希值和官方页面上公布的值对比一下确认一致再解压。这一步看似多余但在网络传输不稳定时能省下至少半小时的调试精力。解压tar -xJf gnome-calculator-45.0.2.tar.xz cd gnome-calculator-45.0.2/进去之后先别急着配置花两分钟浏览一下目录结构这是读源码项目的习惯。里面几个关键目录src/放主程序逻辑lib/是数学内核和计算引擎实现data/放desktop文件、图标和 GSettings schematests/是自动化测试subprojects/是 Meson 的子项目 wrap 定义。分析这个结构本身就能学到很多一个真实应用会主动把“表现层”和“计算逻辑层”分离开来用单独的lib/目录承载核心算法这一点跟教材练习一眼望到底的单一 main.c 形成了鲜明对比。3.2 meson setup选择构建目录和安装前缀配置构建目录时最重要的两个选择是构建目录名和安装前缀。meson setup build --prefix/usr--prefix/usr表示安装到系统目录这样装完以后应用的desktop文件、GSettings schema、图标都会落到系统标准位置。发行版自带的 gnome-calculator 一般也装在/usr如果不先卸载旧版本meson install会直接覆盖系统原有文件。我自己实际建议是首次编译别碰/usr除非你明确知道自己要覆盖系统版本。更稳妥的做法是装到用户目录meson setup build --prefix$HOME/.local装到~/.local的好处是能平行共存改动只影响你的用户出问题随时删目录不影响系统其他组件。代价是 GNOME Shell 的应用列表不一定能自动识别到~/.local/share/applications里的 desktop 文件。不过在多数发行版上~/.local/share本身就是 XDG 数据目录标准的一部分GNOME 桌面会自动扫描所以图标一般会正常出现。我最终用了$HOME/.local这个方案并在配置时一并设置了构建类型meson setup build --prefix$HOME/.local --buildtypereleasebuildtype的选择逻辑值得多说一句。debug模式会保留符号信息方便用 gdb 调试但编译产物大运行性能略差。release模式会开优化符号信息少。如果你只是跑应用直接release如果你想在阅读源码过程中动手调试计算逻辑可以先选debug后面再用meson configure改。在配置阶段Meson 会输出一大串检测结果包括找到的 GTK 版本、libadwaita 版本、数学库是否可用。如果你的系统缺了某些开发头文件这一步就会报错提示你安装对应软件包。我最初的环境里缺了libsoup-3.0 dev包和libgmp-dev报错信息像这样Dependency libsoup-3.0 not found处理方法很简单用发行版的包管理器补上开发包。Debian/Ubuntu 系列是libsoup-3.0-dev、libgmp-dev、libmpfr-devFedora/RHEL 系列是libsoup3-devel、gmp-devel、mpfr-devel。装完以后重跑meson setup build这次 Meson 会重新检测依赖并且顺利通过。3.3 ninja 编译并行、测试和输出解读配置完成后进入编译环节。Ninja 的编译速度极快但它只是调度者实际编译工作还是交给 GCC 或者 Clang。当时我执行的是ninja -C build -j4第一次编译时没有限制并行度Ninja 默认按 CPU 核心数跑16 核机器直接给我吃了 4G 内存。第二次我学乖了直接固定-j4。GNOME 计算器这个体量的项目四核并行编译大概两三分钟能完成不会让人等到绝望。如果编译中遇到源码报错不要急着怀疑编译器。绝大多数情况是你系统的依赖版本跟项目要求的不一致或者 Meson 检测到了某一个库但实际头文件路径有问题。特别要注意的是gtk4和gtk4-dev的关系只装了运行库没装开发包Meson 会一直提示找不到gtk4开发依赖但如果你在 GTK3 的老系统上装了旧版开发包Meson 检查到 GTK4 版本太低也会拒绝继续。编译完成后建议跑一下测试套件再安装这是课本很少强调但工程实践极其重要的一步。GNOME 计算器的测试集中在数学引擎部分命令是meson test -C build我跑测试的时候一个测试失败都看不到全部 PASS。计算器项目的测试覆盖了单位换算、货币转换、数学表达式解析这些纯逻辑功能跑一遍测试说明你编译出来的数学内核和上游预期的行为一致。这一步在编译别人的代码时特别能建立信心。3.4 安装和杀出来的桌面文件测试通过后执行meson install -C build因为目标是$HOME/.local不需要 root 权限。安装过程会输出每个文件的去向包括可执行文件、GTK 图标、desktop 文件、以及 GSettings schema。这里有一个小坑GSettings schema 编译完成后需要让系统重新识别。如果你是以普通用户安装到~/.local需要确保GSETTINGS_SCHEMA_DIR环境变量指向$HOME/.local/share/glib-2.0/schemas或者干脆重新登录。GNOME 桌面的会话启动时一般会扫描这个目录但如果你是在当前会话里直接跑测试schema 可能不会被及时加载计算器启动时会抱怨找不到 schema。安装完成后从命令行直接运行gnome-calculatorWindow 应该弹出来能正常输入数字和运算符。我还试了--version参数输出显示版本号 45.0.2说明我装的确实是源码编译出来的版本而不是系统自带的旧版本。3.5 子项目 subprojects 里藏着的数学引擎说到这里必须单独聊聊subprojects目录。gnome-calculator 45.0.2 的源码包里带了一个名为mmd的子项目全称是 Math Markup Language它是计算器用于渲染数学公式的库。Meson 的 wrap 机制会自动下载这个子项目。但问题是如果你的网络环境访问上游 GitLab 不稳定meson setup会在拉取mmd时卡住半天没有反应。处理这个问题的经验是这样的subprojects/目录下有一个mmd.wrap文件里面记录了源码的 Git 仓库地址和对应的 commit hash。如果自动拉取失败你可以手动去 GitLab 上把对应 commit 的源码打包下载下来解压后放到subprojects/mmd/目录里再重新meson setupMeson 会发现本地已有源码直接跳过下载。国内环境通常还有一个更省事的路径使用 GNOME 源码的镜像站。很多 Linux 发行版的镜像站都会同步 GNOME 的 release tarball包括各个子项目。把download.gnome.org换成你所在区域速度快的镜像下载mmd对应的压缩包放到本地然后让 wrap 走本地源。这个操作的本质是理解 Meson 的“本地优先”策略只要subprojects/name/目录存在就优先用目录里的源码。4. 一路上踩过的坑错误排查与修复记录4.1 坑一GTK4 和 GTK3 的“隐形冲突”我一开始是在一台同时装有 GTK3 和 GTK4 的开发机上编译的。Meson 报错让我一度很困惑它说找不到 GTK4但我知道系统里明明装了libgtk-4-dev。后来用pkg-config --modversion gtk4一查才发现某个旧的软件包把 GTK4 的 pkg-config 文件路径污染了导致 Meson 检索的 prefix 不对。解决方法是清理掉/usr/lib/pkgconfig里的旧冲突文件或者用环境变量PKG_CONFIG_PATH明确指定 GTK4 dev 包所在目录。4.2 坑二adwaita-icon-theme 缺失导致窗口图标空白安装完首次运行时窗口标题栏左边本应显示计算器图标结果是一个空白占位。查日志看到大量 icon theme 相关的 warning这才意识到 GTK4 应用默认使用 Adwaita 图标主题我的自定义系统没有装adwaita-icon-theme的完整版本。装完图标主题包后重新登录图标恢复正常。这个坑和你写的 GTK 代码没有任何关系纯粹是桌面环境集成问题。遇到类似“功能正常但是图标全没”的情况优先检查系统图标主题完整性而不是去查代码。4.3 坑三编译产物运行时报 schema 找不到安装之后直接在终端跑程序报出类似这个的 GLib 异常找不到 GSettings schemaorg.gnome.calculator。原因是我在同一个会话里安装了 schema但 dconf 服务还没刷新。最简单的解决措施就是退出当前会话重新登录或者临时设环境变量export GSETTINGS_SCHEMA_DIR$HOME/.local/share/glib-2.0/schemas这招在 GNOME Wayland 会话下尤其好用。如果你用 X11 会话重启一次也能解决。4.4 坑四计算器界面显示英文中文环境变量处理我的系统是中文 locale但编译出来的计算器界面却是英文。仔细看才发现项目使用的翻译文件.po虽然在源码包里有但 Meson 默认根据系统 locale 生成.mo文件。如果编译时LANG环境变量恰好不是zh_CN.UTF-8则对应的翻译会被跳过。重编译之前先把环境变量指到中文再跑一遍meson compile这把翻译文件补上。一个小细节但对桌面应用使用者来说是否显示母语体验差别很大。这个问题的排查提醒我源码编译的软件locale 相关的归属阶段是构建期不是运行期。4.5 依赖版本速查与避坑清单为了让你少走弯路我把这个项目编译过程中最常见的依赖缺失和对应解决方式列成了速查表。故障现象可能原因快速解决meson setup时报缺少 gtk4系统只有 GTK3或者 dev 包安装不完整安装libgtk-4-dev或gtk4-devel缺少 libsoup-3.0网络功能依赖未装Debian 系装libsoup-3.0-devFedora 系装libsoup3-devel缺少 gmp/mpfr数学库未装开发包安装libgmp-dev、libmpfr-dev或对应 rpmmeson setup 卡住不动子项目 mmd 拉取失败手动放置源码到 subprojects/mmd重新配置运行时图标空白adwaita-icon-theme 缺失安装完整图标主题运行报 GSettings schema 找不到schema 未刷新重登录或设GSETTINGS_SCHEMA_DIR写在编译完成之后老实说第133页那个小练习和 gnome-calculator-45.0.2 之间隔着的不只是几百行代码和一套构建工具而是一整条“软件工程”的思路。教材里教我g_signal_connect怎么连按钮真实项目告诉我回调函数只是冰山一角——背后还有表达式解析、数学内核、单位换算、migrations 一样的东西藏在lib/和src/深处。编译真实项目的意义不在于“多跑了一个软件”而在于它把我之前零散的知识全部打碎重组了一遍。编译完成后我还做了一件事把项目里我最好奇的那段数学表达式解析代码读了一遍设想如果要在第133页那个练习里加入 “支持括号运算”应该怎么抄它。这大概就是学习 GTK 最实际的方式——从真实可用的应用源码里找答案。最后留一个小技巧如果你后面想去改 gnome-calculator 的源码从头再编译一次不用清空 build 目录直接meson compile -C build只会增量编译改动过的文件速度飞快。这个体验比教材练习里每次都要gcc main.c干净利落得多。

相关推荐

Intel DAAL 安装与使用:TaoToken 统一 Key 接入配置与验证
Intel DAAL 安装与使用: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/9/25 10:28:45

GitHub项目推荐--awesome-design-md:给 AI 一份“设计说明书”,告别随机 UI
GitHub项目推荐--awesome-design-md:给 AI 一份“设计说明书”,告别随机 UI

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

com.blankj:utilcodex 使用指南:从依赖引入到常用工具类实战
com.blankj:utilcodex 使用指南:从依赖引入到常用工具类实战

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

前端工程师必备:5个改变开发效率的 MCP Server 与 TaoToken 统一接入配置
前端工程师必备:5个改变开发效率的 MCP Server 与 TaoToken 统一接入配置

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

Claude Code 配 TaoToken:settings.json 骨架与 PowerShell 验证
Claude Code 配 TaoToken:settings.json 骨架与 PowerShell 验证

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

DeepSeek Harness 0.1.5-rc 插件沙盒化升级指南
DeepSeek Harness 0.1.5-rc 插件沙盒化升级指南

1. 为什么0.1.5-rc升级后插件集体“失联”?不是Bug,是架构演进的必然阵痛DeepSeek Harness 这个名字最近在本地大模型工作流圈子里出现频率陡增——它不像传统LLM框架那样只管推理,而是把“智能体编排”“技能调度”“插件生命周期管理”全打… · 2026/9/25 11:00:39

图像处理标准测试图:Lena、cameraman的获取与验证方法
图像处理标准测试图:Lena、cameraman的获取与验证方法

干图像处理这行的人,迟早都会遇到一个绕不开的问题:调试边缘检测、验证压缩算法、跑一跑去噪模型的时候,总不能每次都拿手机自拍来当输入吧?翻了半天博客,下了好几个链接,结果要么是带水印的,要… · 2026/9/25 11:00:08

内容枯竭一表破局:social-media-skills的content-matrix与niche-research如何一次产出32+选题
内容枯竭一表破局:social-media-skills的content-matrix与niche-research如何一次产出32+选题

内容枯竭一表破局:social-media-skills的content-matrix与niche-research如何一次产出32选题 【免费下载链接】social-media-skills 项目地址: https://gitcode.com/gh_mirrors/so/social-media-skills 做个人品牌最折磨人的瞬间,就是打开编辑器… · 2026/9/25 11:00:08

Android ListView 配 TaoToken:simpleCursorAdapter 数据绑定与 settings.json 骨架
Android ListView 配 TaoToken:simpleCursorAdapter 数据绑定与 settings.json 骨架

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

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

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

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

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

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

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

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码