Node.js包管理核心指南:从npm安装到依赖管理全解析
1. 项目概述为什么一个“简单”的安装教程如此重要如果你刚开始接触前端或者Node.js开发大概率第一个遇到的命令就是npm install。看起来简单敲一下回车依赖包就哗啦啦地下来了。但现实往往骨感你可能在第一步就卡住了npm命令找不到安装过程卡在某个包一动不动或者更糟安装完了一运行项目报了一堆版本冲突的错误。我见过太多新手甚至一些工作一两年的朋友对npm的理解还停留在“装包工具”的层面一旦遇到环境问题、网络问题、依赖冲突问题基本就靠重启电脑、重装Node.js、或者求助同事这三板斧。所以这个“详细教程”的目的绝不是教你如何打出npm install这几个字符。我想和你深入聊聊npm安装背后的整个生态和最佳实践。从最基础的“如何让系统认识npm这个命令”到解决国内令人头疼的网络问题再到理解依赖管理的核心逻辑package.json与package-lock.json最后到如何优雅地发布自己的包。这就像学开车不仅要会踩油门和刹车还得懂点交规和基础保养才能安全、顺畅地上路。无论你是刚入门的新手还是想系统梳理一下npm知识的中级开发者这篇从实战中总结出来的经验应该都能帮你避开不少坑。2. 核心基石Node.js与npm的安装与环境配置npm是 Node.js 的包管理器它随着 Node.js 一起安装。因此第一步永远是正确安装 Node.js。2.1 Node.js 安装方案选型目前主流的安装方式有两种选择哪种取决于你的使用场景和对环境纯净度的要求。方案一官方安装包最直接直接从 Node.js 官网下载对应操作系统的安装包.msi 用于 Windows.pkg 用于 macOS二进制包用于 Linux。这是最省心的方法适合绝大多数个人开发者和新手。安装过程基本就是一路“下一步”安装程序会自动将 Node.js 和npm的可执行文件路径添加到系统的环境变量中。注意在 Windows 上安装时务必勾选“Automatically install the necessary tools...”这个选项如果出现。它会安装一些构建原生模块可能需要的工具如 Python、Visual Studio Build Tools避免后续安装某些依赖如node-sass时失败。方案二使用版本管理工具推荐进阶用户对于需要同时维护多个项目、且这些项目可能依赖不同 Node.js 版本的开发者我强烈推荐使用版本管理工具。nvm (Node Version Manager)适用于 macOS/Linux。它允许你在命令行中轻松切换多个 Node.js 版本。nvm-windows适用于 Windows 的 nvm 移植版功能类似。fnm一个更快的、跨平台的 Node.js 版本管理工具使用 Rust 编写速度上有优势。使用版本管理工具的好处是每个版本的 Node.js 及其附带的npm都被隔离在自己的目录下切换版本时环境完全独立不会互相污染。这对于解决“在我机器上好好的怎么到你那就错了”这类问题非常有帮助。2.2 验证安装与理解环境变量安装完成后打开终端Windows 用 CMD 或 PowerShellmacOS/Linux 用 Terminal输入以下命令验证node -v npm -v如果正确输出版本号如v18.17.0和9.6.7恭喜你基础安装成功。如果系统提示“不是内部或外部命令”或“command not found”那说明环境变量PATH没有正确配置。这是新手最常踩的第一个坑。环境变量 PATH 是什么你可以把 PATH 想象成一张“全局通讯录”。当你在终端输入一个命令比如npm时系统会按照 PATH 中记录的路径列表一个一个文件夹去找有没有叫npm的可执行文件。找到了就运行找不到就报错。如何检查和配置Windows:找到 Node.js 的安装目录通常类似C:\Program Files\nodejs\。进入这个文件夹确认npm.cmd和node.exe文件存在。右键点击“此电脑” - “属性” - “高级系统设置” - “环境变量”。在“系统变量”或“用户变量”中找到Path变量双击编辑。检查列表中是否包含 Node.js 的安装路径如C:\Program Files\nodejs\。如果没有点击“新建”添加它。重要修改环境变量后必须关闭所有已打开的终端窗口再重新打开一个新的更改才会生效。macOS/Linux: 如果使用官方安装包通常会自动配置。如果使用 Homebrew 安装或手动安装可能需要手动配置。对于 nvm/fnm 用户它们会自动管理 PATH你只需要按照其文档进行初始化通常在~/.bashrc,~/.zshrc等文件中添加一行脚本。2.3 解决 PowerShell 执行策略问题在 Windows 的 PowerShell 中你可能会遇到这个经典错误npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1因为在此系统上禁止运行脚本...这是因为 PowerShell 默认的执行策略Execution Policy限制了脚本运行这是一种安全措施。解决方案选一种即可以管理员身份运行 PowerShell然后执行Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser这条命令将当前用户的执行策略设置为RemoteSigned允许运行本地脚本和来自可信发布者的远程签名脚本。输入Y确认。使用 CMD 或 Windows Terminal如果你不常使用 PowerShell可以直接使用传统的命令提示符CMD它不受此策略影响。修改 npm 的脚本后缀不推荐这是一个偏方将npm.cmd重命名为npm.ps1的调用改为直接使用npm.cmd但可能引发其他问题。我个人推荐第一种方案一劳永逸。完成后重新打开 PowerShell 即可正常使用npm。3. 依赖安装的核心机制与实战命令解析环境搞定后我们进入核心环节安装依赖。npm install可简写为npm i是使用频率最高的命令但它的行为比你想象的要复杂。3.1 理解 package.json项目的“物料清单”在运行npm install之前你的项目根目录下应该有一个package.json文件。这个文件是 npm 生态的基石它定义了项目的基本信息、脚本命令以及最重要的——依赖关系。依赖主要分两类dependencies项目生产环境运行时必需的包。例如react,vue,express,lodash。devDependencies仅在项目开发阶段需要的包。例如测试框架jest、构建工具webpack、代码格式化工具prettier、TypeScript 编译器typescript。使用--save和--save-dev参数安装包时会自动将其写入对应的字段。npm install axios --save # 安装到 dependencies npm install jest --save-dev # 安装到 devDependencies现在npm默认已启用--save所以npm install axios等价于上面第一条命令。3.2 深度解析 package-lock.json确保依赖树的一致性这是理解现代npm安装行为的关键。当你第一次运行npm install时除了下载包到node_modules还会生成一个package-lock.json文件。它解决了什么问题假设你的项目依赖包 AA 又依赖包 B 的版本^1.0.0表示兼容 1.x.x 的最新版。今天安装时B 的最新版本是1.2.0。一个月后B 发布了1.3.0可能存在未知问题。如果没有 lock 文件你的同事在新电脑上安装或者你在 CI/CD 服务器上构建就会得到1.3.0版本的 B。这可能导致“明明代码没改却出 bug 了”的诡异情况。package-lock.json精确锁定了整个依赖树中每一个包的确切版本号和其下载地址的哈希值。只要这个文件存在无论何时何地运行npm install都会安装完全相同的依赖树保证了环境的一致性。实操心得务必把package-lock.json提交到版本控制系统如 Git中。这是团队协作和持续集成的生命线。以前流行的“删除node_modules和package-lock.json再重装”来解决问题的做法在现代npmv5中已经过时并且可能引入不确定性。3.3 npm install 的不同场景与行为npm install的行为会根据上下文发生变化初始化新项目在空目录下运行npm init -y生成package.json然后npm install package安装包。安装现有项目所有依赖当你拉取一个已有项目后直接运行npm install不带任何包名。npm 会读取package-lock.json优先或package.json安装所有dependencies和devDependencies。安装单个新包npm install package-name。这会更新package.json和package-lock.json。全局安装npm install -g package-name。将包安装到系统全局目录使其在任何地方都能作为命令行工具使用如vue-cli,create-react-app。慎用全局安装因为它可能导致版本冲突。对于项目专用的构建工具更推荐作为devDependencies安装在本地通过npx命令运行例如npx create-react-app my-app。3.4 版本符号SemVer详解package.json中的版本号前面常有符号理解它们至关重要^1.2.3兼容版本默认允许更新到**当前主版本号1**下的最新版本。即可以安装1.x.xx2但不能安装2.0.0。这是最常用的。~1.2.3近似版本允许更新到**当前次版本号1.2**下的最新版本。即可以安装1.2.xx3但不能安装1.3.0。更保守。1.2.3精确版本锁定到该确切版本不更新。、、、指定版本范围。*或x匹配任何版本。非常危险不要在生产依赖中使用。正是由于^和~的存在不同时间安装可能得到不同的依赖树才凸显了package-lock.json的重要性。4. 网络优化与镜像源配置实战对于国内开发者直接从 npm 官方源下载依赖速度慢且不稳定甚至经常超时npm install卡住不动。配置国内镜像源是必做操作。4.1 临时使用镜像源在安装命令后添加--registry参数npm install --registryhttps://registry.npmmirror.com这种方式只对当前命令生效。4.2 永久配置镜像源推荐更一劳永逸的方法是修改 npm 的配置将默认源指向国内镜像。查看当前源npm config get registry切换为淘宝源npmmirror.comnpm config set registry https://registry.npmmirror.com淘宝源现已更名为npmmirror.com它是国内最稳定、同步最及时的 npm 镜像之一。切换回官方源npm config set registry https://registry.npmjs.org4.3 使用 nrm 工具管理多个源如果你需要经常在官方源、公司私有源、测试源之间切换手动改配置很麻烦。可以安装nrmnpm registry manager这个工具来管理。npm install -g nrm # 全局安装 nrm nrm ls # 列出所有可用的源 nrm use taobao # 切换到淘宝源 nrm test taobao # 测试淘宝源的响应速度nrm的本质是修改你本地的npm config只是提供了一个更便捷的命令行界面。4.4 解决特定包安装问题二进制包镜像有些包例如puppeteer会下载 Chromiumnode-sass会下载二进制绑定文件除了 JavaScript 代码还需要下载平台相关的二进制文件。这些文件的下载地址可能也托管在境外同样需要配置镜像。以puppeteer为例可以设置环境变量# macOS/Linux export PUPPETEER_DOWNLOAD_HOSThttps://npmmirror.com/mirrors # 然后再运行 npm install # Windows (PowerShell) $env:PUPPETEER_DOWNLOAD_HOSThttps://npmmirror.com/mirrors或者查阅特定包的文档看是否支持通过.npmrc文件配置镜像。你可以在项目根目录或用户主目录创建.npmrc文件写入配置sass_binary_sitehttps://npmmirror.com/mirrors/node-sass/ phantomjs_cdnurlhttps://npmmirror.com/mirrors/phantomjs/5. 高级操作、问题排查与发布流程掌握了基础安装和配置我们来看看更进阶的操作和如何解决那些令人头疼的错误。5.1 依赖更新与审计更新包npm update package-name # 更新指定包遵守package.json中的版本符号 npm outdated # 检查有哪些过时的包注意npm update会更新package-lock.json。如果想升级主版本如从^1.x.x到^2.x.x可能需要使用npm install packagelatest或专门的工具如npm-check-updates。安全审计npm audit命令会检查项目依赖中的已知安全漏洞并给出修复建议。根据提示运行npm audit fix可以自动修复一些漏洞。5.2 常见错误与排查技巧实录npm ERR! code ENOENT/npm ERR! code EACCES可能原因权限不足尤其是在全局安装时或者在 macOS/Linux 上使用了sudo导致文件所有权混乱。解决方案避免使用sudo npm install。可以通过npm config set prefix ~/.npm-global将全局安装目录设置到用户目录下并将~/.npm-global/bin加入 PATH。如果node_modules目录权限混乱可以尝试删除它并重新安装rm -rf node_modules package-lock.json npm install注意备份。npm ERR! Invalid dependency type/npm ERR! Missing script: “dev”可能原因package.json文件格式错误或者你运行的脚本如npm run dev在package.json的scripts字段中没有定义。解决方案检查package.json的 JSON 语法是否正确可以使用 JSON 验证工具。检查scripts字段是否正确定义了dev: ...。npm WARN using --force Recommended protections disabled.触发条件当你使用npm install --force或npm audit fix --force时出现。含义与风险这个警告告诉你你正在绕过 npm 的一些保护性检查如对等依赖冲突、破坏性更新等强制进行操作。这可能导致依赖关系被破坏项目无法运行。仅在明确知道后果且其他方法都无法解决问题时使用。依赖树冲突/无法解析现象安装失败提示无法找到满足所有依赖版本要求的解决方案。排查运行npm ls problem-package-name可以查看这个包在依赖树中的具体位置和版本帮助定位是哪个上游依赖引入了冲突版本。解决尝试删除node_modules和package-lock.json后重装。这是利用npm新的解析算法重新计算依赖树。如果冲突无法解决可以考虑使用npm install --legacy-peer-deps。这个标志会让 npm 忽略对等依赖peerDependencies冲突但可能导致运行时错误需谨慎。终极方案使用yarn或pnpm这类具有不同依赖解析算法的包管理器有时能解决npm无法解决的冲突。5.3 发布你自己的 npm 包当你写了一个可复用的模块想要分享给社区时就需要发布到 npm 仓库。准备工作在 npm 官网注册一个账号。在终端登录npm login输入用户名、密码和邮箱。确保你的package.json中的name字段是唯一的尚未被占用且version符合语义化版本规范。关键文件package.json定义入口文件main或exports、依赖、关键字等。.npmignore类似于.gitignore列出发布时不希望包含的文件如测试文件、构建配置等。如果没有npm 会使用.gitignore。发布命令npm publish如果是首次发布就是公开包。如果你想发布测试版可以打一个带标签的版本npm version 1.0.0-beta.1然后npm publish --tag beta。更新版本 修改代码后使用npm version patch|minor|major来更新package.json中的版本号例如npm version patch从1.0.0到1.0.1然后再次运行npm publish。发布注意事项发布前务必运行npm pack命令它会生成一个.tgz压缩包你可以解压这个包来检查最终发布出去的文件内容是否符合预期避免泄露敏感信息如.env文件。对于公共包命名需谨慎确保无侵权且能描述功能。考虑使用 TypeScript 编写并提供类型声明文件.d.ts这对使用者非常友好。良好的 README.md 和完整的测试是吸引用户的关键。6. 从npm到现代包管理器yarn与pnpm浅析虽然npm是官方标配且功能日益完善但社区也涌现了优秀的替代品它们在某些场景下表现更佳。Yarn (v1 / Classic)由 Facebook 推出早期以其确定性安装通过yarn.lock和并行下载带来的速度优势而流行。其工作流与npm高度相似yarn add/yarn install。Yarn (v2 / Berry)完全重写引入了创新的 Plug’n’Play (PnP) 模式完全抛弃node_modules将依赖关系存储在压缩包中极大提升了安装速度和磁盘空间利用率。但生态兼容性要求更高。pnpm我个人目前最推荐的替代方案。它采用“内容寻址存储”和“硬链接”机制。所有项目的依赖都统一存储在一个全局仓库中项目中的node_modules里的文件只是指向全局存储的硬链接。这带来了三大好处极快的安装速度如果某个版本的包已在全局存储中安装它只是创建一些硬链接几乎是瞬间完成。巨大的磁盘空间节省同一个版本的包在磁盘上只存在一份无论多少个项目使用它。严格的依赖结构避免了“幽灵依赖”问题即项目代码引用了未在package.json中声明的包这个包只是因为被其他依赖安装而存在于node_modules中。如果你开始一个新项目或者对现有项目的依赖管理感到头疼我强烈建议尝试一下pnpm。它的命令与npm几乎一一对应pnpm install,pnpm add,pnpm run迁移成本很低但带来的效率和规范性的提升是实实在在的。绕开npm install表面的简单深入其背后的环境、配置、原理和生态你会发现它远不止是一个安装命令而是整个 Node.js 开发生态的门户。从解决“命令找不到”的环境问题到配置镜像源优化网络再到理解package-lock.json保证团队协作一致最后到能诊断常见错误甚至发布自己的包——这套组合拳打下来你在项目依赖管理上才算真正入了门。工具在迭代最佳实践也在发展保持学习选择最适合自己和团队的工具与工作流才能让开发过程更加顺畅。

相关新闻

深入解析Spring AOP底层原理:从代理模式到性能调优实战

深入解析Spring AOP底层原理:从代理模式到性能调优实战

1. 项目概述:为什么我们需要深入理解Spring AOP的底层? 在Java企业级开发里,Spring框架几乎是绕不开的存在,而它的AOP(面向切面编程)功能,更是实现日志、事务、权限校验这些横切关注点的“瑞士军…

2026/10/10 20:30:21 阅读更多 →
Edge浏览器锦集按钮消失?5步系统排查与修复指南

Edge浏览器锦集按钮消失?5步系统排查与修复指南

1. 问题现象与影响范围 最近在几个技术社区和用户群里,都看到有朋友在问同一个问题:Edge浏览器右上角那个五颜六色的“锦集”按钮,怎么突然不见了?这个看似不起眼的小图标,对于习惯用它来快速收藏、整理网页内容的朋友…

2026/10/13 18:38:55 阅读更多 →
MySQL安装全攻略:从版本选择到避坑指南,一次搞定Windows/Linux部署

MySQL安装全攻略:从版本选择到避坑指南,一次搞定Windows/Linux部署

1. 为什么你的MySQL安装总是不顺? 如果你在网上搜索过MySQL安装教程,大概率会看到两种极端:一种是“下一步、下一步、完成”的傻瓜式指南,另一种是充斥着复杂命令、让人望而生畏的官方文档。前者在你遇到报错时毫无帮助&#xff0…

2026/10/14 7:14:27 阅读更多 →

最新新闻

基于PSO算法的双微网优化调度MATLAB实现

基于PSO算法的双微网优化调度MATLAB实现

1. 多微网优化调度模型概述 微电网作为分布式能源系统的重要实现形式,其优化调度一直是能源领域的研究热点。当多个微电网通过联络线相互连接时,就形成了多微网系统(Multi-Microgrid System)。这种架构能够实现能源的互补共享&…

2026/10/14 11:36:46 阅读更多 →
Python循环结构详解:从基础到高级优化技巧

Python循环结构详解:从基础到高级优化技巧

1. 循环结构基础概念 循环是编程中最基础也最强大的控制结构之一。简单来说,循环就是让计算机重复执行某段代码,直到满足特定条件为止。想象你在教一个小朋友数数,从1数到100,你不会说"说1,说2,说3...…

2026/10/14 11:36:46 阅读更多 →
Grok Bot从0到1实战:环境搭建、群组接入与任务调试全指南

Grok Bot从0到1实战:环境搭建、群组接入与任务调试全指南

1. 从零理解 Grok Bot:它到底能帮你干什么很多人第一次听到 Grok Bot 这个词,脑子里冒出来的第一个问题就是:它跟普通的聊天机器人有什么区别?我直接说结论——Grok Bot 的核心价值不在于“聊天”,而在于“干活”。它是…

2026/10/14 11:36:46 阅读更多 →
KITTI Raw Data转TUM格式:位姿基准、坐标变换与SLAM评估避坑指南

KITTI Raw Data转TUM格式:位姿基准、坐标变换与SLAM评估避坑指南

简介:面向运行VINS-Fusion等SLAM算法时进行精度比对的开发者,这份资源集中整理了KITTI raw data中00-10序列的groundtruth位姿与时间戳,并给出了可直接使用的TUM格式位姿轨迹。包内还包含各序列对应的轨迹图、数据集sequence说明以及一个转换…

2026/10/14 11:36:46 阅读更多 →
Grok Bot 保姆教程:从环境搭建到拉群协作的完整指南

Grok Bot 保姆教程:从环境搭建到拉群协作的完整指南

1. 从零理解 Grok Bot:它到底能帮你干什么 很多人第一次听到 Grok Bot 这个词,脑子里冒出来的第一个问题就是:这玩意儿跟普通的聊天机器人有什么区别?我直接开个网页对话不就行了吗,为什么还要专门去"装"一个…

2026/10/14 11:36:46 阅读更多 →
Grok Bot 从零搭建实战:群聊自动回复与知识库接入指南

Grok Bot 从零搭建实战:群聊自动回复与知识库接入指南

1. 从零上手 Grok Bot:先搞清楚它到底能干什么很多人第一次听到 Grok Bot 这个词,脑子里浮现的可能是那种满屏代码、需要自己搭服务器、配环境变量的硬核玩意儿。其实不是。Grok Bot 本质上是一个可以接入群聊、自动响应消息、执行特定任务的机器人。你可…

2026/10/14 11:35:45 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

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

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

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

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

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

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

2026/10/13 16:22:04 阅读更多 →
影刀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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →