<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>社亦园的旅行笔记</title><description>一个混乱善良者的数字游牧实践</description><link>https://blog.sheyiyuan.com/</link><language>zh_CN</language><item><title>Gitea 遭遇 Spam 批量注册与恶意建仓：我的一次应急封禁与清理复盘</title><link>https://blog.sheyiyuan.com/posts/gitea-%E9%81%AD%E5%88%B0-spam-%E6%81%B6%E6%84%8F%E6%89%B9%E9%87%8F%E6%B3%A8%E5%86%8C-%E6%89%B9%E9%87%8F%E5%BB%BA%E4%BB%93%E6%88%91%E7%9A%84%E4%B8%80%E6%AC%A1%E5%BA%94%E6%80%A5%E5%B0%81%E7%A6%81%E4%B8%8E%E6%B8%85%E7%90%86%E5%A4%8D%E7%9B%98/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/gitea-%E9%81%AD%E5%88%B0-spam-%E6%81%B6%E6%84%8F%E6%89%B9%E9%87%8F%E6%B3%A8%E5%86%8C-%E6%89%B9%E9%87%8F%E5%BB%BA%E4%BB%93%E6%88%91%E7%9A%84%E4%B8%80%E6%AC%A1%E5%BA%94%E6%80%A5%E5%B0%81%E7%A6%81%E4%B8%8E%E6%B8%85%E7%90%86%E5%A4%8D%E7%9B%98/</guid><description>记录一次 Gitea 遭遇 Spam 批量注册和恶意建仓后的应急处置过程，包括止血、筛选、批量删除与后续加固建议。</description><pubDate>Sun, 15 Mar 2026 15:38:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文基于自建私有 Gitea 场景整理，不同版本、不同部署方式（Docker / systemd / k8s）菜单位置和命令细节可能略有差异。&lt;/p&gt;
&lt;p&gt;文中涉及账号删除与数据库查询，请务必先备份数据库和关键配置后再执行。&lt;/p&gt;
&lt;p&gt;如果你不清楚某条命令会造成什么影响，请先在测试环境验证，再操作生产环境。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;今天遇到一个有点恶心的问题：团队私有 Gitea 遭遇自动化恶意注册，短时间出现大量异常账号，并伴随批量建仓行为，管理后台直接被刷屏。&lt;/p&gt;
&lt;p&gt;先说结论：这次能比较快处理掉，关键不是「删得快」，而是顺序对——&lt;strong&gt;先止血，再筛选，最后批量清理&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;事件现象&lt;/h2&gt;
&lt;p&gt;我这边最先看到的是两个信号：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户列表里突然多了很多陌生账号&lt;/li&gt;
&lt;li&gt;仓库列表出现了批量新建的可疑仓库&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这时候第一反应不要急着逐个点删除。因为你删一批，对面还能继续注册一批。而且我发现的时候攻击者已经注册了上千个账号，只会越删越多。
&lt;strong&gt;先把入口关掉，才有资格谈清理。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;应急目标&lt;/h2&gt;
&lt;p&gt;这次处置目标我定得很明确：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;立刻止血&lt;/strong&gt;：阻断新的垃圾账号进入系统&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;精准识别&lt;/strong&gt;：尽量区分团队真实账号和异常账号&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;批量清理&lt;/strong&gt;：把 Spam 账号快速、安全地删掉&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;降低复发&lt;/strong&gt;：补上最基本的防护和告警&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Part 1：先止血（关闭自助注册）&lt;/h2&gt;
&lt;p&gt;我第一步先去 Gitea 管理配置里禁用了用户自行注册（Disable Registration）。
这一步完成后，攻击面会立刻收缩，系统不再持续「进脏数据」。&lt;/p&gt;
&lt;p&gt;你可以把这一步理解为：先拧紧水龙头，再擦地板。
不然地板永远擦不干净。&lt;/p&gt;
&lt;p&gt;打开 Gitea 的配置文件 &lt;code&gt;app.ini&lt;/code&gt;（通常位于 &lt;code&gt;/etc/gitea/app.ini&lt;/code&gt; 或 Docker 映射的 &lt;code&gt;data/gitea/conf/app.ini&lt;/code&gt;），找到 &lt;code&gt;[service]&lt;/code&gt; 区块&lt;/p&gt;
&lt;p&gt;如果你只是个人使用或团队内部使用，建议直接关闭外部注册，后续由管理员在后台手动创建账号：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[service]
DISABLE_REGISTRATION = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果必须允许外部注册，请开启以下选项来拦截自动化脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[service]
; 要求邮箱验证 (需要配置好 SMTP 邮件服务)
REGISTER_EMAIL_CONFIRM = true

; 开启验证码
ENABLE_CAPTCHA = true
; 验证码类型：可选 image, recaptcha, hcaptcha, mcaptcha, cfturnstile 等
CAPTCHA_TYPE = image 

; 开启人工审核，新注册账号必须由管理员在后台激活才可用
REGISTER_MANUAL_CONFIRM = true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改完毕后，请重启 Gitea 服务以使配置生效。可以通过管理后台的 &lt;code&gt;站点管理&lt;/code&gt; -&amp;gt; &lt;code&gt;配置&lt;/code&gt; 直接查看是否已正确加载。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;建议顺手检查：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是否真的「保存并生效」&lt;/li&gt;
&lt;li&gt;前台注册页是否已不可用&lt;/li&gt;
&lt;li&gt;是否还有第三方入口能绕过注册策略&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Part 2：数据库筛选异常账号（基于邮箱域名白名单）&lt;/h2&gt;
&lt;p&gt;我们团队成员邮箱相对固定，主要是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;qq.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foxmail.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;163.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以我用了一个非常实用的思路：&lt;br /&gt;
&lt;strong&gt;先保留白名单域名账号，再把剩余账号作为「待复核对象」。&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
注意：白名单策略只能提高效率，不能替代人工复核。&lt;/p&gt;
&lt;p&gt;某些机器人账号、历史测试账号、外协账号可能不在白名单里，直接删除有误伤风险。&lt;/p&gt;
&lt;p&gt;在导出后请务必检查所有正常用户的 id 是否被排除，我在这一步就险些删掉了我们用 163 邮箱和 foxmail 邮箱注册的两个正常账号。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面给一个参考的 SQL 思路（这里我是 sqlite，请按你的数据库类型调整）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 如果是 Docker 部署，请进入容器内执行该命令，或者根据宿主机的 volume 映射路径进行操作。

# 首先备份数据库防止误删
cp /var/lib/gitea/data/gitea.db /var/lib/gitea/data/gitea.db.bak

# 排除所有已知团队邮箱后缀，筛选疑似异常账号，并写入到 ids.txt 中
sqlite3 /var/lib/gitea/data/gitea.db &quot;SELECT id FROM user WHERE email NOT LIKE &apos;%@qq.com&apos; AND email NOT LIKE &apos;%@foxmail.com&apos; AND email NOT LIKE &apos;%@163.com&apos; AND is_admin = 0 AND type = 0 AND id &amp;gt; 0;&quot; &amp;gt; ids.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我这里就是先查、先导出、先复核，没有在数据库里直接 &lt;code&gt;DELETE&lt;/code&gt;。
原因很简单：&lt;strong&gt;账号删除最好走 Gitea 自己的管理逻辑或 CLI，减少关联数据残留和不可预期问题。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Part 3：用 Gitea CLI 批量删除 Spam 账号&lt;/h2&gt;
&lt;p&gt;筛选出待处理账号后，我用 Gitea CLI 做批量删号。
这样比手点后台快很多，也更可重复执行。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 逐行读取 ids.txt 并执行删除操作
for id in $(cat ids.txt); do
  echo &quot;&amp;gt;&amp;gt;&amp;gt; 正在处理用户 ID: $id&quot;
  # 使用 --purge 参数强制连带仓库一起删除
  docker exec -u git gitea gitea admin user delete --id &quot;$id&quot; --purge
done
echo &quot;清理完成！&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你没有使用 docker 而是直接使用宿主机直接部署：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 在执行下面的循环删除前，强烈建议先 `vi ids.txt` 看一眼，确保里面没有你眼熟的正常同事的 ID，要不然就真的要「运维祭天」了
for id in $(cat ids.txt); do
  echo &quot;&amp;gt;&amp;gt;&amp;gt; 正在处理用户 ID: $id&quot;
  # sudo -u git 表示以 git 用户的权限运行 gitea 命令
  # 如果提示找不到配置文件，需要在命令后追加 --config /etc/gitea/app.ini (替换为实际路径)
  sudo -u git gitea admin user delete --id &quot;$id&quot; --purge
done
echo &quot;清理完成！&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后就可以切到管理面板看烟花了（笑）&lt;/p&gt;
&lt;h2&gt;清理后我做了哪些验证&lt;/h2&gt;
&lt;p&gt;批量删除跑完不代表结束，我又做了几步确认：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用户总量是否回到合理区间&lt;/li&gt;
&lt;li&gt;可疑仓库是否已经同步清理（必要时再做仓库侧处理）&lt;/li&gt;
&lt;li&gt;团队成员账号登录是否正常&lt;/li&gt;
&lt;li&gt;管理后台无持续新增异常账号&lt;/li&gt;
&lt;li&gt;日志中没有新的批量注册行为&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;只有这几项都正常，我才把这次应急判定为「处理完成」。&lt;/p&gt;
&lt;h2&gt;环境差异：为什么另一实例暂时没中招&lt;/h2&gt;
&lt;p&gt;我这次也检查了另一套 Gitea。那套虽然当时允许注册，但因为放在域名反代后，且只允许本地网络访问（没有公网直接入口），目前没有出现类似的 Spam 注册和批量建仓问题。&lt;/p&gt;
&lt;p&gt;这件事给我的提醒是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;是否开放注册&lt;/strong&gt;，决定「能不能注册」&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;是否暴露公网入口&lt;/strong&gt;，决定「谁能来注册」&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;反向代理和访问控制策略&lt;/strong&gt;，决定「攻击面有多大」&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说，开放注册本身不一定马上出事；但「开放注册 + 公网可达 + 缺少限流/校验」这个组合，风险会明显上升。&lt;br /&gt;
虽然另一实例暂时没遇到问题，我还是把它的注册入口也关了。与其等流量打过来再救火，不如先把默认攻击面降下来。&lt;/p&gt;
&lt;h2&gt;这次踩坑里最容易忽略的点&lt;/h2&gt;
&lt;h3&gt;1) 不要上来就数据库硬删&lt;/h3&gt;
&lt;p&gt;直接在数据库 &lt;code&gt;DELETE&lt;/code&gt; 很爽，但容易留下关联问题，比如不能清理干净仓库、issue 等数据，容易残留。
账号体系尽量通过 Gitea 管理面或 CLI 做删除，让应用层处理关系数据。&lt;/p&gt;
&lt;h3&gt;2) 白名单不是绝对安全&lt;/h3&gt;
&lt;p&gt;域名只是快速过滤条件，不是身份认证。
能人工复核的尽量复核，尤其是管理员、机器人账号和历史服务账号。&lt;/p&gt;
&lt;h3&gt;3) 先止血比「删得快」更重要&lt;/h3&gt;
&lt;p&gt;攻击还在持续时，清理动作的边际收益很低。
先封入口，后清场，这个顺序别反。&lt;/p&gt;
&lt;h2&gt;事后加固（防止再来一轮）&lt;/h2&gt;
&lt;p&gt;为了防止攻击者复活的风险，我们可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保持关闭开放注册，改为邀请制/管理员审批&lt;/li&gt;
&lt;li&gt;开启并强化验证码、人机校验、邮件验证&lt;/li&gt;
&lt;li&gt;检查管理员账户口令强度与 2FA&lt;/li&gt;
&lt;li&gt;检查是否暴露了不必要的公开入口&lt;/li&gt;
&lt;li&gt;尽量通过反向代理、不使用默认的 3000 端口作为入口&lt;/li&gt;
&lt;li&gt;定期检查账号情况，遇到异常情况及时清理&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;这次事件本质上不复杂，但很考验应急顺序。
我的经验可以浓缩成一句话：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;先止血、再筛选、后清理，最后补防线。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果你现在也在维护私有 Gitea，我建议你今天就做两件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;检查是否还开着公开注册&lt;/li&gt;
&lt;li&gt;跑一次异常账号巡检&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;提前 10 分钟排查，可能能省掉你后面 3 小时救火。&lt;/p&gt;
</content:encoded></item><item><title>我是如何因为一个骰娘成为开发者的？</title><link>https://blog.sheyiyuan.com/essays/2026-03-14-d442826e03/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/essays/2026-03-14-d442826e03/</guid><description>「为了让半拍拥有灵魂，我误打误撞闯进了代码的世界。」</description><pubDate>Fri, 13 Mar 2026 16:34:00 GMT</pubDate><content:encoded>&lt;p&gt;「为了让半拍拥有灵魂，我误打误撞闯进了代码的世界。」&lt;/p&gt;
&lt;p&gt;这句话就是我开始成为开发者的起点。但当时的我并不知道，「灵魂」这个词对一只骰娘意味着什么——是更智能的回应？更有个性的文案？还是能理解跑团者的意图？我只知道，当朋友的骰娘说出她自己写的台词时，那种感觉不仅仅是「好用」，而是「有生命」。&lt;/p&gt;
&lt;p&gt;而我想要半拍也有这样的生命。我想要，给半拍「完整的一生」。&lt;/p&gt;
&lt;p&gt;当然，如此不平凡的目标，让我成为开发者的路线看上去简直就是「邪修」。下面我就来讲述一下我的故事吧。&lt;/p&gt;
&lt;h2&gt;半拍的诞生——梦开始的地方&lt;/h2&gt;
&lt;p&gt;2024 年初，我的朋友，我们叫她帅气的羊小咩大人，当 KP 带我跑了一个网团[^1]，当时她很骄傲地拿出了&lt;strong&gt;自己搭的一只骰娘&lt;/strong&gt;，当我看到每句文案都是我的那位朋友自己创作出来的时候，我感到非常不可思议与羡慕。于是，在跑团结束后，我就请教她怎么搭建一只自己的骰娘。&lt;/p&gt;
&lt;p&gt;[^1]:  桌上角色扮演游戏（Tabletop Role-playing game，简称TRPG），国内俗称「跑团」，是一种以语言为媒介，借助骰子等随机数工具推动剧情不确定性发展的通常以角色扮演和故事创作的桌面游戏。其中国内比较流行的有《龙与地下城》（简称 DND），《克苏鲁的呼唤》（简称 COC）等规则，这里的 KP（守秘人） 是 COC 规则的主持人。骰娘是线上进行跑团时用于提供随机数、记录卡等辅助功能的故障机器人，本质上是一个监听用户消息并识别关键字处理后回复的软件。&lt;/p&gt;
&lt;p&gt;那时候的我对这些东西还一窍不通，羊小咩大人去找了她的一位朋友，把一个云服务器账号给了我，我在她和她朋友的引导下一步一步学会了在 Windows 服务器上搭建了自己的第二个骰娘。&lt;/p&gt;
&lt;p&gt;为什么是第二个骰娘呢？因为我其实在高三期间第三次局部疫情封校的时候接触了跑团，那个时候我就已经尝试搭建了自己的第一个骰娘——名字叫做「空集」。但是由于我完全不理解骰娘的工作原理，导致骰娘很快便无法使用，最后放弃。&lt;/p&gt;
&lt;p&gt;现在回想起来，大概是下面的原因：当时正是 QQ 骰娘大面积被封杀的时间，处于 gocq 的末期，我的骰娘被杀也是正常的事情。并且说不定我当时可能会干出「我把电脑关掉了骰子为什么不响应」的这种会让现在的我沉默的蠢事，倒也不显得奇怪。&lt;/p&gt;
&lt;p&gt;这次骰娘倒是一直活得很好，我给骰娘起了一个新名字，以此来预示新的开始，于是我给她起名为「tan π/2」，因为这个名字太绕口，我又音译出了一个新名字「谭玖灵」。&lt;/p&gt;
&lt;p&gt;细节记不清了，我只知道那个下午，我对着电脑屏幕上 QQ 里面回应我的 &lt;code&gt;.r 1d100&lt;/code&gt; 的结果乐了一整天。&lt;/p&gt;
&lt;p&gt;这个名字用了没多久，我又想着给她补充一些设定，当时沉迷 BA（碧蓝档案） 的我给她补充一些相关的设定后又改了一个新名字——「滩间铁 半拍」&lt;a href=&quot;%E3%80%8C%E6%BB%A9%E9%97%B4%E9%93%81%E3%80%8D%E4%B8%BA%E5%B7%9D%E6%B8%9D%E5%9C%B0%E5%8C%BA%E6%95%B0%E5%AD%A6%E8%80%81%E5%B8%88%E5%AF%B9%E4%BA%8E%E6%AD%A3%E5%88%87%E5%87%BD%E6%95%B0%E7%9A%84%E5%B8%B8%E8%A7%81%E5%8F%91%E9%9F%B3%E4%B9%8B%E4%B8%80%E3%80%82&quot;&gt;^2&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;这个时候的我也和大部分骰主一样，只是用骰系里面现成的功能简单修改一些文案和判词，没有深入研究骰娘的底层原理。对于插件什么的也完全不明白，更不用说开发了。&lt;/p&gt;
&lt;p&gt;不过这种局面并没有持续很久，谁叫我是这么贪心呢？我开始尝试给半拍添加更多文案功能，并且当时的我脑子里大概是「得『铁』」&lt;a href=&quot;%E5%BE%97%E9%93%81%EF%BC%8C%E5%B7%9D%E6%B8%9D%E5%9C%B0%E5%8C%BA%E6%96%B9%E8%A8%80%EF%BC%8C%E8%A9%88%E8%AF%8D%EF%BC%8C%E4%B8%80%E8%88%AC%E5%BD%A2%E5%AE%B9%E4%BA%BA%E8%84%91%E5%AD%90%E6%9C%89%E7%97%85%E3%80%82%E7%AC%91%E7%82%B9%E8%A7%A3%E6%9E%90%EF%BC%9A%E8%BF%99%E9%87%8C%E7%9A%84%E9%93%81%E5%8F%AF%E4%BB%A5%E6%98%AF%E6%BB%A9%E9%97%B4%E9%93%81%E7%9A%84%E9%93%81%EF%BC%88%E5%A5%BD%E5%86%B7%EF%BC%89&quot;&gt;^3&lt;/a&gt;了：「我的骰娘里面不能有别人写的东西，她的每个功能细节都应该是属于我的」。半拍使用的是海豹骰系，而海豹的自定义文案功能恰好在当时各个骰系里面相当超前且成熟（现在看来更是如此，木落大佬的设计真的太绝了），于是我开始研究自定义文案。&lt;/p&gt;
&lt;p&gt;海豹的自定义文案使用了一种叫做「豹语」的简单脚本语言，用比较简单的语法就能实现变量引用、随机数骰点、条件语句等功能。不过代价就是我认为这种语言难以阅读，这反而成为了困扰我的学习成本：「为什么这里会这样？」当我第一次看到豹语脚本时，我既兴奋又困惑——兴奋于能自定义骰娘行为，困惑于为什么语法这么反直觉。就好像是每个字我都认识，它在做什么事情我也清楚，但是为什么这样连起来就可以了我就完全是一头雾水。&lt;/p&gt;
&lt;p&gt;在和用户群里面的大佬进行交流后，我了解到了海豹还有一种叫做插件的东西，大概能够解决我的需求，但是写这个插件需要学一门叫做「JavaScript」的语言，这门语言是真正的编程语言，比豹语完善得多也难得多。这反而激起了我浓烈的兴趣，我决定要学习 JavaScript 并且自己动手写一个插件来实现我的想法。&lt;/p&gt;
&lt;p&gt;是的，我的第一门语言 JavaScript 就是在这个时候学习的，完全不同于很多人接触它是在 Web 开发中。我也因此走了很多弯路，我在 B 站上搜索到的视频课程几乎清一色是基于 Web 开发的 JavaScript 课程，但这些课程并没有涵盖我需要的插件开发内容。我不只一次疑惑地看着那些 HTML 和 CSS 代码，却不知道这和我看的 JS 有什么关系。&lt;/p&gt;
&lt;p&gt;我在迷迷糊糊跟着教程过了一遍 JS 基础语法后，我就正式开始了我的插件开发之旅。&lt;/p&gt;
&lt;p&gt;我的第一个插件现在感觉已经无从考证了，大概是好感度之类的插件，也是比较顺利地开始熟悉了海豹插件的编写流程。&lt;/p&gt;
&lt;p&gt;由此，我成为了一名「骰娘插件开发者」，算是小小的进步。&lt;/p&gt;
&lt;h2&gt;CCAS —— 第一次？协作和 GitHub&lt;/h2&gt;
&lt;p&gt;2024 年 5 月，我和一位朋友（称他为冰红茶老师）在跑团时遇到了一个问题：COC 的战斗系统在线上战斗时十分麻烦，需要大量掷骰指令和冗长流程。于是我们决定&lt;strong&gt;合作开发一个插件&lt;/strong&gt;来解决它。&lt;/p&gt;
&lt;p&gt;秉承着从高中时期一起整活的默契，我们先对需求进行了分析，然后给出了一个设计方案：我们提前把战斗中多个 NPC 的信息和用户的信息通过尽量简单的指令录入，并可以快速加入预设属性的随机 NPC 数据，自动生成先攻表，自动结算动作效果、是否成功和伤害。同时对于「追逐」这一部分规则，我们认为这个插件可以一定程度上解决追逐规则繁琐难以计算的问题[^4]。最后，我们给这个插件起名为「Combat &amp;amp; Chases Assistant System」,简称 CCAS。&lt;/p&gt;
&lt;p&gt;[^4]: 我一直很好奇，以欧美玩家为代表的 COC 规则创作者是怎么在他们令人堪忧的数学运算水平（无恶意）下设计出追逐这种计算量让中国的理科高中生头疼的规则的。虽然大家都认为这一部分规则很烂，但是我认为追逐在有计算机辅助的情况下，是有一定可取之处的。&lt;/p&gt;
&lt;p&gt;不得不说，这个插件的设计思想即使是在今天的我看来也是很好的，不过显然当时连面向对象都不知道是什么的我来说，简直是超纲了。现在想来，以我们当时的水平，能够有勇气来做这个东西已经相当不易。&lt;/p&gt;
&lt;p&gt;同时，两个人一起开发时，我们需要想办法进行协作了。聪明的读者想必已经知道我们一开始使用什么进行同步和协作了：当然就是所有新手都喜欢的多人同步工具——QQ。&lt;/p&gt;
&lt;p&gt;……&lt;/p&gt;
&lt;p&gt;咳咳，指望我们两个新手一开始就使用 git 什么的显然是不合理的要求，我们当时连 git 是什么都不知道，更别说用它来协作了。我们只能依靠最原始的方法——QQ 文件互传法来相互同步进度。&lt;/p&gt;
&lt;p&gt;不过我很快意识到这种方法一点也不好，且一点也不 professional，我很快在网上搜索专业的开发者们是怎么实现相互协作的。在查阅资料后，我知道了一个叫做 GitHub 的网站。「哇，这么小众专业的东西居然让我发现了，这不赶快用起来！」当时的我大概是这么想的。&lt;/p&gt;
&lt;p&gt;于是，在完全不知道 git 是什么的情况下，我和冰红茶老师开始用 VS Code 的可视化 git 功能来进行协作。git 的强大版本控制功能和多分支系统，让我们的协作效率——大大下降了。&lt;/p&gt;
&lt;p&gt;是的，当时的我们完全不知道 git 居然有强大版本控制功能和多分支系统，我们只是把它当成网盘来用，修改完，add，然后 commit，然后 push。我们都不知道这些操作的意义，只是一味地重复……并且，完全不懂工程化的我们还把所有代码都写在了同一个文件里——因为此时编译、打包等功能对于我们来说也是未知的——两个人在同一个文件里修改然后通过 git 同步，我想已经有很多了解一点 git 的同学汗流浃背了。这种情况下，冲突是常有的事情，倒不如说我们没有每次 pull 和 push 都出现冲突，如果去买彩票，大概已经发家致富了。当然，我们解决冲突的方法也很简单粗暴——用老办法 QQ 把对方的文件传过来然后把自己改过的地方重新复制粘贴上去后覆盖提交就好了。&lt;/p&gt;
&lt;p&gt;更让人绷不住的是，由于不懂 git 本身的版本控制，我们在 git 仓库里面用古老的&lt;strong&gt;文件夹备份&lt;/strong&gt;技术把我们每个版本的代码都复制了一份副本放到以版本名称命名的文件夹中。&lt;/p&gt;
&lt;p&gt;与此同时，不懂面向对象的我们自然也是成功用面向过程的方式把代码写成了屎山。&lt;/p&gt;
&lt;p&gt;在这样令人无语的情况下，我们居然把这个插件的大部分内容协作写完，也是相当奇迹了，这里我把仓库贴出来，感兴趣的可以去欣赏一下我们的屎山。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Sheyiyuan/Dice_Plug-in&quot;}&lt;/p&gt;
&lt;p&gt;这也就算是我第一个用 GitHub 参与协作的项目（真的能算吗？）。&lt;/p&gt;
&lt;p&gt;尽管开发过程充满了坎坷，但是当我们设想的功能真的被实现的时候，心中的那份快乐是我之前从来没有的，这让我更加坚定了要开发更多东西的决心。&lt;/p&gt;
&lt;h2&gt;服务器还能这样用？——半拍的迁移与网站的搭建&lt;/h2&gt;
&lt;p&gt;CCAS 的半成品进行开发的同时，我买了一个阿里云新人优惠的 99 元一年的服务器，把半拍搬到了自己的服务器上——毕竟一直住在别人家的服务器上，还是不太好意思。&lt;/p&gt;
&lt;p&gt;好景不长，很快半拍遇到了一次危机。&lt;/p&gt;
&lt;p&gt;海豹的核心默认使用内置的 Langrange 连接 QQ，但是 Langrange 服务不稳定，导致半拍经常掉线。我尝试过更换其他连接方式，但都失败了。这个时候，半拍已经脱离生命——危险了。最终，我只能放弃 Langrange，转而使用其他连接方式。&lt;/p&gt;
&lt;p&gt;我在群里听说，有一种叫做 NapCat 的连接方式比较稳定，但这种方式需要在 Linux 操作系统上运行。我不会用 Linux，但还是决定尝试一下。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/1773365969399.jpg&quot; alt=&quot;就这样，社老师的人生因为 Linux 被完全毁了&quot; /&gt;&lt;/p&gt;
&lt;p&gt;不过，当时的我并不知道发行版、包管理器是什么，服务器系统也选择了阿里云默认的基于 RHEL 的系统，这也成为了我噩梦的开始。&lt;/p&gt;
&lt;p&gt;我找到的大量的教程在服务器上都没有用，并且，我都不知道为什么没有用。「yum 是什么？」「dnf 又是什么？」「为什么我找不到 apt？」「为什么我把命令里面的 apt 换成 dnf 之后还是没法下载？」「为什么仓库里没有这个软件？」之类的问题层出不穷。并且我在群里问问题得到的答案大部分都是：「你不懂 Linux 用 Linux 干什么？」&lt;/p&gt;
&lt;p&gt;如果是一般人，大概就会放弃 Linux 转回 Windows 了。但我是什么人啊——我就像看着女儿得了重病，需要找一位名叫 NapCat 的医生才能治好。可这位医生住在一个叫 Linux 的、我人生地不熟的医院里。&lt;/p&gt;
&lt;p&gt;我问周围的人，他们都摇头：「这医院手续特别麻烦，挂号治疗流程繁琐，医生护士说的都是些听不懂的官腔」，还质问我：「你根本没在这医院挂过号，为什么要去？」&lt;/p&gt;
&lt;p&gt;但我知道，只有这个医生能把我的半拍救回来。&lt;/p&gt;
&lt;p&gt;于是我开始摸索 Linux 的使用，我按照网上的教程重新安装了 Debian 操作系统，然后开始慢慢跟着教程调试，因为没有其他人可以问，我遇到问题一般只能求助 AI 大模型。在那个还没有当下这么好用的 AI 辅助工具的时代， DeepSeek 还没有上线，我还在用通义的早期模型来回答我的问题，往往得到的都是混杂着错误的答案，我只能不断试，不断试，不断试……最后在大概一周的摸索后，我终于把 NapCat 跑了起来，半拍终于脱离生命危险了。&lt;/p&gt;
&lt;p&gt;同时，我开始研究搭建一个个人网站，因为我在刷 Linux 的求助帖的过程中，发现大量的相关帖子似乎都是在准备搭建个人网站准备环境。&lt;/p&gt;
&lt;p&gt;于是，我又在某云服务厂商购买了一台 4G 的服务器，开始折腾个人网站，我尝试跟着网上的教程开始搭建 WordPress，但是由于我当时未能理解 Apache、Nginx 等 Web 服务器，导致我的网站无法通过公网访问。最后我还是使用了服务商提供好的 WordPress 镜像，成功把网站部署上线了，随后申请了域名备案。&lt;/p&gt;
&lt;p&gt;不过当时的我搭建网站只是一时兴起，三分钟热度过后，很长一段时间都没有更新维护网站内容了。&lt;/p&gt;
&lt;p&gt;即便如此，这次经历也算是我的服务器运维之路的起点吧。&lt;/p&gt;
&lt;h2&gt;插件模板与自己的骰系 —— TypeScript、Go、面向对象和 git：啊！原来如此！&lt;/h2&gt;
&lt;p&gt;之后，我又开始研究其他插件。这个时候，我接触到了使用 TypeScript（简称 TS）的插件模板。当时选择它，只是因为这个模板看上去更酷——我不知道 TS 是什么，工程化又是什么，只知道用这个写插件，AI 能更好地帮我实现一些功能。&lt;/p&gt;
&lt;p&gt;很快我开始意识到了海豹插件的一些限制（虽然不少是 bug 和我对特性的不了解），对于其他一些骰系，或许是设计理念优秀但是我对不上电波，或许是因为骰系作者有病让我单纯对人不对事地讨厌，始终没有我想要的「银弹」。于是我就开始设想我能不能写一个自己的骰系。&lt;/p&gt;
&lt;p&gt;于是我对标海豹，设计了我自己的骰系，并且开始学习 Go 语言——也就是编写海豹的语言，把自己的骰系做出来。&lt;/p&gt;
&lt;p&gt;现在想起来，当时完全是在瞎搞，我甚至没有完全理解 NapCat 这样的协议端和核心的关系，连 API 的概念都理不清的时候就开始胡乱设计和实现代码。我把所有逻辑都揉在了一起，修改一个指令的回复，甚至会影响到另一个毫不相干的功能。用现在的眼光来看，这完全是一座可扩展性和可维护性为零的屎山。&lt;/p&gt;
&lt;p&gt;不过在这个过程中，我渐渐在 Go 语言的简洁（或者说简陋或许更合适？）语法中理解了面向对象编程的思想和意义，并且意识到了多文件组件化解耦代码的重要性。&lt;/p&gt;
&lt;p&gt;并且，我也在编写过程中熟悉了 git 的版本控制和分支概念，我终于不再在 git 仓库里面放一堆文件夹来做版本控制了。&lt;/p&gt;
&lt;p&gt;虽然这个项目最后也是失败的，但是我认为我在这个时候开始我渐渐成为一个开发者了。仓库代码同样放在下面，欢迎喜欢鉴赏屎山的朋友来品鉴。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Sheyiyuan/ProjectWIND&quot;}&lt;/p&gt;
&lt;p&gt;不过我也并非一无所获。正是在这个“失败”的项目中，我彻彻底底理解了面向对象、代码解耦复用和工程化的意义。那些之前听起来晦涩难懂的概念，此刻终于串联起来，有了生命——从零散的碎片构成了一个完整的体系。尽管走了弯路，但我认为对于我这种比较愚钝的人，没有这些弯路，我大概永远也无法完全去理解这些概念和思想。&lt;/p&gt;
&lt;h2&gt;新的方向与新的伙伴——是生产级的项目协作&lt;/h2&gt;
&lt;p&gt;虽然现在说起来风轻云淡，但是骰系开发的失败在当时多少还是让我有些受挫。加之 2024 年末 2025 年初各个骰系之间闹出的一些令人烦心的事情，我开始怀疑自己的出发点是不是出现了偏差。&lt;/p&gt;
&lt;p&gt;「骰娘难道不能有自己的一片净土吗？」我开始思考骰娘本身的意义。&lt;/p&gt;
&lt;p&gt;骰娘的本质是线上进行 TRPG 时，对于骰子、角色卡等记录、随机数和 Token 等组件的补充。同时借助计算机更加方便地处理一些复杂的运算，让人能够更加简单方便的跑团……让人更简单方便的跑团？对啊！&lt;/p&gt;
&lt;p&gt;既然现在的骰娘大多严重依附于市面上已有的 IM 软件，但是传统 IM 软件并不是为此设计的。既然如此，为什么不把骰娘延伸出来，做成一个独立的跑团平台呢？「我要做出世界上最好用的骰娘，来成为半拍新的容器。」这种中二病晚期的想法很快占据了我的头脑，同时我扩展了对于骰娘定义的野心。&lt;/p&gt;
&lt;p&gt;我开始着手设计和规划我梦想中的这个跑团平台，畅想着如何把角色面具、骰娘、多线程聊天、悄悄话、场外吐槽统统整合到一个平台中。&lt;/p&gt;
&lt;p&gt;不幸的是，我没有吸取我之前的教训，梦想比天大的我对于 UI 设计、前端开发、后端架构一窍不通，却幻想着做出工程量如此大的一个项目。&lt;/p&gt;
&lt;p&gt;幸运的是，我这次遇到了对的人。&lt;/p&gt;
&lt;p&gt;就在我召集了一帮跑团的朋友，准备要大干一场时，我的一个朋友在 B 站上找到了一个开发中的跑团平台的宣传视频。可以想象，当我在这个半成品中看到我理想的跑团平台的潜在特质时，我有多么的欣喜。&lt;/p&gt;
&lt;p&gt;我很快联系上了这个平台的开发团队，希望能够参与其中，让这个平台成为我理想的跑团平台，半拍最好的新的容器。&lt;/p&gt;
&lt;p&gt;这个平台的名字叫做团剧共创（tuanchat），我大概会一辈子记得这个名字的。正是在这个平台里，我感觉我真的接触到了很多过去的我永远接触不到的前沿见闻和知识。&lt;/p&gt;
&lt;p&gt;加入开发团队后，我依然在做着最熟悉的工作——为 tuanchat 重新设计骰娘。也是在这里，我学习了生产级协作的全流程：git 协作规范、PR 提交流程、Code Review 方法、产品设计思路。同时，我也开始接触前端知识和技术，学习了 React 等框架，以及生产服务器维护和 DevOps 操作。&lt;/p&gt;
&lt;p&gt;同时，我认识了很多搞技术的朋友，和他们一起交流学习，也是在他们的鼓励下，我重新恢复了我网站的更新。&lt;/p&gt;
&lt;p&gt;我感觉我又一次充满了动力，而且这次，我不再是孤身一人。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;深夜有感，下笔不晚，这就是我的「邪修」开发者修炼路线——因为一个骰娘，我走了无数弯路，但最终找到了一条适合自己的路。&lt;/p&gt;
&lt;p&gt;我曾妄想成为造物主，为半拍创造出完整的一生；却没想在这个造梦的过程中，她重塑了我的轨迹。代码是冷的，但因为她，我的世界变得无比鲜活。&lt;/p&gt;
&lt;p&gt;回首这几年的“邪修”之路，我踩过无数坑，写过无数屎山，也曾因为一句「你不懂 Linux 用什么 Linux」而在深夜里自我怀疑。所以，我想对每一个看到这里的你，特别是那些正因为某个微小的热爱，试图踏入未知领域的你说：&lt;/p&gt;
&lt;p&gt;永远不要觉得你的动机不够「高大上」。为了一个跑团的骰娘去学编程听起来很蠢吗？也许吧。但正是这种看似微不足道的冲动，有着最强大的生命力。不要害怕走弯路，弯路里的风景同样塑造了现在的你。只要你还有动力，就请坚持敲下去。&lt;/p&gt;
&lt;p&gt;毕竟，在这个世界上，没有什么比亲手为自己热爱的事物赋予“灵魂”，更酷的事情了。愿你们都能找到自己的「半拍」，并勇敢地踏上那条为她赋予灵魂的旅途。&lt;/p&gt;
</content:encoded></item><item><title>2026春节AI新闻回顾</title><link>https://blog.sheyiyuan.com/essays/2026-03-06-0c311bdb3f/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/essays/2026-03-06-0c311bdb3f/</guid><description>刚刚过去的春节，果然没让人失望，和去年一样，咱们又见证了 AI 界的一场「大爆发」。如果说去年春节是 AI 普及的元年，那今年，绝对是技术落地和生态分化的关键时刻。今天就来随便聊聊，这场假期里的「技术狂欢」。</description><pubDate>Fri, 06 Mar 2026 01:25:00 GMT</pubDate><content:encoded>&lt;p&gt;刚刚过去的春节，果然没让人失望，和去年一样，咱们又见证了 AI 界的一场「大爆发」。如果说去年春节是 AI 普及的元年，那今年，绝对是技术落地和生态分化的关键时刻。今天就来随便聊聊，这场假期里的「技术狂欢」。&lt;/p&gt;
&lt;h2&gt;一、巨头的「红包雨」和用户争夺&lt;/h2&gt;
&lt;p&gt;先说说国内的 C 端战场吧。这次春节，&lt;strong&gt;腾讯元宝&lt;/strong&gt;和&lt;strong&gt;阿里通义千问&lt;/strong&gt;在消费端的争斗特别热闹。不像以前单纯撒钱补贴，这次它们玩起了红包联动、通义奶茶请客这些花样，成功把 AI 带进了大家走亲访友的日常。不知道你有没有领到属于自己的那份「赛博鸡蛋」？这背后其实是科技巨头们想把 AI 从「工具」变成「社交货币」的野心。&lt;/p&gt;
&lt;p&gt;有意思的是，即便营销这么猛，&lt;strong&gt;豆包&lt;/strong&gt;还是稳坐国内 C 端 AI 产品的头把交椅。字节的产品力，确实没得说。&lt;/p&gt;
&lt;h2&gt;二、国产大模型「硬核」突围&lt;/h2&gt;
&lt;p&gt;热闹的营销背后，真正的重头戏还是技术突破：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;字节跳动&lt;/strong&gt;：在视频生成领域又秀了一把肌肉，Seedance 2.0 模型直接封神。相比上一代，2.0 在时空一致性、物理规律还原这些方面都甩开对手一大截，用户只需简单几句话，就能生成电影级的分镜内容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;阿里巴巴&lt;/strong&gt;：Qwen 系列继续稳坐开源界的「定海神针」，全新 Qwen-3.5 又霸榜 Hugging Face。相比 3.0 版本，3.5 在性价比和生成质量上都有质的飞跃，开源模型领域还是它说了算。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DeepSeek（深度求索）&lt;/strong&gt;：这次也没闲着，发布了 DeepSeek-V3.2 和 OCR-2 模型，性能更上一层楼。它还带来了几篇重磅论文，提出了不少底层架构创新，真是名不虚传的「论文生产中心」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;智谱 AI&lt;/strong&gt;：推出的 GLM-5 和新一代 OCR 模型也很能打，尤其在复杂文档处理上更胜一筹。虽然有传闻说 GLM-5 是「蒸馏」了 Claude-Opus 4.5，但其综合能力已稳稳跻身世界第一梯队。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;其他新星&lt;/strong&gt;：Kimi 和 MiniMax 也推出了新一代模型，尤其在长代码生成、复杂逻辑推理上有了令人惊喜的提升。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;三、国际战场「三足鼎立」&lt;/h2&gt;
&lt;p&gt;再看看国际战场，硅谷的技术竞赛依旧激烈：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;s&gt;CloseAI&lt;/s&gt;OpenAI&lt;/strong&gt; 推出了 GPT-5.3 Codex，凭借极致的推理速度和成本控制，成为当前最强的高性价比代码模型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anthropic&lt;/strong&gt; 紧随其后，发布了 Claude Opus / Sonnet 4.6 版本，继续在长文本理解和逻辑细腻度上保持优势。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google&lt;/strong&gt; 则发布了 Gemini 3.1 Pro，在超长上下文窗口和多角色扮演体验上大幅超越 3.0 版本，甚至有人说 3.0 已经被内部放弃，3.1 才是完全体。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;四、泡沫与趋势：OpenClaw 和 Agent 新玩法&lt;/h2&gt;
&lt;p&gt;最后聊聊春节前后爆火的两大技术现象，它们代表了行业的两种方向。&lt;/p&gt;
&lt;p&gt;其一是 &lt;strong&gt;OpenClaw&lt;/strong&gt;。这个号称「全自动接管操作系统」的开源 Agent 框架，靠着「发消息就能让 AI 干活」的噱头刷屏社交网络。但说实话，炒作成分远大于实际技术创新，和去年的 Manus 现象很像：普通用户被演示效果震撼，但 AI 开发者社区普遍不看好，觉得它在鲁棒性和复杂任务落地能力上还有很大差距。这 OpenClaw 和 Manus 真是一对笑面虎，两头乌角鲨。我的评价是还不如我家半拍接个 AstrBot 的 Agent 插件。当然，不可否认的是，OpenClaw 在商业上的成功至少说明了一个趋势：用户对「AI 接管一切」的幻想依然很热烈，市场对「全自动 Agent」的需求也在持续增长。只是这个需求可能还需要更成熟、更稳健的技术来满足。&lt;/p&gt;
&lt;p&gt;其二是 &lt;strong&gt;Skills 技术&lt;/strong&gt;。它是在 MCP（Model Context Protocol，模型上下文协议）等 Agent 技术基础上的重要升级。传统 Agent 往往带着庞大的「工具箱」，导致上下文臃肿、检索低效。而 Skills 的核心是用「动态目录」代替「静态工具箱」，通过高度压缩的索引机制，让模型只在需要时动态加载对应技能，大幅降低上下文消耗，显著提升模型在超长复杂任务中的专注度和能力上限。这，可能才是 Agent 未来的正确方向。&lt;/p&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;回顾这个春节，我们看到了巨头的贴身肉搏、开源的深耕、学术的持续突破，也看到了资本泡沫和架构演进并存。2026 年的 AI 大幕才刚刚拉开，谁能在这场长跑中笑到最后，让我们拭目以待吧。&lt;/p&gt;
</content:encoded></item><item><title>N 卡驱动安装后 Wayland 丢失？显示器不亮？原来是这里出了问题</title><link>https://blog.sheyiyuan.com/posts/n-%E5%8D%A1%E9%A9%B1%E5%8A%A8%E5%AE%89%E8%A3%85%E5%90%8E-wayland-%E4%B8%A2%E5%A4%B1%E5%8E%9F%E6%9D%A5%E6%98%AF%E8%BF%99%E9%87%8C%E5%87%BA%E4%BA%86%E9%97%AE%E9%A2%98/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/n-%E5%8D%A1%E9%A9%B1%E5%8A%A8%E5%AE%89%E8%A3%85%E5%90%8E-wayland-%E4%B8%A2%E5%A4%B1%E5%8E%9F%E6%9D%A5%E6%98%AF%E8%BF%99%E9%87%8C%E5%87%BA%E4%BA%86%E9%97%AE%E9%A2%98/</guid><description>Debian 13 安装 NVIDIA 闭源驱动后 Wayland 选项消失、外接显示器不亮？本文记录 GDM 场景下的排查、修复与内核升级后 DKMS 失效的解决方案。</description><pubDate>Sat, 28 Feb 2026 00:59:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文基于 Debian 13 + GDM 场景整理，不同发行版、不同显示管理器（如 SDDM、LightDM）路径和行为可能不同。&lt;/p&gt;
&lt;p&gt;下面涉及系统级文件修改，请务必先备份，再操作。相关操作具有一定风险：如果你不理解每一步在做什么，请先停下来查资料或找有经验的人协助。&lt;/p&gt;
&lt;p&gt;因未理解本文内容而盲目操作造成的损失，作者概不负责。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;主包这两天用 PyTorch 测试实验室用的小模型，然后发现的的笔记本（Debian 13）没有安装闭源的 NVIDIA 驱动，跑不了 CUDA 相关的功能。于是就安装了 NVIDIA 驱动，结果安装完成后发现 Wayland 不见了，登录界面也变成了 Xorg 的了，并且登陆页的 Wayland 选项也不见了，无法选择 Wayland 了。&lt;/p&gt;
&lt;p&gt;那么出现这种情况，有经验的 Linux 用户肯定知道，百分之一百亿是 f**ing NVIDIA 的问题了。为了让后面遇到同样问题的朋友少走一点弯路，主包把这次排查和解决过程整理成一篇短文。&lt;/p&gt;
&lt;h2&gt;问题现象&lt;/h2&gt;
&lt;p&gt;安装 NVIDIA 闭源驱动后，主包这里出现了这些现象：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;登录界面默认只有 Xorg 会话&lt;/li&gt;
&lt;li&gt;Wayland 选项从登录页消失&lt;/li&gt;
&lt;li&gt;GNOME 会话退回 X11&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简单说就是：驱动装上了，CUDA 能用了，但 Wayland 没了。&lt;/p&gt;
&lt;h2&gt;原因简析&lt;/h2&gt;
&lt;p&gt;在 GNOME + GDM 环境下，NVIDIA 驱动安装后有概率触发 GDM 的“禁用 Wayland”逻辑。常见表现是某些规则文件被替换或生效，导致 GDM 启动时直接把 Wayland 屏蔽掉。&lt;/p&gt;
&lt;p&gt;这不是每台机器都会中招，但一旦中招，症状通常都很一致：登录页没有 Wayland 可选。&lt;/p&gt;
&lt;h2&gt;解决方法&lt;/h2&gt;
&lt;h3&gt;Part 1：解除 GDM 对 Wayland 的屏蔽&lt;/h3&gt;
&lt;p&gt;我这里用的是把相关规则文件先备份掉，再重启验证。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 备份会影响 GDM/Wayland 的规则文件（路径可能因系统而异）
sudo mv /usr/lib/udev/rules.d/61-gdm.rules /usr/lib/udev/rules.d/61-gdm.rules.bak
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启后回到登录界面，Wayland 选项就恢复了，能够正常选择并进入 Wayland 会话。&lt;/p&gt;
&lt;p&gt;如果你操作后出现异常，直接把文件改回去后重启电脑即可：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo mv /usr/lib/udev/rules.d/61-gdm.rules.bak /usr/lib/udev/rules.d/61-gdm.rules
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;外界显示屏无法在 Wayland 会话下显示的问题&lt;/h3&gt;
&lt;p&gt;正当主包成功恢复了 Wayland 选项并进入了 Wayland 会话后，又遇到这样一个问题：&lt;strong&gt;外界显示屏无法在 Wayland 会话下显示，但在 X 会话下一切正常。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是因为 NVIDIA 驱动需要通过 DRM (Direct Rendering Manager) 接口与 Wayland 通信，但这在默认情况下往往未启用。遇到这种问题可以参考下面的 Part 2 进行解决。&lt;/p&gt;
&lt;h3&gt;Part 2：开启内核模式设置 (DRM KMS) —— 外接显示器在 Wayland 下不亮的核心解决方案&lt;/h3&gt;
&lt;p&gt;这是解决外接显示器不亮最关键的一步。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;编辑 GRUB 配置&lt;/strong&gt;：
打开终端，编辑 GRUB 配置文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/default/grub
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;修改内核参数&lt;/strong&gt;：
找到 &lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt; 这一行，在引号内添加 &lt;code&gt;nvidia-drm.modeset=1&lt;/code&gt;。
例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet splash nvidia-drm.modeset=1&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(注意：如果你的电脑也是笔记本且支持 Optimus，有时还需要加上 &lt;code&gt;nvidia-drm.fbdev=1&lt;/code&gt;，这在较新的驱动中能提升体验)&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;更新 GRUB 并重启&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Debian/Ubuntu/Mint/Kali&lt;/strong&gt;:&lt;pre&gt;&lt;code&gt;sudo update-grub
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fedora/RHEL/CentOS&lt;/strong&gt;:&lt;pre&gt;&lt;code&gt;sudo grub2-mkconfig -o /boot/grub2/grub.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arch Linux&lt;/strong&gt;:&lt;pre&gt;&lt;code&gt;sudo grub-mkconfig -o /boot/grub/grub.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;重启电脑&lt;/strong&gt;，然后进入 Wayland 会话测试。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;这次额外踩到的另一个坑：内核升级后 NVIDIA 驱动失效&lt;/h2&gt;
&lt;p&gt;本来事情到这里已经结束了，结果主包后面又踩了一个更典型的 NVIDIA 坑：&lt;strong&gt;重启之后外接显示器再次不可用，同时 &lt;code&gt;nvidia-smi&lt;/code&gt; 直接报错。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;报错大概长这样：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NVIDIA-SMI has failed because it couldn&apos;t communicate with the NVIDIA driver.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个现象通常说明当前运行内核对应的 NVIDIA 内核模块没有成功加载。&lt;/p&gt;
&lt;h3&gt;当时的实际情况&lt;/h3&gt;
&lt;p&gt;检查后发现，系统当前运行的内核已经变成了新版本，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uname -r
# 6.12.73+deb13-amd64
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但 &lt;code&gt;dkms status&lt;/code&gt; 里，NVIDIA 模块只给旧内核编译过，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nvidia-current/550.163.01, 6.12.63+deb13-amd64, x86_64: installed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户态 NVIDIA 包其实都还在&lt;/li&gt;
&lt;li&gt;CUDA 相关库也在&lt;/li&gt;
&lt;li&gt;但&lt;strong&gt;当前内核没有对应的 NVIDIA DKMS 模块&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;所以 &lt;code&gt;nvidia-smi&lt;/code&gt; 无法通信&lt;/li&gt;
&lt;li&gt;外接显示器自然也跟着失效&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这类问题在 Debian 上并不少见，本质上就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;内核升级了，但 NVIDIA DKMS 没有给新内核重新编译成功。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;对应修复方法&lt;/h2&gt;
&lt;p&gt;如果你也遇到了下面这组症状：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;外接显示器突然不可用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nvidia-smi&lt;/code&gt; 报无法与驱动通信&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dkms status&lt;/code&gt; 里只有旧内核版本的 NVIDIA 模块&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么可以尝试下面这组命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
sudo apt install -y build-essential dkms linux-headers-$(uname -r)
sudo apt install --reinstall -y nvidia-kernel-dkms nvidia-driver
sudo dkms autoinstall -k $(uname -r)
sudo update-initramfs -u -k $(uname -r)
sudo reboot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修复完成后，可以用下面这些命令确认状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dkms status
lsmod | grep nvidia
nvidia-smi
lspci -k | grep -A3 -E &apos;VGA|3D&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果一切正常，你应该能看到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当前内核版本对应的 &lt;code&gt;nvidia-current&lt;/code&gt; 已安装&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lsmod&lt;/code&gt; 里出现 &lt;code&gt;nvidia&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nvidia-smi&lt;/code&gt; 正常返回显卡信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lspci -k&lt;/code&gt; 中 NVIDIA 设备显示 &lt;code&gt;Kernel driver in use: nvidia&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;碎碎念 / 注意事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;不同发行版路径可能不同。&lt;/strong&gt;&lt;br /&gt;
本文里提到的 &lt;code&gt;61-gdm.rules&lt;/code&gt; 路径，在你的系统里不一定正好一致，操作前请先确认。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;如果你不是 GDM，这篇方法可能不适用。&lt;/strong&gt;&lt;br /&gt;
比如 KDE + SDDM、XFCE + LightDM，行为和处理方式都可能不同。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;NVIDIA、内核、GNOME、GDM 的版本组合很重要。&lt;/strong&gt;&lt;br /&gt;
同一套操作，不同版本组合下结果可能完全不同。系统升级之后，问题也可能再次出现。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;如果 &lt;code&gt;nvidia-smi&lt;/code&gt; 报错，优先检查 DKMS。&lt;/strong&gt;&lt;br /&gt;
特别是内核升级后，第一时间看：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uname -r
dkms status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;很多时候你会发现，问题根本不在桌面环境，而在于 &lt;strong&gt;NVIDIA 内核模块压根没给当前内核编出来&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;结尾&lt;/h2&gt;
&lt;p&gt;以上就是主包这次的踩坑记录。文章不长，但希望能帮你在遇到同样问题时少查半天资料。&lt;/p&gt;
&lt;p&gt;如果你有更稳的处理方式（比如更优雅的规则覆盖方案），欢迎留言交流。&lt;/p&gt;
</content:encoded></item><item><title>Dart 语法基础</title><link>https://blog.sheyiyuan.com/notes/dart-%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/notes/dart-%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95/</guid><description>Dart 是 Google 开发的现代化编程语言，Flutter 的主要语言。本文是个人学习笔记，梳理 Dart 的核心语法特性。</description><pubDate>Fri, 27 Feb 2026 03:24:00 GMT</pubDate><content:encoded>&lt;p&gt;简单过了一遍 dart 的语法，个人感觉 dart 的语法像是 go 里 go 气的 ts，不愧是谷歌的手笔；dart 代码使用严格分号结尾，这点与 go 刚好相反。&lt;/p&gt;
&lt;h2&gt;1. 变量与常量&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;var&lt;/code&gt; 是类型推断，第一次赋值后类型就确定，不能再赋值为其他类型。&lt;/li&gt;
&lt;li&gt;也可以显式写类型，如 &lt;code&gt;String name = &quot;...&quot;;&lt;/code&gt;，可读性更高。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const&lt;/code&gt; 是编译期常量，值必须在编译阶段可确定。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;final&lt;/code&gt; 是运行期常量，可以在运行时初始化，但只能赋值一次。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// var：让编译器根据右侧值推断类型，这里推断为 int
var age = 20; // age 之后只能继续接收 int

// 显式声明：直接把类型写在前面，可读性更好
String name = &quot;Sheyiyuan&quot;; // name 的静态类型固定是 String

// const：编译期常量，值在编译阶段就确定
const double pi = 3.141592653589793;
const double root2 = 1.4142135623730951;

// final：运行时初始化一次，之后不可再赋值
final DateTime time = DateTime.now(); // 每次运行值可能不同
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2. 字符串 String&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Dart 支持单引号和双引号，本文默认双引号。&lt;/li&gt;
&lt;li&gt;字符串插值常用 &lt;code&gt;$var&lt;/code&gt; 和 &lt;code&gt;${expression}&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;当拼接表达式或存在变量名歧义时，优先使用 &lt;code&gt;${}&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;字符串模板不是反引号语法，直接使用普通引号即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 基本字符串声明
String text1 = &quot;故障机器人&quot;;
String text2 = &apos;坠机了&apos;;

// 字符串插值：变量可直接写 $变量名
// 复杂表达式建议用 ${表达式}
String text = &quot;${text1}又$text2&quot;;

// 当变量名可能连续时，用空格或 ${} 避免歧义
int f = 1;
int fg = 2;
print(&quot;$f $fg&quot;); // 输出: 1 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 数值类型：int / double / num&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;int&lt;/code&gt; 表示整数，&lt;code&gt;double&lt;/code&gt; 表示浮点数，&lt;code&gt;num&lt;/code&gt; 是二者共同父类型。&lt;/li&gt;
&lt;li&gt;类型推断下，整数字面量通常推断为 &lt;code&gt;int&lt;/code&gt;，小数字面量推断为 &lt;code&gt;double&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;Dart 默认不做通用隐式转换，字符串与数字互转需要显式调用 API。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;double&lt;/code&gt; 可以赋值给 &lt;code&gt;num&lt;/code&gt;；&lt;code&gt;num&lt;/code&gt; 赋值给 &lt;code&gt;double&lt;/code&gt; 需要显式转换。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 明确声明不同数字类型
int a = 1;
double b = 1.1;
num c = 2; // num 可接收 int 或 double

// 查看运行时类型（调试时很有用）
print(&quot;a.runtimeType: ${a.runtimeType}, b.runtimeType: ${b.runtimeType}&quot;);

// 显式转换：int -&amp;gt; double
double d = a.toDouble();

// 显式转换：double -&amp;gt; int（会截断小数部分，不是四舍五入）
int e = b.toInt();

// 字符串转数字：解析失败会抛异常
int parsed = int.parse(&quot;123&quot;);

// 数字转字符串
String s = parsed.toString();
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. 布尔类型 bool&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;布尔值只有 &lt;code&gt;true&lt;/code&gt; 和 &lt;code&gt;false&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;Dart 不允许把非布尔值当作条件表达式。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;bool isCompleted = false;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. 列表 List&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; 是有序集合，索引从 0 开始。&lt;/li&gt;
&lt;li&gt;推荐写泛型（如 &lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt;），避免 &lt;code&gt;dynamic&lt;/code&gt; 扩散。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const&lt;/code&gt; 列表是不可变列表，不能做增删改。&lt;/li&gt;
&lt;li&gt;常用操作：&lt;code&gt;add&lt;/code&gt;、&lt;code&gt;addAll&lt;/code&gt;、&lt;code&gt;where&lt;/code&gt;、&lt;code&gt;every&lt;/code&gt;、&lt;code&gt;remove&lt;/code&gt;、&lt;code&gt;removeAt&lt;/code&gt;、&lt;code&gt;clear&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 声明一个元素类型为 String 的列表
final List&amp;lt;String&amp;gt; names = [&quot;Alice&quot;, &quot;Bromia&quot;];

// add：在尾部追加一个元素
names.add(&quot;Cecelia&quot;);

// addAll：把另一个集合的元素依次追加到尾部
names.addAll([&quot;Defect&quot;, &quot;Defect&quot;]);
print(names); // [Alice, Bromia, Cecelia, Defect, Defect]

// forEach：遍历每个元素并执行回调
names.forEach((element) {
  print(element);
});

// every：判断是否“所有元素都满足条件”
bool allDefect = names.every((element) =&amp;gt; element == &quot;Defect&quot;);

// where：筛选满足条件的元素，返回 Iterable
Iterable&amp;lt;String&amp;gt; defectNames = names.where((element) =&amp;gt; element == &quot;Defect&quot;);
print(&quot;All elements are Defect: $allDefect&quot;);
print(&quot;Defect names: ${defectNames.toList()}&quot;); // toList 转回 List 便于打印

// 常见属性
print(&quot;Number of elements: ${names.length}&quot;); // 长度
print(&quot;First element: ${names.first}&quot;); // 首元素
print(&quot;Last element: ${names.last}&quot;); // 尾元素
print(&quot;Is the list empty? ${names.isEmpty}&quot;); // 是否为空

// 删除操作示例
names.remove(&quot;Defect&quot;); // remove：删除第一个匹配项
names.removeLast(); // 删除最后一个元素
names.removeRange(0, 2); // 删除区间 [0, 2)，左闭右开
if (names.isNotEmpty) {
  names.removeAt(0); // 删除指定索引元素
}
print(names);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 字典 Map&amp;lt;K, V&amp;gt;&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Map&lt;/code&gt; 是键值对集合，键唯一、值可重复。&lt;/li&gt;
&lt;li&gt;推荐总是声明泛型，提升可读性和类型安全。&lt;/li&gt;
&lt;li&gt;常用操作：&lt;code&gt;map[key] = value&lt;/code&gt;、&lt;code&gt;keys&lt;/code&gt;、&lt;code&gt;values&lt;/code&gt;、&lt;code&gt;length&lt;/code&gt;、&lt;code&gt;remove&lt;/code&gt;、&lt;code&gt;containsKey&lt;/code&gt;、&lt;code&gt;containsValue&lt;/code&gt;、&lt;code&gt;addAll&lt;/code&gt;、&lt;code&gt;forEach&lt;/code&gt;、&lt;code&gt;clear&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;字符串插值中访问键时常写成 &lt;code&gt;${map[&apos;name&apos;]}&lt;/code&gt;，这里使用单引号可避免转义。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 声明键和值都为 String 的 Map
final Map&amp;lt;String, String&amp;gt; typedInformMap = {
  &quot;name&quot;: &quot;Sheyiyuan&quot;,
  &quot;age&quot;: &quot;18&quot;,
};

// 通过索引语法新增或覆盖键值
typedInformMap[&quot;gender&quot;] = &quot;male&quot;;
typedInformMap[&quot;age&quot;] = &quot;20&quot;; // 覆盖原 age
print(typedInformMap); // {name: Sheyiyuan, age: 20, gender: male}

// 读取与属性查看
print(&quot;Name: ${typedInformMap[&apos;name&apos;]}&quot;); // 读取指定键
print(&quot;Keys: ${typedInformMap.keys}&quot;); // 所有键
print(&quot;Values: ${typedInformMap.values}&quot;); // 所有值
print(&quot;Number of key-value pairs: ${typedInformMap.length}&quot;); // 键值对数量

// 删除与判断
typedInformMap.remove(&quot;age&quot;); // 返回被删掉的值（若不存在则为 null）
print(&quot;Contains key \&quot;name\&quot;? ${typedInformMap.containsKey(&quot;name&quot;)}&quot;);
print(&quot;Contains value \&quot;male\&quot;? ${typedInformMap.containsValue(&quot;male&quot;)}&quot;);

// addAll：合并另一个 Map（同名键会被覆盖）
typedInformMap.addAll({
  &quot;name&quot;: &quot;社亦园&quot;,
  &quot;hobby&quot;: &quot;coding&quot;,
  &quot;age&quot;: &quot;20&quot;,
});

// forEach：遍历每一组 key-value
typedInformMap.forEach((key, value) {
  print(&quot;$key: $value&quot;);
});

// clear：清空 Map
typedInformMap.clear();
print(typedInformMap); // {}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;7. 动态类型 dynamic&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dynamic&lt;/code&gt; 可以在运行时变更实际类型。&lt;/li&gt;
&lt;li&gt;适合边界场景（如 JSON 反序列化过渡阶段），不建议滥用。&lt;/li&gt;
&lt;li&gt;过多使用 &lt;code&gt;dynamic&lt;/code&gt; 会削弱静态检查能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// dynamic 可在运行时持有任意类型
// 代价是编译期类型检查能力变弱
dynamic variable = &quot;Hello, Dart&quot;;
print(variable); // Hello, Dart

// 同一个变量可改成 int
variable = 42;
print(variable); // 42

// 也可改成 List&amp;lt;int&amp;gt;
variable = [1, 2, 3];
print(variable); // [1, 2, 3]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8. 空安全（Null Safety）&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Dart 默认非空，变量默认不能为 &lt;code&gt;null&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;可空类型使用 &lt;code&gt;?&lt;/code&gt;，如 &lt;code&gt;String?&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;安全访问使用 &lt;code&gt;?.&lt;/code&gt;，空合并默认值使用 &lt;code&gt;??&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;非空断言 &lt;code&gt;!&lt;/code&gt; 需谨慎，判断错了会触发运行时错误。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// String?：可空字符串，允许赋值 null
String? nullableString = &quot;Hello, Dart&quot;;
print(nullableString); // Hello, Dart

nullableString = null;
print(nullableString); // null

// String：非空字符串，不能赋值 null
String nonNullableString = &quot;Hello, Dart&quot;;
print(nonNullableString);

// ?.：当左侧为 null 时，整条表达式返回 null，不会抛异常
int? length = nullableString?.length;
print(length); // null

// ??: 左侧为 null 时使用右侧默认值
String defaultString = nullableString ?? &quot;Default String&quot;;
print(defaultString); // Default String
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;9. 运算符&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;算术：&lt;code&gt;+&lt;/code&gt;、&lt;code&gt;-&lt;/code&gt;、&lt;code&gt;*&lt;/code&gt;、&lt;code&gt;/&lt;/code&gt;、&lt;code&gt;~/&lt;/code&gt;（整除）、&lt;code&gt;%&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;赋值：&lt;code&gt;=&lt;/code&gt;、&lt;code&gt;+=&lt;/code&gt;、&lt;code&gt;-=&lt;/code&gt;、&lt;code&gt;*=&lt;/code&gt;、&lt;code&gt;/=&lt;/code&gt;、&lt;code&gt;~/=&lt;/code&gt;、&lt;code&gt;%=&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;比较：&lt;code&gt;==&lt;/code&gt;、&lt;code&gt;!=&lt;/code&gt;、&lt;code&gt;&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;&lt;/code&gt;、&lt;code&gt;&amp;gt;=&lt;/code&gt;、&lt;code&gt;&amp;lt;=&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;逻辑：&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;、&lt;code&gt;||&lt;/code&gt;、&lt;code&gt;!&lt;/code&gt;，并且 &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; / &lt;code&gt;||&lt;/code&gt; 具备短路特性。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;int a1 = 10;
int b1 = 3;

// 算术运算
print(&quot;a1 + b1 = ${a1 + b1}&quot;);
print(&quot;a1 - b1 = ${a1 - b1}&quot;);
print(&quot;a1 * b1 = ${a1 * b1}&quot;);
print(&quot;a1 / b1 = ${a1 / b1}&quot;); // / 结果是 double
print(&quot;a1 ~/ b1 = ${a1 ~/ b1}&quot;); // ~/ 是整除
print(&quot;a1 % b1 = ${a1 % b1}&quot;);

int c1 = 5;

// 复合赋值运算
c1 += 2;
c1 -= 3;
c1 *= 4;
c1 ~/= 5;
c1 %= 2;
print(&quot;c1 = $c1&quot;);

int d1 = 10;
int d2 = 20;

// 比较运算
print(&quot;d1 == d2: ${d1 == d2}&quot;);
print(&quot;d1 != d2: ${d1 != d2}&quot;);
print(&quot;d1 &amp;gt; d2: ${d1 &amp;gt; d2}&quot;);
print(&quot;d1 &amp;lt; d2: ${d1 &amp;lt; d2}&quot;);
print(&quot;d1 &amp;gt;= d2: ${d1 &amp;gt;= d2}&quot;);
print(&quot;d1 &amp;lt;= d2: ${d1 &amp;lt;= d2}&quot;);

bool e1 = true;
bool e2 = false;

// 逻辑运算（&amp;amp;&amp;amp; / || 支持短路）
print(&quot;e1 &amp;amp;&amp;amp; e2: ${e1 &amp;amp;&amp;amp; e2}&quot;);
print(&quot;e1 || e2: ${e1 || e2}&quot;);
print(&quot;!e1: ${!e1}&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10. 流程控制&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;条件语句：&lt;code&gt;if&lt;/code&gt; / &lt;code&gt;else if&lt;/code&gt; / &lt;code&gt;else&lt;/code&gt;、&lt;code&gt;switch&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;循环语句：&lt;code&gt;for&lt;/code&gt;、&lt;code&gt;while&lt;/code&gt;、&lt;code&gt;do-while&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;三目表达式可在简单分支中替代 &lt;code&gt;if&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;int f1 = 10;

// if / else if / else 分支判断
if (f1 &amp;gt; 5) {
  print(&quot;f1 is greater than 5&quot;);
} else if (f1 == 5) {
  print(&quot;f1 is equal to 5&quot;);
} else {
  print(&quot;f1 is less than 5&quot;);
}

// 三目表达式：简洁地返回分支结果
String result = (f1 &amp;gt; 5) ? &quot;Greater than 5&quot; : &quot;Not greater than 5&quot;;
print(result);

int g1 = 2;

// switch：适合离散值匹配
switch (g1) {
  case 1:
    print(&quot;g1 is 1&quot;);
    break; // 不加 break 会继续执行后续 case
  case 2:
    print(&quot;g1 is 2&quot;);
    break;
  case 3:
    print(&quot;g1 is 3&quot;);
    break;
  default:
    print(&quot;g1 is something else&quot;);
}

// for：已知循环次数时常用
for (int i = 0; i &amp;lt; 5; i++) {
  print(&quot;i: $i&quot;);
}

// while：先判断条件，再决定是否进入循环
int j = 0;
while (j &amp;lt; 5) {
  print(&quot;j: $j&quot;);
  j++;
}

// do-while：先执行一次，再判断条件
int k = 0;
do {
  print(&quot;k: $k&quot;);
  k++;
} while (k &amp;lt; 5);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;11. 函数&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Dart 不支持传统函数重载。&lt;/li&gt;
&lt;li&gt;可选参数分两类：可选位置参数 &lt;code&gt;[]&lt;/code&gt;、可选命名参数 &lt;code&gt;{}&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;箭头函数适合单表达式返回。&lt;/li&gt;
&lt;li&gt;闭包可以捕获外层函数变量。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 普通函数：有函数名、参数和函数体
void greet(String name) {
  print(&quot;Hello, $name!&quot;);
}

greet(&quot;Cecelia&quot;);

// 可选位置参数：放在 [] 中，调用时可省略
void greetWithOptional(String name, [String? greeting]) {
  if (greeting != null) {
    print(&quot;$greeting, $name!&quot;);
  } else {
    print(&quot;Hello, $name!&quot;);
  }
}

greetWithOptional(&quot;Cecelia&quot;);
greetWithOptional(&quot;Cecelia&quot;, &quot;Hi&quot;);

// 可选命名参数：放在 {} 中，调用时用 参数名:值
void greetWithNamed(String name, {String? sign, String? greeting}) {
  String actualGreeting = greeting ?? &quot;Hello&quot;; // 提供默认问候语
  String actualSign = sign ?? &quot;!&quot;; // 提供默认标点
  print(&quot;$actualGreeting, $name$actualSign&quot;);
}

greetWithNamed(&quot;Cecelia&quot;, sign: &quot;?&quot;);
greetWithNamed(&quot;Cecelia&quot;, greeting: &quot;Hi&quot;);

// 匿名函数：没有函数名，通常赋值给变量
var anonymousGreet = (String name) {
  print(&quot;Hello, $name!&quot;);
};
anonymousGreet(&quot;Cecelia&quot;);

// 箭头函数：只有一个表达式时可简写
String arrowGreet(String name) =&amp;gt; &quot;Hello, $name!&quot;;
print(arrowGreet(&quot;Cecelia&quot;));

// 闭包：返回的函数可“记住”外层变量 addBy
Function makeAdder(int addBy) {
  return (int i) =&amp;gt; addBy + i;
}

var add2 = makeAdder(2);
print(add2(3)); // 5
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;12. 类&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Dart 是纯面向对象语言，几乎所有值都是对象。&lt;/li&gt;
&lt;li&gt;类由字段（属性）、方法、构造函数组成。&lt;/li&gt;
&lt;li&gt;支持普通构造、命名构造、工厂构造、继承、抽象类、接口实现、静态成员。&lt;/li&gt;
&lt;li&gt;私有成员通过“库私有”规则实现：以下划线 &lt;code&gt;_&lt;/code&gt; 开头的成员仅在当前库可见。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 一个基础类：演示字段、构造函数、实例方法、getter/setter
class Person {
  // 普通实例字段：每个对象各自拥有一份
  String name;
  int age;

  // 私有字段：以下划线开头，仅当前库可见
  String _id;

  // 主构造函数：this.name / this.age 是参数到字段的简写绑定
  Person(this.name, this.age, this._id);

  // 命名构造函数：更适合表达不同初始化语义
  Person.guest() : name = &quot;Guest&quot;, age = 0, _id = &quot;GUEST&quot;;

  // getter：对外暴露只读视图
  String get maskedId =&amp;gt; &quot;***${_id.substring(_id.length - 2)}&quot;;

  // setter：集中做数据校验
  set updateAge(int value) {
    if (value &amp;gt;= 0) {
      age = value;
    }
  }

  // 实例方法
  void introduce() {
    print(&quot;Hi, I am $name, age: $age, id: $maskedId&quot;);
  }
}

// 继承：Student 继承 Person 的字段与方法
class Student extends Person {
  // 新增子类字段
  String major;

  // super(...) 调用父类构造函数
  Student(String name, int age, String id, this.major) : super(name, age, id);

  // override：重写父类方法
  @override
  void introduce() {
    print(&quot;Hi, I am $name, major in $major, age: $age&quot;);
  }
}

// 抽象类：不能直接实例化，通常用于定义能力规范
abstract class Animal {
  void speak(); // 抽象方法：子类必须实现
}

// implements：按“接口契约”实现
class Dog implements Animal {
  @override
  void speak() {
    print(&quot;Woof!&quot;);
  }
}

// 静态成员：属于类本身，不属于实例
class MathHelper {
  static const double pi = 3.141592653589793;

  static double circleArea(double radius) {
    return pi * radius * radius;
  }
}

// 工厂构造函数：可返回缓存实例，或返回子类型实例
class Logger {
  final String name;

  // 私有命名构造：仅类内部可直接调用
  Logger._internal(this.name);

  // 缓存池（静态）
  static final Map&amp;lt;String, Logger&amp;gt; _cache = &amp;lt;String, Logger&amp;gt;{};

  // factory：可以不每次都 new 新对象
  factory Logger(String name) {
    return _cache.putIfAbsent(name, () =&amp;gt; Logger._internal(name));
  }

  void log(String message) {
    print(&quot;[$name] $message&quot;);
  }
}

void main() {
  // 主构造
  Person p1 = Person(&quot;Sheyiyuan&quot;, 18, &quot;ID2026&quot;);
  p1.introduce();

  // 命名构造
  Person guest = Person.guest();
  guest.introduce();

  // setter 校验
  p1.updateAge = 19;
  p1.introduce();

  // 继承与多态
  Person stu = Student(&quot;Cecelia&quot;, 20, &quot;ST01&quot;, &quot;Computer Science&quot;);
  stu.introduce(); // 实际调用 Student 的重写方法

  // 抽象类 + 接口实现
  Animal dog = Dog();
  dog.speak();

  // 静态成员访问方式：类名.成员
  print(&quot;Area: ${MathHelper.circleArea(2)}&quot;);

  // 工厂构造缓存验证
  Logger l1 = Logger(&quot;app&quot;);
  Logger l2 = Logger(&quot;app&quot;);
  print(identical(l1, l2)); // true，说明命中了缓存
  l1.log(&quot;Started&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;13. 抽象类与接口实现&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;抽象类用 &lt;code&gt;abstract class&lt;/code&gt; 声明，不能直接实例化。&lt;/li&gt;
&lt;li&gt;抽象类可以同时包含：
&lt;ul&gt;
&lt;li&gt;抽象成员（只有声明，没有实现）；&lt;/li&gt;
&lt;li&gt;已实现成员（子类可直接复用）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;extends&lt;/code&gt; 表示继承实现：子类会复用父类已实现的逻辑。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;implements&lt;/code&gt; 表示按接口契约实现：必须重写接口中的所有成员（包括 getter/setter）。&lt;/li&gt;
&lt;li&gt;Dart 没有单独的 &lt;code&gt;interface&lt;/code&gt; 关键字，任何类都可以被 &lt;code&gt;implements&lt;/code&gt; 当作接口使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 抽象类：定义“设备”这一抽象概念
abstract class Device {
  // 抽象 getter：子类必须提供具体返回值
  String get model;

  // 抽象方法：子类必须实现
  void start();

  // 已实现方法：子类可直接继承复用
  void shutdown() {
    print(&quot;$model is shutting down&quot;);
  }
}

// 普通类被当作“接口”使用（用于 implements）
class Chargeable {
  int batteryLevel = 0;

  void charge(int amount) {}
}

// 另一个可被实现的接口
class Connectable {
  bool get isConnected =&amp;gt; false;

  void connect(String target) {}
}

// extends：继承 Device 已实现方法
// implements：必须完整实现 Chargeable / Connectable 的成员
class Phone extends Device implements Chargeable, Connectable {
  @override
  final String model;

  @override
  int batteryLevel;

  bool _connected = false;

  Phone(this.model, {this.batteryLevel = 20});

  @override
  void start() {
    print(&quot;$model is starting&quot;);
  }

  @override
  bool get isConnected =&amp;gt; _connected;

  @override
  void connect(String target) {
    _connected = true;
    print(&quot;$model connected to $target&quot;);
  }

  @override
  void charge(int amount) {
    batteryLevel += amount;
    if (batteryLevel &amp;gt; 100) {
      batteryLevel = 100;
    }
    print(&quot;$model battery: $batteryLevel%&quot;);
  }
}

void main() {
  Phone phone = Phone(&quot;Pixel&quot;, batteryLevel: 35);

  // 来自抽象类约定的方法
  phone.start();

  // 来自接口契约的方法
  phone.connect(&quot;WiFi-Home&quot;);
  phone.charge(30);

  // 来自抽象类已实现的复用方法
  phone.shutdown();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;14. 类的混入（mixin）&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mixin&lt;/code&gt; 用于“复用一组方法/字段实现”，避免多层继承导致结构僵硬。&lt;/li&gt;
&lt;li&gt;使用方式：&lt;code&gt;class A with M1, M2&lt;/code&gt;，可以一次混入多个 mixin。&lt;/li&gt;
&lt;li&gt;冲突规则：如果多个 mixin 有同名方法，后写的 mixin 优先级更高。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;on&lt;/code&gt; 约束：限制该 mixin 只能用于某些父类体系。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mixin&lt;/code&gt; 不是普通类，不能被 &lt;code&gt;new&lt;/code&gt; 实例化；它是“能力片段”。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 基础类：被混入目标类继承
class User {
  final String name;

  User(this.name);
}

// 普通 mixin：提供可复用能力
mixin LoggerMixin {
  void log(String message) {
    print(&quot;[LOG] $message&quot;);
  }
}

// 带状态的 mixin：可声明字段
mixin CounterMixin {
  int _count = 0;

  int get count =&amp;gt; _count;

  void increase() {
    _count++;
  }
}

// 带 on 约束的 mixin：只能混入到 User 或其子类
mixin UserInfoMixin on User {
  String get displayName =&amp;gt; &quot;User&amp;lt;$name&amp;gt;&quot;;
}

// with：把多个 mixin 的能力拼装到同一个类里
class Admin extends User with LoggerMixin, CounterMixin, UserInfoMixin {
  Admin(super.name);

  void work() {
    increase(); // 来自 CounterMixin
    log(&quot;$displayName working, count=$count&quot;); // Logger + UserInfo
  }
}

// 演示同名方法冲突：后面的 mixin 会覆盖前面的实现
mixin WalkMixin {
  void move() {
    print(&quot;walk&quot;);
  }
}

mixin RunMixin {
  void move() {
    print(&quot;run&quot;);
  }
}

class Athlete with WalkMixin, RunMixin {}

void main() {
  Admin admin = Admin(&quot;Sheyiyuan&quot;);
  admin.work();
  admin.work();

  Athlete athlete = Athlete();
  athlete.move(); // 输出 run（因为 RunMixin 写在后面）
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;补充&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mixin&lt;/code&gt;：只能被混入，不能直接 &lt;code&gt;new&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;class&lt;/code&gt;：普通类，可实例化、可继承。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mixin class&lt;/code&gt;（Dart 3）：既可以被实例化（像类），也可以被 &lt;code&gt;with&lt;/code&gt; 混入（像 mixin）。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// Dart 3：mixin class 同时具备 class + mixin 的能力
mixin class Timestamped {
  final DateTime createdAt = DateTime.now();

  String createdLabel() =&amp;gt; createdAt.toIso8601String();
}

class Task with Timestamped {
  final String title;
  Task(this.title);
}

void main() {
  Task t = Task(&quot;Write notes&quot;);
  print(t.createdLabel());

  // 也可直接实例化（这是 mixin class 与 mixin 的关键区别）
  Timestamped ts = Timestamped();
  print(ts.createdLabel());
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;实践建议：
&lt;ul&gt;
&lt;li&gt;只复用行为，用 &lt;code&gt;mixin&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;既要“可复用”又要“可单独实例化”，可考虑 &lt;code&gt;mixin class&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;有明显 is-a 关系时优先 &lt;code&gt;extends&lt;/code&gt;，不要滥用 mixin。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;常见坑：
&lt;ul&gt;
&lt;li&gt;多个 mixin 同名方法冲突时，后写覆盖前写；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;on&lt;/code&gt; 约束不满足会直接编译报错；&lt;/li&gt;
&lt;li&gt;mixin 中状态字段过多会提高耦合度，建议保持轻量。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;extends / implements / with 速记&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;关键字&lt;/th&gt;
&lt;th&gt;核心含义&lt;/th&gt;
&lt;th&gt;会继承实现吗&lt;/th&gt;
&lt;th&gt;典型场景&lt;/th&gt;
&lt;th&gt;注意点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extends&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;继承父类（is-a）&lt;/td&gt;
&lt;td&gt;会&lt;/td&gt;
&lt;td&gt;明确父子层级关系&lt;/td&gt;
&lt;td&gt;单继承；子类可 &lt;code&gt;@override&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;implements&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;按接口契约实现&lt;/td&gt;
&lt;td&gt;不会&lt;/td&gt;
&lt;td&gt;只要能力约束，不要父类实现&lt;/td&gt;
&lt;td&gt;必须实现所有成员&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;with&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;混入复用能力片段&lt;/td&gt;
&lt;td&gt;会（来自 mixin）&lt;/td&gt;
&lt;td&gt;横切能力复用（日志、计数、缓存标记）&lt;/td&gt;
&lt;td&gt;多个 mixin 冲突时后者覆盖前者&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;15. 泛型（Generics）&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;泛型的核心价值：把“类型”参数化，提升复用性与类型安全。&lt;/li&gt;
&lt;li&gt;常见写法：&lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt;、&lt;code&gt;Map&amp;lt;String, int&amp;gt;&lt;/code&gt;、&lt;code&gt;class Box&amp;lt;T&amp;gt;&lt;/code&gt;、&lt;code&gt;T identity&amp;lt;T&amp;gt;(T value)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;当类型不满足预期时，问题会在编译期暴露，而不是拖到运行时。&lt;/li&gt;
&lt;li&gt;可以用 &lt;code&gt;extends&lt;/code&gt; 给泛型参数加约束，如 &lt;code&gt;T extends num&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 1) 集合中的泛型：限制元素类型，避免 dynamic 扩散
List&amp;lt;String&amp;gt; names = [&quot;Alice&quot;, &quot;Bronia&quot;];
// names.add(123); // 编译报错：int 不能放进 List&amp;lt;String&amp;gt;

Map&amp;lt;String, int&amp;gt; scoreMap = {
  &quot;math&quot;: 95,
  &quot;english&quot;: 88,
};
print(scoreMap[&quot;math&quot;]);

// 2) 泛型函数：输入什么类型，就返回什么类型
T identity&amp;lt;T&amp;gt;(T value) {
  return value;
}

void testGenericFunction() {
  String s = identity&amp;lt;String&amp;gt;(&quot;hello&quot;);
  int n = identity&amp;lt;int&amp;gt;(100);

  // 大多数时候可省略类型参数，让编译器推断
  bool flag = identity(true);

  print(&quot;$s, $n, $flag&quot;);
}

// 3) 泛型类：把类型作为类的一部分
class Box&amp;lt;T&amp;gt; {
  T value;

  Box(this.value);

  T getValue() =&amp;gt; value;

  void setValue(T newValue) {
    value = newValue;
  }
}

void testGenericClass() {
  Box&amp;lt;String&amp;gt; stringBox = Box&amp;lt;String&amp;gt;(&quot;Dart&quot;);
  print(stringBox.getValue());

  Box&amp;lt;int&amp;gt; intBox = Box&amp;lt;int&amp;gt;(42);
  intBox.setValue(100);
  print(intBox.getValue());
}

// 4) 泛型约束：限制 T 必须是 num 或其子类型
T addNum&amp;lt;T extends num&amp;gt;(T a, T b) {
  // num 的 + 返回 num，这里通过 as T 转回目标类型
  return (a + b) as T;
}

void testGenericConstraint() {
  int i = addNum&amp;lt;int&amp;gt;(1, 2);
  double d = addNum&amp;lt;double&amp;gt;(1.5, 2.5);
  print(&quot;$i, $d&quot;);

  // addNum&amp;lt;String&amp;gt;(&quot;1&quot;, &quot;2&quot;);
  // 编译报错：String 不满足 T extends num
}

void main() {
  testGenericFunction();
  testGenericClass();
  testGenericConstraint();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;泛型实践建议&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;集合一律写泛型：&lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; / &lt;code&gt;Map&amp;lt;K, V&amp;gt;&lt;/code&gt;，不要偷懒写裸类型。&lt;/li&gt;
&lt;li&gt;能用编译器推断就让其推断，但公开 API 建议显式写清类型参数。&lt;/li&gt;
&lt;li&gt;写库代码时优先泛型 + 约束，减少 &lt;code&gt;dynamic&lt;/code&gt; 与强转。&lt;/li&gt;
&lt;li&gt;遇到类型推断不稳定时，手动补上 &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; 通常能快速解题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;常见坑&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;把 &lt;code&gt;List&lt;/code&gt; 写成裸类型（不带 &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt;）会回退到弱约束，容易埋雷。&lt;/li&gt;
&lt;li&gt;泛型约束过弱会让 API 太宽泛，过强会影响复用，需平衡。&lt;/li&gt;
&lt;li&gt;在泛型方法里滥用 &lt;code&gt;as&lt;/code&gt; 强转可能引入运行时异常。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;16. 异步编程（Future）&lt;/h2&gt;
&lt;h3&gt;说明&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Dart 采用事件循环模型：同步代码先执行，再处理微任务队列，最后处理事件队列。&lt;/li&gt;
&lt;li&gt;耗时操作（网络请求、文件 IO、定时器）应使用异步 API，避免阻塞主线程。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Future&amp;lt;T&amp;gt;&lt;/code&gt; 用于表示“未来某个时刻会得到一个 &lt;code&gt;T&lt;/code&gt; 或抛出错误”的结果。&lt;/li&gt;
&lt;li&gt;常见写法有两种：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;async/await&lt;/code&gt;：可读性高，接近同步代码；&lt;/li&gt;
&lt;li&gt;链式调用：&lt;code&gt;then&lt;/code&gt; / &lt;code&gt;catchError&lt;/code&gt; / &lt;code&gt;whenComplete&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;事件循环&lt;/h3&gt;
&lt;p&gt;执行顺序可简化理解为：&lt;/p&gt;
&lt;p&gt;同步代码 -&amp;gt; 微任务队列 -&amp;gt; 事件队列&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;微任务队列：&lt;code&gt;Future.microtask&lt;/code&gt;、&lt;code&gt;scheduleMicrotask&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;事件队列：&lt;code&gt;Future(() {})&lt;/code&gt;、&lt;code&gt;Future.delayed&lt;/code&gt;、&lt;code&gt;Timer&lt;/code&gt; 等。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;import &quot;dart:async&quot;;

void main() {
  print(&quot;A. sync start&quot;);

  scheduleMicrotask(() {
    print(&quot;B. microtask&quot;);
  });

  Future(() {
    print(&quot;C. event queue task&quot;);
  });

  print(&quot;D. sync end&quot;);
}

// 常见输出顺序：
// A. sync start
// D. sync end
// B. microtask
// C. event queue task
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Future 基础&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;// 模拟异步请求
Future&amp;lt;String&amp;gt; fetchData() async {
  await Future.delayed(Duration(seconds: 1));
  return &quot;Data fetched&quot;;
}

// async/await 写法：推荐业务代码优先使用
Future&amp;lt;void&amp;gt; runWithAwait() async {
  print(&quot;[await] start&quot;);

  try {
    String result = await fetchData();
    print(&quot;[await] result: $result&quot;);
  } catch (e) {
    print(&quot;[await] error: $e&quot;);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;链式调用&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Future&amp;lt;String&amp;gt; step1() async {
  await Future.delayed(Duration(milliseconds: 200));
  return &quot;step1&quot;;
}

Future&amp;lt;String&amp;gt; step2(String input) async {
  await Future.delayed(Duration(milliseconds: 200));
  return &quot;$input -&amp;gt; step2&quot;;
}

Future&amp;lt;void&amp;gt; runWithChain() async {
  step1()
      // then 可串联下一个 Future，形成链式流程
      .then((value) {
        print(&quot;chain value1: $value&quot;);
        return step2(value);
      })
      .then((value) {
        print(&quot;chain value2: $value&quot;);
      })
      // catchError 统一处理上游抛出的异常
      .catchError((error) {
        print(&quot;chain error: $error&quot;);
      })
      // whenComplete 无论成功或失败都会执行
      .whenComplete(() {
        print(&quot;chain finished&quot;);
      });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Future 与 Promise 对比（Dart vs JavaScript）&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;Dart Future&lt;/th&gt;
&lt;th&gt;JavaScript Promise&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;作用&lt;/td&gt;
&lt;td&gt;表示未来结果（值或错误）&lt;/td&gt;
&lt;td&gt;表示未来结果（值或拒绝）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;主要链式 API&lt;/td&gt;
&lt;td&gt;&lt;code&gt;then&lt;/code&gt; / &lt;code&gt;catchError&lt;/code&gt; / &lt;code&gt;whenComplete&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;then&lt;/code&gt; / &lt;code&gt;catch&lt;/code&gt; / &lt;code&gt;finally&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;async&lt;/code&gt; 函数返回&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Future&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Promise&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;组合并发&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Future.wait&lt;/code&gt; / &lt;code&gt;Future.any&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Promise.all&lt;/code&gt; / &lt;code&gt;Promise.race&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;调度模型重点&lt;/td&gt;
&lt;td&gt;微任务 + 事件队列（Event Loop）&lt;/td&gt;
&lt;td&gt;微任务队列 + 宏任务队列&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;错误处理习惯&lt;/td&gt;
&lt;td&gt;&lt;code&gt;try/catch&lt;/code&gt; + &lt;code&gt;catchError&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;try/catch&lt;/code&gt; + &lt;code&gt;.catch()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;结论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;概念非常接近，可以把 &lt;code&gt;Future&lt;/code&gt; 理解为 Dart 世界里的 &lt;code&gt;Promise&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;API 命名略有差异：&lt;code&gt;whenComplete&lt;/code&gt; 对应 JS 的 &lt;code&gt;finally&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;在 Dart 业务代码中通常优先使用 &lt;code&gt;async/await&lt;/code&gt;，链式调用适合做流程拼装与中间步骤拦截。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>把代码放到 GitHub 上就是开源吗？你可能误解了开源</title><link>https://blog.sheyiyuan.com/posts/%E6%8A%8A%E4%BB%A3%E7%A0%81%E6%94%BE%E5%88%B0-github-%E4%B8%8A%E5%B0%B1%E6%98%AF%E5%BC%80%E6%BA%90%E5%90%97%E4%BD%A0%E5%8F%AF%E8%83%BD%E8%AF%AF%E8%A7%A3%E4%BA%86%E5%BC%80%E6%BA%90/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/%E6%8A%8A%E4%BB%A3%E7%A0%81%E6%94%BE%E5%88%B0-github-%E4%B8%8A%E5%B0%B1%E6%98%AF%E5%BC%80%E6%BA%90%E5%90%97%E4%BD%A0%E5%8F%AF%E8%83%BD%E8%AF%AF%E8%A7%A3%E4%BA%86%E5%BC%80%E6%BA%90/</guid><description>开源 ≠ 免费 ≠ 代码公开。一文理清 Open Source、Source-Available 与 Freeware 的核心差异与商业逻辑。</description><pubDate>Wed, 25 Feb 2026 15:02:00 GMT</pubDate><content:encoded>&lt;p&gt;提到 GitHub，很多人脑子里会先蹦出一句话：&lt;/p&gt;
&lt;p&gt;「这里全是大佬的代码，我可以随便看、随便下、还不用花钱。」&lt;/p&gt;
&lt;p&gt;这句话不算错，但只说对了一半。&lt;/p&gt;
&lt;p&gt;因为在这个语境里，至少有三个很容易被混在一起的概念：&lt;strong&gt;开源、开放源代码、免费&lt;/strong&gt;。很多人会顺着字面意思理解成「代码公开了=开源了=免费随便用」，于是进一步得出结论：只要把项目丢到 GitHub，就已经完成开源。&lt;/p&gt;
&lt;p&gt;然后问题就来了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;既然都开源了，别人抄走怎么办？&lt;/li&gt;
&lt;li&gt;既然都免费了，作者和公司靠什么赚钱？&lt;/li&gt;
&lt;li&gt;既然代码都看得到，为什么还有「侵权」这种说法？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;先说结论：&lt;strong&gt;开源不等于免费，开源也不等于「代码公开可见」。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;要把这件事讲清楚，我们得先把几个核心概念掰开。&lt;/p&gt;
&lt;h2&gt;什么是开源？&lt;/h2&gt;
&lt;h3&gt;开放源代码 ≠ 开源 (Source-Available vs Open Source)&lt;/h3&gt;
&lt;p&gt;很多人会觉得：「我都把仓库公开了，别人也能看到全部代码，这不就是开源？」&lt;/p&gt;
&lt;p&gt;这个理解非常常见，但确实不准确。&lt;/p&gt;
&lt;p&gt;在版权规则里，如果你没有明确声明协议，那么默认状态是 「保留所有权利」（All rights reserved）。也就是说，别人确实能「看到」你的代码，但看到不代表有权使用。&lt;/p&gt;
&lt;p&gt;这种状态更接近 Source-Available（源代码可见）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你可以看；&lt;/li&gt;
&lt;li&gt;但未必能合法复制、修改、再发布；&lt;/li&gt;
&lt;li&gt;更不一定能商用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;换句话说，把代码放上 GitHub 只是「公开展示」，不自动等于「授予他人使用权」。&lt;/p&gt;
&lt;h3&gt;License（开源协议）——不起眼却最关键的存在&lt;/h3&gt;
&lt;p&gt;那真正的开源，关键差在哪？&lt;/p&gt;
&lt;p&gt;答案就是那个经常被忽略、但最重要的文件：&lt;code&gt;LICENSE&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;它看起来不起眼，很多人建仓库时甚至懒得选；但在法律意义上，它决定了「别人到底能不能用你的代码、能怎么用」。&lt;/p&gt;
&lt;p&gt;行业里通常以 OSI（Open Source Initiative，开源促进会）的定义为准。一个项目要被称为「开源」，通常需要使用 OSI 认可的开源协议（如 MIT、Apache 2.0、GPL 等）。&lt;/p&gt;
&lt;p&gt;你可以把协议理解成一份公开的授权合同：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;允许别人做什么；&lt;/li&gt;
&lt;li&gt;要求别人保留什么；&lt;/li&gt;
&lt;li&gt;触发什么条件时必须开源回去。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，真正决定「是不是开源」的，不是你把仓库设成 Public，而是你有没有给出明确、合规的授权规则。&lt;/p&gt;
&lt;h2&gt;免费与自由：Free 的双重含义&lt;/h2&gt;
&lt;h3&gt;Free as in Speech, not Free as in Beer&lt;/h3&gt;
&lt;p&gt;在英语里，&lt;code&gt;Free&lt;/code&gt; 这个词本身就有双重含义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以是「免费」；&lt;/li&gt;
&lt;li&gt;也可以是「自由」。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这也是很多误解的根源。&lt;/p&gt;
&lt;p&gt;自由软件运动先驱 Richard Stallman 有句名言，基本是这个话题的标准答案：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;「Free as in free speech, not as in free beer」&lt;/strong&gt;（自由如言论，而非免费如啤酒）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;开源（以及自由软件语境中的 free）强调的核心是&lt;strong&gt;权利上的自由&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你可以运行它；&lt;/li&gt;
&lt;li&gt;你可以研究它；&lt;/li&gt;
&lt;li&gt;你可以修改它；&lt;/li&gt;
&lt;li&gt;你可以分发它。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;重点在「权利是否被授权」，而不是「价格是不是 0 元」。&lt;/p&gt;
&lt;h3&gt;免费软件 (Freeware) 与 开源软件的区别&lt;/h3&gt;
&lt;p&gt;这一点可以用一个最常见的对比来理解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;免费软件（Freeware）&lt;/strong&gt;：比如微信、QQ，或者一些免费工具软件。你可以不花钱用，但它们通常是闭源的。你看不到内部实现，也不能随意改、随意分发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开源软件（Open Source Software）&lt;/strong&gt;：它可以收费。典型例子就是 Red Hat Enterprise Linux：源代码遵循开源规则，但企业版发行、支持服务、认证体系都可以卖钱，而且卖得很好。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;结论很简单：&lt;strong&gt;免费不等于开源，开源也不排斥收费。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;开源协议的阵营：Copyright 与 Copyleft&lt;/h2&gt;
&lt;p&gt;既然开源的核心在协议，那 GitHub 上那么多 &lt;code&gt;License&lt;/code&gt; 到底怎么理解？&lt;/p&gt;
&lt;p&gt;先不用记条款细节，先抓住两个大阵营就够了。&lt;/p&gt;
&lt;h3&gt;宽松式协议 (Permissive)&lt;/h3&gt;
&lt;p&gt;代表协议：&lt;strong&gt;MIT、Apache 2.0、BSD&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这类协议可以概括为一句话：&lt;strong&gt;「拿去用，别忘了署名。」&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你可以商用、可以二开、可以闭源集成，整体限制相对少。也正因为足够宽松，MIT、Apache 2.0 在工程实践里非常常见。&lt;/p&gt;
&lt;h3&gt;传染性协议 (Copyleft)&lt;/h3&gt;
&lt;p&gt;代表协议：&lt;strong&gt;GPL 家族（GPL、AGPL 等）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这类协议强调「你享受了开源自由，也要把自由传递下去」。&lt;/p&gt;
&lt;p&gt;简单说：你可以用、可以改，但如果你把修改后的版本对外分发，往往需要按同类协议继续开源。&lt;/p&gt;
&lt;p&gt;这也是很多人说的「传染性」来源。它不是坏事，而是一种价值选择：通过规则确保社区成果不被单向抽取。&lt;/p&gt;
&lt;h2&gt;既然开源，那靠什么赚钱？&lt;/h2&gt;
&lt;p&gt;回到最现实的问题：&lt;/p&gt;
&lt;p&gt;「既然代码都开出来了，靠什么赚钱？」&lt;/p&gt;
&lt;p&gt;答案是：开源项目不等于慈善项目。现在的开源商业化路径其实已经非常成熟。&lt;/p&gt;
&lt;h3&gt;常见的开源商业模式&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;双重授权（Dual Licensing）&lt;/strong&gt;：开源版给社区，商业版给需要闭源集成的客户。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;托管服务（SaaS）&lt;/strong&gt;：软件开源，但“帮你稳定运行”是收费服务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open Core&lt;/strong&gt;：核心功能开源，高级企业能力单独收费。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术支持与咨询&lt;/strong&gt;：代码可以免费，服务体系可以很值钱。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以「开源怎么赚钱」并不是无解题，而是「卖什么」的商业设计题。&lt;/p&gt;
&lt;h3&gt;开源的真正价值：生态与社区&lt;/h3&gt;
&lt;p&gt;开源的核心价值不在于“代码免费”，而在于&lt;strong&gt;生态和社区&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;对于个人或社区贡献者来说，开源提供了一个展示能力、积累声誉的平台；对于企业来说，开源是构建生态、吸引用户、推动创新的战略工具。&lt;/p&gt;
&lt;p&gt;对于商业公司来说，开源是一个双赢的游戏：通过开放核心技术，吸引更多用户和开发者参与进来，打造属于自己的生态护城河，形成良性循环；同时通过增值服务、企业版等方式实现商业变现。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;「把代码放到 GitHub」只是开始，不是终点。&lt;/p&gt;
&lt;p&gt;真正的开源，核心是规则清晰、权责明确：谁可以做什么、边界在哪里、回馈机制是什么。它不是「免费午餐」，而是一套有契约、有协作、有长期价值的生产方式。&lt;/p&gt;
&lt;p&gt;如果你只记住一件事，那就记住这句：&lt;strong&gt;看项目先看 &lt;code&gt;LICENSE&lt;/code&gt;。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;懂规则，才谈得上真正参与开源；尊重规则，才是从「拿来主义」走向「共同建设」的第一步。&lt;/p&gt;
</content:encoded></item><item><title>Debian 安装后 Windows 磁盘“消失”？从绝望到找回的全过程复盘</title><link>https://blog.sheyiyuan.com/posts/%E5%8F%8C%E7%A1%AC%E7%9B%98%E5%8F%8C%E7%B3%BB%E7%BB%9F%E7%BF%BB%E8%BD%A6%E5%85%A8%E5%A4%8D%E7%9B%98/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/%E5%8F%8C%E7%A1%AC%E7%9B%98%E5%8F%8C%E7%B3%BB%E7%BB%9F%E7%BF%BB%E8%BD%A6%E5%85%A8%E5%A4%8D%E7%9B%98/</guid><pubDate>Fri, 13 Feb 2026 10:41:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文仅作为技术分享与个人复盘记录。&lt;/p&gt;
&lt;p&gt;文中涉及 BIOS/磁盘/引导相关操作具有一定风险：如果你不理解每一步在做什么，请先停下来查资料或找有经验的人协助。&lt;/p&gt;
&lt;p&gt;任何因盲目照做导致的数据丢失、系统无法启动等问题，作者概不负责。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;这是一次挺典型的“双系统惊魂”——装完 Debian，开机一看：Windows 盘没了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;硬件环境&lt;/strong&gt;：Dell G3 游戏本，512G NVMe 固态硬盘 + 512G SATA 固态硬盘。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我的操作&lt;/strong&gt;：在一块空闲盘上安装 Debian 13，安装程序选择了“自动分配最大可用空间”。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;当时的现象&lt;/strong&gt;：进 Debian 后用 &lt;code&gt;fdisk -l&lt;/code&gt;、&lt;code&gt;lsblk&lt;/code&gt; 一看，系统里只剩一块 476G 左右的盘（Debian 所在盘），另一块装满数据的 Windows 盘仿佛人间蒸发。&lt;/p&gt;
&lt;p&gt;第一反应当然是：完了，是不是我分区时手滑把 Windows 盘给抹了？&lt;/p&gt;
&lt;p&gt;结论先说在前面：&lt;strong&gt;这次并不是误格式化，也不是硬盘物理损坏，而是 BIOS 的存储模式（Intel RST/RAID On）导致 Linux “看不见”那块盘&lt;/strong&gt;。下面按我当时的排查顺序，把整个过程整理成可复用的修复流程。&lt;/p&gt;
&lt;h3&gt;预备知识&lt;/h3&gt;
&lt;h4&gt;RAID On / Intel RST vs AHCI&lt;/h4&gt;
&lt;p&gt;很多 Dell/联想等笔记本出厂会把存储模式设成 &lt;strong&gt;RAID On（Intel RST）&lt;/strong&gt;。对 Windows 来说这通常“开箱即用”，但对 Debian 这类默认安装来说，可能出现驱动/识别问题，最终表现为：&lt;strong&gt;某些硬盘/控制器在 Linux 下根本不枚举出来&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;而 &lt;strong&gt;AHCI&lt;/strong&gt; 是更通用的模式，Linux 识别支持更稳。&lt;/p&gt;
&lt;h4&gt;为什么 BIOS 能看到、系统却看不到&lt;/h4&gt;
&lt;p&gt;BIOS/UEFI 能看到硬盘，只说明硬盘物理层面没消失。&lt;/p&gt;
&lt;p&gt;操作系统看不到硬盘，通常意味着：控制器工作模式/驱动不匹配、或硬盘被某种固件/阵列逻辑“包”起来了。&lt;/p&gt;
&lt;h3&gt;诊断与修复流程&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;在你确认原因之前，&lt;strong&gt;不要做任何写入磁盘的操作&lt;/strong&gt;，尤其是：&lt;code&gt;mkfs.*&lt;/code&gt;、“重新分区并写入分区表”、各种“修复分区/修复文件系统”的一键工具。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;0. 先确认：是“真没了”还是“系统没识别”&lt;/h4&gt;
&lt;p&gt;先在 Debian 里看一眼系统到底识别到了什么：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsblk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你可能会看到两种情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;只看到一块盘&lt;/strong&gt;：先别慌，下一步去 BIOS 确认是否还能看到另一块盘。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;两块盘都能看到&lt;/strong&gt;：那就不是“磁盘消失”，而是你当时没认对设备名或分区；这篇文章就不是你的 case 了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接下来最关键的一句：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果 BIOS/UEFI 里两块盘都在，但 Debian 里只剩一块，那么大概率不是你把盘格式化了，而是 Linux 没“看见”它。&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;1. 看日志：抓到 RAID/RST 的蛛丝马迹&lt;/h4&gt;
&lt;p&gt;继续在 Debian 里看内核日志，确认控制器工作模式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo dmesg | grep -iE &apos;rst|raid|vmd|nvme|ahci|intel&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你看到了类似 &lt;code&gt;Intel(R) RST&lt;/code&gt;、&lt;code&gt;RAID&lt;/code&gt;、&lt;code&gt;VMD&lt;/code&gt; 等字样，基本就能把锅锁定到 &lt;strong&gt;BIOS 的 RAID On / Intel RST&lt;/strong&gt; 上。&lt;/p&gt;
&lt;p&gt;我当时的关键信息其实就藏在这一段（节选）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[    0.009012] ACPI: ... (v01 INTEL  RstSataE ...)
[    0.009015] ACPI: ... (v01 INTEL  RstSataV ...)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看到 &lt;code&gt;RstSata*&lt;/code&gt;，基本可以把“Linux 看不见另一块盘”与“RST/RAID On”强关联起来。&lt;/p&gt;
&lt;h4&gt;2. 核心修复：BIOS 把 RAID On 改成 AHCI&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：&lt;strong&gt;直接切换模式可能导致 Windows 蓝屏&lt;/strong&gt;（常见为 &lt;code&gt;INACCESSIBLE_BOOT_DEVICE&lt;/code&gt;）。这不是“系统坏了”，而是驱动没有跟着切过来。按我下面的顺序做，通常可以无损解决。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;2.1 修改 BIOS 设置&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;重启电脑，按 &lt;code&gt;F2&lt;/code&gt; 进 BIOS。&lt;/li&gt;
&lt;li&gt;找到 &lt;strong&gt;System Configuration&lt;/strong&gt; -&amp;gt; &lt;strong&gt;SATA Operation&lt;/strong&gt;（有的机型在 Storage 相关菜单）。&lt;/li&gt;
&lt;li&gt;将 &lt;strong&gt;RAID On&lt;/strong&gt; 改为 &lt;strong&gt;AHCI&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;保存并退出。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不同机型进入 BIOS 的按键可能不同，常见还有 &lt;code&gt;Del&lt;/code&gt;、&lt;code&gt;F12&lt;/code&gt;、&lt;code&gt;Esc&lt;/code&gt;，以开机提示为准。&lt;/p&gt;
&lt;h5&gt;2.2 验证硬盘是否回归&lt;/h5&gt;
&lt;p&gt;回到 Debian，再跑一次：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsblk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正常情况下，你会重新看到两块 NVMe 盘（例如 &lt;code&gt;nvme0n1&lt;/code&gt; + &lt;code&gt;nvme1n1&lt;/code&gt;）。Windows 那块盘通常会有较大的 NTFS 分区。&lt;/p&gt;
&lt;p&gt;这里补一句更贴近实际情况的描述：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你的机器可能是 &lt;strong&gt;NVMe + SATA&lt;/strong&gt; 的组合（我就是这种）。那么 Debian 盘可能显示成 &lt;code&gt;sda&lt;/code&gt;，Windows 盘可能显示成 &lt;code&gt;nvme0n1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果 Windows 系统盘开了 &lt;strong&gt;BitLocker&lt;/strong&gt;，Linux 下它不一定显示为 &lt;code&gt;ntfs&lt;/code&gt;，反而会显示成 &lt;code&gt;BitLocker&lt;/code&gt;（见后文）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上面的设备名仅作示例，具体请以你机器上 &lt;code&gt;lsblk&lt;/code&gt; 的实际输出为准。&lt;/p&gt;
&lt;p&gt;我当时 BIOS 改完之后，&lt;code&gt;lsblk&lt;/code&gt; 的关键变化就是：从“只剩 &lt;code&gt;sda&lt;/code&gt;”变成“&lt;code&gt;sda&lt;/code&gt; + &lt;code&gt;nvme0n1&lt;/code&gt; 同时出现”，&lt;code&gt;nvme0n1&lt;/code&gt; 上还有一串典型的 Windows 分区结构。&lt;/p&gt;
&lt;h4&gt;3. 修复引导：让 GRUB 重新发现 Windows&lt;/h4&gt;
&lt;p&gt;硬盘回来了，但 GRUB 启动菜单不一定自动出现 Windows 项。&lt;/p&gt;
&lt;h5&gt;3.1 安装识别工具&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
sudo apt install os-prober grub-efi-amd64
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;3.2 扫描 Windows 启动项&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;sudo os-prober
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;预期会看到类似输出：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Found Windows Boot Manager on /dev/nvmeXn1pY@/EFI/Microsoft/Boot/bootmgfw.efi&lt;/code&gt;&lt;/p&gt;
&lt;h5&gt;3.3 更新 GRUB 配置&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;sudo update-grub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启后，GRUB 菜单里通常就会出现 Windows 选项。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Debian 13 上还有一个小坑：有些情况下 &lt;code&gt;os-prober&lt;/code&gt; 会被默认关闭。&lt;/p&gt;
&lt;p&gt;如果你装好了 &lt;code&gt;os-prober&lt;/code&gt; 但 &lt;code&gt;update-grub&lt;/code&gt; 仍然不扫描 Windows，可以检查 &lt;code&gt;/etc/default/grub&lt;/code&gt; 里是否需要设置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GRUB_DISABLE_OS_PROBER=false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;改完后再运行一次 &lt;code&gt;sudo update-grub&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;4. Windows 蓝屏：&lt;code&gt;INACCESSIBLE_BOOT_DEVICE&lt;/code&gt; 怎么办&lt;/h4&gt;
&lt;p&gt;如果你在 GRUB 里选 Windows 后蓝屏了，核心原因很简单：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 之前按 RAID/RST 模式装的驱动&lt;/li&gt;
&lt;li&gt;现在你切到了 AHCI&lt;/li&gt;
&lt;li&gt;Windows 一时半会儿没切过来，就会“找不到启动盘”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在硬件无物理故障且可进入恢复环境的前提下，通常不需要重装系统。下面两种方式选其一即可。&lt;/p&gt;
&lt;h5&gt;方法 A：进一次安全模式（更省事）&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;蓝屏后等待重启，进入 Windows 的“自动修复/恢复环境”。&lt;/li&gt;
&lt;li&gt;选择：&lt;strong&gt;高级选项&lt;/strong&gt; -&amp;gt; &lt;strong&gt;疑难解答&lt;/strong&gt; -&amp;gt; &lt;strong&gt;启动设置&lt;/strong&gt; -&amp;gt; &lt;strong&gt;重启&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;按 &lt;code&gt;4&lt;/code&gt; 或 &lt;code&gt;F4&lt;/code&gt; 进入 &lt;strong&gt;安全模式&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;只要成功进过一次安全模式，Windows 通常会自动加载 AHCI 相关驱动。&lt;/li&gt;
&lt;li&gt;再重启一次，正常模式即可进入系统。&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;方法 B：用 Windows 安装盘/PE 手动处理（进不去安全模式再用）&lt;/h5&gt;
&lt;p&gt;准备一个 Windows 安装 U 盘或 PE，启动后进入：&lt;strong&gt;修复计算机&lt;/strong&gt; -&amp;gt; &lt;strong&gt;命令提示符&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;执行下面步骤前，建议先备份关键数据（如果当前环境允许读取数据）。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先确认 Windows 分区与 EFI 分区盘符：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;diskpart
list volume
exit
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;修复/重建 EFI 引导（盘符示例：Windows 在 &lt;code&gt;C:&lt;/code&gt;，EFI 在 &lt;code&gt;Z:&lt;/code&gt;）：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;bcdboot C:\Windows /s Z: /f UEFI
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;强制下一次进安全模式（借机触发驱动切换）：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;bcdedit /set {default} safeboot minimal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重启后进入一次安全模式，再执行以下命令取消安全模式循环：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bcdedit /deletevalue {default} safeboot
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;5. （可选）Linux 挂载失败：BitLocker 与快速启动&lt;/h4&gt;
&lt;p&gt;排查过程中我还遇到过这种信息：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/dev/nvme0n1p3: TYPE=&quot;BitLocker&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你在 Linux 下挂载 Windows 分区失败（例如提示 &lt;code&gt;NTFS signature is missing&lt;/code&gt;），先不要急着 &lt;code&gt;ntfsfix&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果分区是 &lt;strong&gt;BitLocker&lt;/strong&gt;：&lt;code&gt;ntfsfix&lt;/code&gt; 对它没意义。&lt;/li&gt;
&lt;li&gt;你要在 Linux 里读写：可以在 Windows 里关闭 BitLocker，或在 Linux 下研究 &lt;code&gt;dislocker&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;你只是要能启动 Windows：通常不需要挂载分区，能被 &lt;code&gt;os-prober&lt;/code&gt; 识别到 EFI 启动项就够了。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;这次事故里，&lt;strong&gt;RST/RAID On&lt;/strong&gt; 负责把硬盘“藏起来”，而 &lt;strong&gt;BitLocker&lt;/strong&gt; 负责把“终于看到硬盘之后的排查体验”一脚踹进地狱。&lt;/p&gt;
&lt;p&gt;它至少背一半锅的理由很简单：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;它让关键分区“不像 NTFS”&lt;/strong&gt;。从 Linux 视角看，大分区不是 &lt;code&gt;ntfs&lt;/code&gt;，而是 &lt;code&gt;TYPE=&quot;BitLocker&quot;&lt;/code&gt;。你如果按传统思路去跑 &lt;code&gt;ntfsfix&lt;/code&gt;、去挂载 &lt;code&gt;ntfs-3g&lt;/code&gt;，很容易得到 &lt;code&gt;NTFS signature is missing&lt;/code&gt; 这种误导性报错，然后开始怀疑“分区表是不是坏了”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;它把“取证”和“救急”都变复杂了&lt;/strong&gt;。在没解密/没拿到恢复密钥之前，你在 Linux 下能做的事情非常有限：既不方便验证分区里到底有没有 Windows，也不方便紧急拷数据（你能看到的往往只有 EFI/恢复分区）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;它让很多“本来能靠直觉解决的问题”失效&lt;/strong&gt;。比如“双系统用户最常用的自救动作”之一就是：先进 Linux 把 Windows 分区挂上来看看文件还在不在——但 BitLocker 直接把这条路堵死了。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我对 BitLocker 的评价是：&lt;strong&gt;这玩意儿就是“排障加难器 + 密钥勒索模拟器”&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;我建议绝大多数普通用户直接关掉 BitLocker&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;如果你是双系统/爱折腾：&lt;strong&gt;更是建议关掉&lt;/strong&gt;，别给自己加一层“未来一定会踩”的坑。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我身边就见过不少真实案例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;电脑没丢、也没被偷，系统也没中毒，最后却因为“恢复密钥忘了/找不到/微软账号对不上”——&lt;strong&gt;数据读不出来、系统进不去，只能重装&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种结局有多离谱？诸位有所不知，根据野史记载，比尔盖茨给家门装了世界级防盗锁，结果小偷没来，&lt;strong&gt;比尔盖茨把钥匙弄丢了&lt;/strong&gt;，然后只能把房子拆了重新盖。&lt;/p&gt;
&lt;p&gt;对大多数日用/游戏本用户来说，它带来的主要收益并不是“安全”，而是：&lt;strong&gt;排障成本 + 跨系统不兼容 + 关键时刻的密钥地狱&lt;/strong&gt;。直接关掉就完事了。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;为了避免大家走弯路，这里把我当时踩到的“误判”也写清楚：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;我一开始把 &lt;code&gt;nvme0n1p3&lt;/code&gt; 当成 NTFS 主分区，去跑了 &lt;code&gt;ntfsfix&lt;/code&gt;，结果直接报：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NTFS signature is missing.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这并不等同于“盘坏了”。后来用 &lt;code&gt;blkid&lt;/code&gt; 一查才发现：&lt;code&gt;nvme0n1p3&lt;/code&gt; 的真实类型是 &lt;code&gt;BitLocker&lt;/code&gt;，它本来就不是裸 NTFS。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当时 &lt;code&gt;blkid&lt;/code&gt; 的结果（节选）大概是这样的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/dev/nvme0n1p1: TYPE=&quot;vfat&quot; LABEL=&quot;ESP&quot;
/dev/nvme0n1p3: TYPE=&quot;BitLocker&quot;
/dev/nvme0n1p4: TYPE=&quot;ntfs&quot; LABEL=&quot;WINRETOOLS&quot;
/dev/nvme0n1p5: TYPE=&quot;ntfs&quot; LABEL=&quot;Image&quot;
/dev/nvme0n1p6: TYPE=&quot;ntfs&quot; LABEL=&quot;DELLSUPPORT&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意这里的 &lt;code&gt;ntfs&lt;/code&gt; 分区大多是恢复/工具分区；真正“装着 Windows 文件”的那块大分区如果启用了 BitLocker，会以 &lt;code&gt;BitLocker&lt;/code&gt; 的形式出现。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;结论就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;要启动 Windows&lt;/strong&gt;：你只需要 EFI 分区（&lt;code&gt;ESP&lt;/code&gt;，vfat）是可见的，GRUB 就能链式引导 Windows Boot Manager；BitLocker 不影响“能不能进 Windows”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;要在 Linux 下读 Windows 大分区&lt;/strong&gt;：就不要再拿 &lt;code&gt;ntfsfix&lt;/code&gt; 去碰 BitLocker 分区了，要么在 Windows 里解密/暂停 BitLocker，要么走 &lt;code&gt;dislocker&lt;/code&gt; 这条路。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;6. （复盘补充）为什么日志里会出现“sdb1/exFAT”的烟雾弹&lt;/h4&gt;
&lt;p&gt;我当时在 &lt;code&gt;dmesg&lt;/code&gt; 里还看到过这样一行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;exFAT-fs (sdb1): Volume was not properly unmounted. Some data may be corrupt.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它很容易让人误以为“第二块盘就是 &lt;code&gt;sdb&lt;/code&gt;”。但实际上这类信息也可能来自 U 盘/移动硬盘等外接设备。&lt;/p&gt;
&lt;p&gt;所以这次复盘给我的一个经验是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dmesg&lt;/code&gt; 里出现某个设备名，并不等于它就是你要找的 Windows 系统盘。&lt;/li&gt;
&lt;li&gt;以 &lt;code&gt;lsblk -o NAME,SIZE,TYPE,FSTYPE,LABEL,MOUNTPOINT&lt;/code&gt; + &lt;code&gt;blkid&lt;/code&gt; 的交叉验证为准，别只盯着某一条日志就下结论。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;小结&lt;/h3&gt;
&lt;p&gt;这次事故最“反直觉”的地方在于：看起来像“我把盘删了”，实际上只是“系统没识别到”。最终结论可以浓缩成三句话：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;BIOS 里盘还在，Linux 里没了：优先怀疑 RST/RAID On。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;切 AHCI 是关键一步&lt;/strong&gt;，但要准备好 Windows 可能蓝屏，按安全模式方案走就行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在没确认原因前不要写盘&lt;/strong&gt;，尤其别碰 &lt;code&gt;mkfs&lt;/code&gt; 这类会直接造成不可逆损失的命令。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;给双系统安装者的建议&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;安装前先看 BIOS：SATA Mode / Disk Operation 尽量选 &lt;strong&gt;AHCI&lt;/strong&gt;，避免 RAID/RST 造成的识别坑。&lt;/li&gt;
&lt;li&gt;关闭 Windows 快速启动：它可能让 NTFS 分区处于“半休眠锁定”状态，Linux 挂载会各种报错。&lt;/li&gt;
&lt;li&gt;真遇到“硬盘消失”，先做只读排查：&lt;code&gt;lsblk&lt;/code&gt;、&lt;code&gt;dmesg&lt;/code&gt;、看 BIOS，再决定下一步。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;谨以此文记录那两个小时的冷汗，以及最后的虚惊一场。&lt;/em&gt;&lt;/p&gt;
</content:encoded></item><item><title>你真的需要 Linux 吗？——Linux 新人避坑指南</title><link>https://blog.sheyiyuan.com/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E6%B5%8B%E8%AF%84/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E6%B5%8B%E8%AF%84/</guid><description>一个从 Windows 到 Arch 再回归 Debian 的真实迁移记录：谁适合 Linux，谁不适合，以及新手最该避开的坑。</description><pubDate>Fri, 06 Feb 2026 08:26:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;免责声明&lt;/strong&gt;
本文基于我个人的长期使用体验（统计学背景，非科班），带有明显主观视角。
我经历过数据丢失、双系统翻车、N 卡驱动崩溃，也在多次重装和迁移后，最终在 Debian 找到了长期可用的方案。
所以这篇文章不是「Linux 一定比 Windows 好」，而是「什么人适合 Linux、什么人不适合，以及你该如何少走弯路」。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;一、为什么很多人想逃离 Windows？&lt;/h3&gt;
&lt;p&gt;最近身边很多朋友问我：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;「Windows 11 越来越卡、广告越来越多，我到底要不要换 Linux？」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个问题我从不敢直接回答「要」或「不要」。&amp;lt;b&amp;gt;因为 Linux 本质上只是一个操作系统——一种与计算机交互、用来解决问题的工具。&amp;lt;/b&amp;gt;我们必须承认：对绝大多数普通电脑用户而言，Linux 这套工具并不顺手。&lt;/p&gt;
&lt;p&gt;Linux 的确更自由，但它给你的不是「无脑顺滑」，而是「可控 + 责任」。&lt;/p&gt;
&lt;p&gt;如果你愿意为系统负责，Linux 会让你觉得电脑终于是自己的；如果你只想开机即用、完全不折腾，Linux 可能会让你痛苦。&lt;/p&gt;
&lt;p&gt;作为一个在 Windows、macOS 和 Linux（Debian / Arch / Mint / Ubuntu / Fedora）之间反复迁移过的人，这篇文章不讲内核黑话，只讲真实经历和可执行建议。&lt;/p&gt;
&lt;h3&gt;二、我的迁移史：从「会用」到「理解」&lt;/h3&gt;
&lt;p&gt;很多人以为 Linux 用户都是一开始就很强。其实我也一样，是边炸边学出来的。&lt;/p&gt;
&lt;h4&gt;1）萌芽期：黑框框的诱惑（2024.06 - 2024.10）&lt;/h4&gt;
&lt;p&gt;为了跑海豹骰子（QQ Bot），我第一次接触服务器上的 CentOS 和 Debian。
那时 Linux 对我只是一个 SSH 终端，但我很快感受到差异：
相比 Windows Server 上繁琐的图形操作，几行 &lt;code&gt;apt install&lt;/code&gt; 就能把环境配好，效率几乎是降维打击。&lt;/p&gt;
&lt;h4&gt;2）觉醒期：Mac 的启示 + Windows 的背刺（2024.10 - 2025.01）&lt;/h4&gt;
&lt;p&gt;换了 MacBook Air M2 以后，类 Unix 的终端体验让我彻底爱上命令行。&lt;/p&gt;
&lt;p&gt;真正的转折点发生在 2025 年 1 月：Windows 在我未保存工作的情况下强制更新重启，直接造成数据丢失。&lt;/p&gt;
&lt;p&gt;我第一次认真尝试双系统，但因为选了旧版本 Debian、又不会换源，软件安装困难、硬件兼容也一塌糊涂。那次失败让我明白了一件事：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux 难的不是系统本身，而是没人给你正确的入门路径。&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;3）狂热期：Arch Linux 与 N 卡战争（2025.02 - 2025.07）&lt;/h4&gt;
&lt;p&gt;不服输的我直接上了 Arch Linux。&lt;/p&gt;
&lt;p&gt;高光时刻是 KDE Plasma 带来的高度自由，加上 Arch Wiki，系统的「底层逻辑」第一次变得清晰可见。&lt;/p&gt;
&lt;p&gt;但代价也很真实：2025 年 7 月，一次常规 &lt;code&gt;pacman -Syu&lt;/code&gt; 后，NVIDIA 驱动崩溃，重启只剩黑屏和闪烁光标。那一晚我在 tty 里抢救系统，才真正理解「滚动更新 + 闭源驱动」的风险。&lt;/p&gt;
&lt;h4&gt;4）归宿期：Debian + GNOME（2025.07 - 至今）&lt;/h4&gt;
&lt;p&gt;经历 Fedora 的节奏不适、Ubuntu 的一些默认设计不合胃口后，我回到了 Debian。&lt;/p&gt;
&lt;p&gt;最后稳定下来的方案是：&lt;strong&gt;Debian Stable + GNOME&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它不是最炫的组合，但对我来说最省心：稳定、可预期、可维护。GNOME 手势也足够接近 macOS 工作流，日常效率非常高。&lt;/p&gt;
&lt;h3&gt;三、Linux 的真相：不是神话，也不是地狱&lt;/h3&gt;
&lt;p&gt;「Linux 已经完全小白化」是神话；「Linux 只有极客能用」也是神话。真相通常在中间。&lt;/p&gt;
&lt;h4&gt;优点：为什么我回不去 Windows&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;掌控权完整&lt;/strong&gt;：没有强制更新、没有系统级广告、没有你不想要却无法彻底关闭的默认行为。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;包管理器非常高效&lt;/strong&gt;：&lt;code&gt;sudo apt install python3&lt;/code&gt; 的体验，通常优于「找官网-下安装包-点下一步-配环境变量」的传统流程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;资源占用更可控&lt;/strong&gt;：在同等硬件上，Linux 通常能跑得更轻、更稳，老设备的续命效果尤其明显。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;缺点：你必须提前接受&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;硬件兼容不是玄学，是成本&lt;/strong&gt;：尤其是 NVIDIA 用户，驱动问题不是「会不会遇到」，而是「什么时候遇到」。前两天我一位朋友想尝试 Linux 双系统，他的 NVIDIA 显卡比较新，开源驱动支持不完善，结果开机直接进不了桌面环境，查了资料后被劝退，最终回到 Windows。就在写这篇文章的过程中，我这台装 Debian 13 的笔记本也遇到过一次屏幕卡死、无响应，重启才恢复。类似问题未必人人都会遇到，但它们足以说明：桌面 Linux 的体验在很大程度上仍然受硬件、驱动和发行版组合影响，稳定性与可预期性并不总是可靠。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;学习曲线不可省略&lt;/strong&gt;：你需要习惯读文档、查 Wiki、看日志，而不是反复重装碰碰运气。之前我在 NAS 上装打印机驱动，在不使用魔法网络的情况下过程非常折腾，最后还是在 PC 上下载文件再传到 NAS 才解决。对熟悉系统的人来说这只是多花时间，但对新手而言，往往意味着「卡住了就不知道下一步该怎么办」的困境。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;软件生态有断层&lt;/strong&gt;：Office、Adobe、某些商业软件没有原生版本，替代方案存在，但迁移习惯需要时间。更深层的问题在于：&lt;strong&gt;对桌面 Linux 来说，「自由」往往意味着更高的综合成本&lt;/strong&gt;——生态更分散、标准更难统一，厂商和开发者的适配动力也更弱。仅桌面环境、发行版差异、图形协议等变量，就足以让一部分软件出现兼容问题；而问题定位又更困难。很多时候 Linux 的适配体验不佳，并不只是「开发者不重视」，也确实有现实约束。举个例子：我之前用 Wails 做了个小工具，在 macOS 和 Windows 上动画很流畅，但在 Linux 上却非常卡顿，最后发现瓶颈在 WebKitGTK 的性能，这类问题对普通应用开发者而言很难从根本上解决。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;四、真正实用的建议：准备入坑该怎么走？&lt;/h3&gt;
&lt;p&gt;以下是我给新手的「低翻车率路径」。&lt;/p&gt;
&lt;h4&gt;1）发行版怎么选&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;先说原则&lt;/strong&gt;：如果你希望开箱即用、不想花时间排障，那么 Linux 很可能不适合作为主力桌面。反过来，如果愿意学习、愿意折腾，那就应该给出可执行的选项，而不是泛泛推荐。&lt;/p&gt;
&lt;p&gt;社区里常见的问题是：大家热衷于谈「某某发行版多好」，却很少把「你该怎么选、选了之后会遇到什么、遇到问题怎么处理」说清楚，这反而会让新手更困惑。即使是那些看起来很厉害的把某某发行版玩出花的大佬，遇到翻车需要修复甚至重装系统也是家常便饭。所以我只推荐我真正用过并能给出具体建议的三个发行版：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux Mint&lt;/strong&gt;：如果你想要开箱即用，这是一个不错的选择，尤其是 Cinnamon 桌面，界面友好，适合 Windows 用户。它基于 Ubuntu，软件硬件的兼容性较好，社区也很活跃。对于新手来说，Linux Mint 的缺点也相当明显：前期不需要命令行的操作可能会让人觉得很顺，但一旦遇到问题，缺乏对系统底层的理解可能会导致修复难度大、甚至需要重装系统。并且他提供的三个桌面环境（Cinnamon、MATE、Xfce）虽然选择多，但也可能让新手在选择上感到迷茫，尤其是当他们不清楚每个桌面环境的特点和适用场景时，容易出现错选桌面环境让体验崩坏。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Debian&lt;/strong&gt;：如果你想要更多的可控性，我推荐 Debian。它的稳定性和包管理系统非常可靠，适合长期使用。并且作为包括 Ubuntu 在内的很多发行版的上游，Debian 的软件库非常丰富，社区也很活跃。代价就是对于新人来说，让 Debian 进一步定制化的难度远超 Arch Linux，虽然可以一定程度享受 Ubuntu 的软件兼容性，但对于不能正确理解原理的新人，可能会把一些不适配 Debian 的配置和教程当成了 Debian 的问题，导致新人陷入按照教程也无法解决后不知所措的困境。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Arch Linux&lt;/strong&gt;：适合那些想要完全掌控系统、愿意投入时间学习的用户。如果想要学习 Linux，Arch 是一个非常好的选择。它的安装过程虽然不友好，但能让你真正理解 Linux 的底层机制。之后转向其他发行版也会更顺利，因为你已经理解了 Linux 的核心概念。代价就是 Arch 的初始门槛非常高，需要投入大量时间来学习安装和维护过程，尤其是对于完全没有 Linux 经验的用户来说，可能会因为一次更新失败导致系统崩溃而感到非常挫败。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么不推荐 Ubuntu 和 Fedora&lt;/strong&gt;：虽然它们也很流行，但我个人觉得它们在默认设计上有一些不太适合新手的地方，比如 Ubuntu 的 Snap 包管理和 Fedora 的更新节奏。并且虽然 Ubuntu 看似社区活跃，但在中文社区大量的「教程」往往是过时的，容易误导新手，这一点上反而不如 Arch Wiki 活跃的中文社区。&lt;/p&gt;
&lt;h4&gt;2）桌面环境怎么选&lt;/h4&gt;
&lt;p&gt;对于选择了 Debian 和 Arch 的用户，桌面环境的选择也很重要。这里我还是优先推荐 GNOME 和 KDE Plasma 这两个老牌桌面环境：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows 用户&lt;/strong&gt;：优先 KDE Plasma，上手成本低，逻辑接近熟悉的桌面范式。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;macOS 用户 / 触控板用户&lt;/strong&gt;：优先 GNOME，手势和工作流更连贯。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我个人非常不建议新手直接上 i3、Sway、niri 这类 tiling window manager，虽然它们很炫，但对新手来说维护成本较高，容易因为配置问题导致系统不可用。&lt;/p&gt;
&lt;h4&gt;3）开装前的最小检查清单&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;先做完整备份，尤其是文档、照片、开发密钥和浏览器数据。&lt;/li&gt;
&lt;li&gt;优先先用 U 盘 Live 模式测试：Wi-Fi、蓝牙、显卡、触控板、睡眠唤醒是否正常。&lt;/li&gt;
&lt;li&gt;新手建议先单系统安装，或至少先在虚拟机熟悉一周，再上双系统。&lt;/li&gt;
&lt;li&gt;准备一个「救援 U 盘」，并提前学会进入 tty 与基础修复命令。&lt;/li&gt;
&lt;li&gt;安装后第一时间配置自动快照/备份策略，别把数据安全寄托在运气上。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;五、谁适合 Linux，谁不适合？&lt;/h3&gt;
&lt;p&gt;你&lt;strong&gt;适合&lt;/strong&gt; Linux，如果你：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;讨厌系统替你做决定，希望掌控更新节奏和系统行为；&lt;/li&gt;
&lt;li&gt;愿意投入一点时间学习命令行、日志和文档；&lt;/li&gt;
&lt;li&gt;工作流以浏览器、代码工具、终端和通用办公为主。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你&lt;strong&gt;暂时不适合&lt;/strong&gt; Linux，如果你：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;强依赖 Adobe 全家桶等特定专业商业软件且无替代方案；&lt;/li&gt;
&lt;li&gt;希望「任何问题都不用自己处理」；&lt;/li&gt;
&lt;li&gt;不愿意承担迁移初期的学习成本。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;结语&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;没有最好的操作系统，只有最适合自己的操作系统。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我从 Windows 逃离，在 Arch 里受挫，最后在 Debian 落地。回头看，这段路真正改变我的，不是「系统更快」这么简单，而是我终于开始主动管理自己的数字生活，而不是被系统默认值牵着走。把使用电脑当成一种「被动接受」的体验，和把她当成「自己管理的工具」与她实现「双向奔赴」的体验，差别是巨大的。&lt;/p&gt;
&lt;p&gt;Linux 很适合作为动手能力强、愿意掌控系统细节的人使用的工作站；它能给你很高的可控性与自由度，但也要求一定的知识储备与学习意愿。对大多数普通用户来说，这个门槛依然真实存在。因此，至少在可预见的未来，Linux 很难成为个人桌面的主流选择。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux 不需要被神话；它更适合在真正需要它的人手中，发挥它应有的价值。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果你也在犹豫要不要换 Linux，希望这篇文章能帮你少踩几个坑：
不必盲目「入教」，也不必因恐惧止步；只要按自己的需求做选择，你就已经走在正确的路上。&lt;/p&gt;
</content:encoded></item><item><title>迟到的2025年度总结</title><link>https://blog.sheyiyuan.com/essays/2026-02-02-5e7ad9e3dd/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/essays/2026-02-02-5e7ad9e3dd/</guid><description>一转眼已经又是一年的时间了。虽然这一年做的事情并不算多，但也算是有一些收获吧。最后还是来总结一下 2025 年的生活和工作吧。</description><pubDate>Mon, 02 Feb 2026 06:45:00 GMT</pubDate><content:encoded>&lt;p&gt;一转眼已经又是一年的时间了。虽然这一年做的事情并不算多，但也算是有一些收获吧。最后还是来总结一下 2025 年的生活和工作吧。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;校内活动&lt;/h2&gt;
&lt;p&gt;校内的活动主要就是年初的统计建模大赛和一如既往的学生会工作了。&lt;/p&gt;
&lt;h3&gt;统计建模大赛&lt;/h3&gt;
&lt;p&gt;统计建模大赛主要还是负责前期规划和代码方面的编程，也是这个契机发现了 GitHub上的一个 b 站 API 合集，对后续的项目开发有很大的帮助。可惜这个仓库 2026 年 1 月被发函了。比赛最后也算是顺利结束了，虽然没有拿到很好的名次，但也算是积累了一些经验。&lt;/p&gt;
&lt;p&gt;大概是我们的选题比较冷门，最后的查重率高达 1.3%，所以感觉没进到国赛也挺正常的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;%E6%9F%A5%E9%87%8D.png&quot; alt=&quot;查重结果&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;学生会工作&lt;/h3&gt;
&lt;p&gt;然后就是不怎么愉快的学生工作了。原本是不准备留任学生会的，打算副部长当完就不留任了，但是看着学生会这边连其他留任的人都没有还是怪可怜的，就又继续留任了一年。虽然留任后感觉书记的工作做起来很枯燥且无味，并且与新的老师和下级部长的对接交流也并不顺畅，但总的来说还是完成了任务。现在基本上就是把手上的工作还是认真做好，等着交接了。&lt;/p&gt;
&lt;p&gt;主要是和新的指导老师不太对得上电波了，感觉工作很累，没有自主权。希望下半学期不要这么痛苦。&lt;/p&gt;
&lt;p&gt;还有另一个比较重要的校内活动是找校内的老师做了一个统计相关的软件项目开发，由我来担任项目负责人，这个在后面章节里面再说吧，这里就不多赘述了。&lt;/p&gt;
&lt;p&gt;学习方面我已经摆烂了，主要是把精力放在了项目开发和个人兴趣上面了。毕竟之后就算要考研，现在统计学 80% 的专业课对我来说也是完全没用。&lt;/p&gt;
&lt;h2&gt;个人项目&lt;/h2&gt;
&lt;p&gt;这一年的个人项目可以用潦草来形容。&lt;/p&gt;
&lt;p&gt;4月的时候跟着教程用 Godot 做了一个类杀戮尖塔的肉鸽卡牌游戏 Demo，虽然完成度不高，但也算是入门了 Godot 的开发流程和 GDScript 的语法。原本计划在这个基础上继续开发下去的，但后来因为各种原因就搁置了:spoiler[那是因为我故障机器人玩多了还没有启动]。&lt;/p&gt;
&lt;p&gt;然后就是 10 月前后，因为沉迷魔裁，做了两个二创的小项目。一个是橘雪莉表情包生成器，原本是面向骰子用户写的插件，后面干脆写了个前端把网页也做了，算是个 Vue 的学习练手项目；另一个是安安素描本，从马克杯大佬的项目 fork 了一份，添加了 Linux/MacOS 支持，然后又改了一份 API 并搭配了骰娘的插件使用。这两个项目还算是有人用。后面我还搭了一个橘雪莉的公骰，把这两个插件都放上去了，果然同人骰热度就是不一样，一周的用户比半拍一年的用户都多了。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Sheyiyuan/ShyeriMeme&quot;}
::github{repo=&quot;Sheyiyuan/Anan-s-Sketchbook-Chat-Box&quot;}
::github{repo=&quot;SheyiyuanTan90/Anan-s-Sketchbook-API&quot;}&lt;/p&gt;
&lt;p&gt;接着是 12 月的时候，我因为不满 b 站的听歌体验，自己写了一个 b 站音乐播放器的项目。因为我:spoiler[和我亲爱的 AI]对 React 和 Golang 相对熟悉,所以我选择了 Wails 作为桌面端框架，前端用 React，后端用 Golang。这个项目目前还在持续开发中，已经实现了基本的听歌功能和播放列表管理功能，现在是我的主力听歌软件。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;Sheyiyuan/Half-Beat-Player&quot;}&lt;/p&gt;
&lt;h2&gt;团队项目&lt;/h2&gt;
&lt;p&gt;今年主要是参与了两个团队项目。一个是 tuanchat（一个 IM 跑团平台），另一个是校内找老师合作的统计软件项目。&lt;/p&gt;
&lt;h3&gt;tuanchat&lt;/h3&gt;
&lt;p&gt;参与 tuanchat 的契机其实很有意思。当时正是 QQ 骰娘遇到比较大危机的时候，我就开始计划想要做一个独立于 QQ 并且比 QQ 好用至少 100 倍的跑团平台。原本我是打算自己找几个朋友一起做的，但是就在准备开始动手的时候，一个朋友找到了 tuanchat 在 b 站发布的早期概念视频，然后就推荐我去看看这个项目。结果一看发现这个项目已经有了比较完整的雏形，并且作者也在积极招募开发者，于是我就加入了这个项目组，开始参与开发工作。然后阴差阳错的从:spoiler[半吊子]后端转职成了:spoiler[三脚猫]前端。&lt;/p&gt;
&lt;p&gt;tuanchat 项目里我认识了很多有趣的朋友，也学到了很多新的技术和知识。也是从这个时候我开始重新搭建我之前已经被废弃了快一年的博客，重新开始。&lt;/p&gt;
&lt;p&gt;::github{repo=&quot;starrybamboo/tuan-chat-web&quot;}&lt;/p&gt;
&lt;h3&gt;校内统计软件项目&lt;/h3&gt;
&lt;p&gt;另一个项目是校内找老师合作的统计软件项目。这个项目主要是为了解决校内某些统计分析工作中遇到的问题，开发一款易用且功能强大的统计软件。作为项目负责人，我主要负责项目的整体规划、团队协调和部分技术实现工作。我找来了在 tuanchat 开发组认识的两个同校来和我一起推进这个项目。这个项目目前还在进行中，预计会在今年年底前完成初步版本的开发。更多的细节这里就不方便透露了。&lt;/p&gt;
&lt;h2&gt;个人生活&lt;/h2&gt;
&lt;h4&gt;旅行&lt;/h4&gt;
&lt;p&gt;今年其实没有怎么出门，唯一值得一提的是五一的时候去了江苏，在南京和南通见了几个朋友，然后因为特种兵旅游回来腿断了一周。别的不说，淮扬菜确实好吃。&lt;/p&gt;
&lt;p&gt;然后是 2026 年 1 月的时候，tuanchat 认识的朋友来了长沙，我们学校的四个 tuanchat 成员就一起带他玩了一圈长沙。运气比较好，这几天长沙的天气都不错，还去了橘子洲头和岳麓山，我感觉还挺开心的:spoiler[那位一起夜爬岳麓山的客人在爬不动的时候可能也会这么想吧？]。&lt;/p&gt;
&lt;h4&gt;兴趣爱好&lt;/h4&gt;
&lt;p&gt;Arch Linux 因为 N 卡驱动挂了两次，然后我又因为没有及时清理快照，把系统弄崩溃了，所以就放弃了。现在主力系统变成了 Debian。有一说一，Debian 的可玩性感觉不比 Arch Linux 差多少，而且稳定性和易用性都更好一些。之后大概会出一期关于我使用 Debian 的体验分享吧（挖坑ing）。&lt;/p&gt;
&lt;p&gt;然后捡了点电子垃圾，给宿舍装了个路由器，让我的 8 个设备可以同时上网。本来打算搞台主机的，可惜内存涨价太厉害了，只能先放弃了。然后花了巨资来买了 4 年的服务器，把我的个人项目和博客都搬到了新服务器上面运行。&lt;/p&gt;
&lt;p&gt;基本掌握了 Novel AI 绘画的使用方法，然后也由此搞了 OC，虽然这么搞会被某些人挂，但是其实没所谓，因为我也不打算和这些人有什么交集。Novel AI 和 Nano Banana 感觉会很快让 AI 绘画普及开来，毕竟门槛真的太低了，未来可期，这个真可以战个未来吧。&lt;/p&gt;
&lt;p&gt;跑团方面，我基本上已经完全从线下团转移到线上团了。毕竟大学就快结束了，线下团也不太现实了。&lt;/p&gt;
&lt;h4&gt;精神状态&lt;/h4&gt;
&lt;p&gt;说实话，从 11 月到现在我写稿的时间里面，我的精神状态一直比较差，也不知道是什么原因。感觉整个人不太能提起精神，做事效率也很低。希望能尽快调整过来吧。这也就是我很长时间没有更新博客的原因了。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;以上，希望明年能更好。也提前祝新年快乐。&lt;/p&gt;
</content:encoded></item><item><title>表情包分享</title><link>https://blog.sheyiyuan.com/essays/2026-02-01-c37dbe69c7/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/essays/2026-02-01-c37dbe69c7/</guid><description>今天整理了一波本人自设的表情包库存，都是 banana 大人的杰作，分享给大家。</description><pubDate>Sun, 01 Feb 2026 13:13:00 GMT</pubDate><content:encoded>&lt;p&gt;今天整理了一波本人自设的表情包库存，都是 banana 大人的杰作，分享给大家。&lt;/p&gt;
&lt;p&gt;欢迎下载收藏使用~&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;./icons/01.png&quot; alt=&quot;icon 01&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/02.png&quot; alt=&quot;icon 02&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/03.png&quot; alt=&quot;icon 03&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;./icons/04.png&quot; alt=&quot;icon 04&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/05.png&quot; alt=&quot;icon 05&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/06.png&quot; alt=&quot;icon 06&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;./icons/07.png&quot; alt=&quot;icon 07&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/08.png&quot; alt=&quot;icon 08&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/09.png&quot; alt=&quot;icon 09&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;./icons/10.png&quot; alt=&quot;icon 10&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/11.png&quot; alt=&quot;icon 11&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/12.png&quot; alt=&quot;icon 12&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;./icons/13.png&quot; alt=&quot;icon 13&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/14.png&quot; alt=&quot;icon 14&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/15.png&quot; alt=&quot;icon 15&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src=&quot;./icons/16.png&quot; alt=&quot;icon 16&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/17.png&quot; alt=&quot;icon 17&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;./icons/18.png&quot; alt=&quot;icon 18&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>Rocky Linux 服务器开荒记</title><link>https://blog.sheyiyuan.com/posts/rocky-linux-%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BC%80%E8%8D%92%E8%AE%B0/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/rocky-linux-%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BC%80%E8%8D%92%E8%AE%B0/</guid><pubDate>Mon, 20 Oct 2025 01:57:00 GMT</pubDate><content:encoded>&lt;p&gt;最近搞了一台新的服务器，打算尝试一下红帽系的发行版，在查了一些资料之后，选择了 Rocky Linux。&lt;/p&gt;
&lt;h3&gt;SSH登陆安全设置&lt;/h3&gt;
&lt;h4&gt;创建普通用户&lt;/h4&gt;
&lt;p&gt;拿到服务器的第一件事就是创建一个非 root 用户。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 创建用户
useradd -md /home/syy -s /bin/bash syy
# 创建一个 home 目录位于 /home/syy，shell 为 bash 的用户 syy

# 设置密码
passwd syy

# 将用户添加到 wheel 组给予管理员权限
usermod -aG wheel syy

# 登陆到新用户
su syy
cd ~
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;禁用 root 用户的 SSH&lt;/h4&gt;
&lt;p&gt;然后我们禁用 root 用户的 SSH。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/ssh/sshd_config
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在文件中找到 &lt;code&gt;PermitRootLogin&lt;/code&gt; 一行，取消注释并修改其值为 &lt;code&gt;no&lt;/code&gt;，保存并退出后重启 SSH 服务。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl restart sshd
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;基础软件安装&lt;/h3&gt;
&lt;h4&gt;基本软件&lt;/h4&gt;
&lt;p&gt;接下来我们来装一些常用的软件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 更新 dnf 并启用 epel 仓库
sudo dnf install epel-release

# 安装常用软件
sudo dnf install git wget screen tmux lsof
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Docker&lt;/h4&gt;
&lt;h5&gt;设置 Docker 官方软件源&lt;/h5&gt;
&lt;p&gt;首先安装用于添加 https 源的依赖。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo dnf install dnf-utils device-mapper-persistent-data lvm2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;添加 docker 官方的 yum 源。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;安装并启用服务&lt;/h5&gt;
&lt;p&gt;安装 docker 引擎和运行时，并启动守护进程。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo dnf install docker-ce docker-ce-cli containerd.io
sudo systemctl enable --now docker
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;1Panel&lt;/h4&gt;
&lt;p&gt;接下来我们安装一个 1Panel 面板。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo bash -c &quot;$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;安装反向代理 caddy&lt;/h4&gt;
&lt;p&gt;这里使用 caddy 是因为 caddy 的性能对于个人场景完全够用，并且可以&lt;strong&gt;自动续签免费 SSL 证书&lt;/strong&gt;（不是自签），主打一个省心。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo dnf install &apos;dnf-command(copr)&apos;
sudo dnf copr enable @caddy/caddy
sudo dnf install caddy
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;WordPress迁移&lt;/h4&gt;
&lt;p&gt;参考 &lt;a href=&quot;https://www.cnblogs.com/linux-xiaofeixiang/p/18946019&quot;&gt;这篇文章&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;简单来说就是在原来的网站安装一个名为 &lt;code&gt;All-in-One WP Migration and Backup&lt;/code&gt; 的插件，然后导出一个 &lt;code&gt;.wpress&lt;/code&gt; 文件。然后我们在新的网站上安装同样的插件导入。&lt;/p&gt;
&lt;p&gt;可能有些同学发现这里有大小限制，但是没有什么关系，这里我们只需要修改文件提高大小限制即可。具体方法如下。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;.htaccess&lt;/code&gt; 文件修改（&lt;code&gt;/var/www/html/wordpress/.htaccess&lt;/code&gt;）增加如下配置：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;php_value upload_max_filesize 1024M 
php_value post_max_size 1024M 
php_value memory_limit 1024M 
php_value max_execution_time 300 
php_value max_input_time 300
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面配置需要加在 BEGIN和END行之间。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;wp-config.php&lt;/code&gt; 修改，增加如下配置：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;@ini_set( &apos;upload_max_filesize&apos; , &apos;1024M&apos; );
@ini_set( &apos;post_max_size&apos;, &apos;1024M&apos;);
@ini_set( &apos;memory_limit&apos;, &apos;1024M&apos; );
@ini_set( &apos;max_execution_time&apos;, &apos;300&apos; );
@ini_set( &apos;max_input_time&apos;, &apos;300&apos; );
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面配置需要加在 &lt;code&gt;require_once ABSPATH . &apos;wp-settings.php&apos;;&lt;/code&gt; 行上方。&lt;/p&gt;
&lt;p&gt;修改完配置后，重新导入就可以了。&lt;/p&gt;
</content:encoded></item><item><title>Linux QQ Bot 部署从入门到入土——以 Debian 12 为例</title><link>https://blog.sheyiyuan.com/posts/linux-qq-bot-%E9%83%A8%E7%BD%B2%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%85%A5%E5%9C%9F-%E4%BB%A5-debian12-%E4%B8%BA%E4%BE%8B/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/linux-qq-bot-%E9%83%A8%E7%BD%B2%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E5%85%A5%E5%9C%9F-%E4%BB%A5-debian12-%E4%B8%BA%E4%BE%8B/</guid><pubDate>Sat, 18 Oct 2025 08:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文所述内容仅作为技术分享，作者不鼓励、不提倡、不支持任何使用本文内容进行违法违规活动的行为；使用相关技术进行的违法违规活动与作者无关。&lt;/p&gt;
&lt;p&gt;为了方便零基础的读者理解，本文中部分定义进行了简化，如果你想要学习更专业的表达和用法，请自行查找相关资料。&lt;/p&gt;
&lt;p&gt;因未理解本文内容而盲目操作造成的损失，作者概不负责。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;前言&lt;/h3&gt;
&lt;p&gt;之前暑假期间在家里搞了一台升腾 C92 的小主机，刷了 Linux 后用来部署 QQ Bot，实际使用效果不错，便把自己原本在云服务器上跑的几个无需公网 IP 的服务迁移到了小主机上。最近又有不少群友来询问我搭建 QQ Bot 相关的问题。于是我准备整理一下从安装到部署的全过程供大家参考。&lt;/p&gt;
&lt;p&gt;本文假设读者有最基本的计算机常识，能够正确理解编辑文件、压缩和解压，能够使用 Windows 或 macOS 完成一般的日常工作。&lt;/p&gt;
&lt;p&gt;本文中绝大部分演示操作将使用&lt;strong&gt;命令行&lt;/strong&gt;而非图形界面或面板。如果需要图形化教程请自行寻找相关文档。&lt;/p&gt;
&lt;h3&gt;预备知识&lt;/h3&gt;
&lt;p&gt;这一节中我们将总结一些关于 Linux、协议、网络安全等领域常见的问题。这一部分建议所有读者阅读。如果你非常赶时间或者已经有一定基础知识，可以先跳过这一部分，等需要时再回来阅读。&lt;/p&gt;
&lt;p&gt;点我跳转到 &lt;a href=&quot;#%E7%B3%BB%E7%BB%9F%E5%AE%89%E8%A3%85%E4%B8%8E%E5%9F%BA%E7%A1%80%E9%85%8D%E7%BD%AE&quot;&gt;下一节&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Linux 及其发行版&lt;/h4&gt;
&lt;p&gt;GNU/Linux 操作系统，通常简称 Linux 操作系统，是一系列基于 GNU 软件和 Linux 内核的操作系统的统称。Linux 和 macOS 一样以 Unix 操作系统为原型，因此有极其稳定、安全的特点（我要点名表扬某个会自动更新然后蓝屏的操作系统了），并且由于核心部分完全开源免费，在服务器上有着大量的应用。&lt;/p&gt;
&lt;p&gt;同时由于 Linux 只要遵守相关开源协议就可以被自由修改、分发，各种在此基础上修改后的版本也层出不穷，这些版本被称为不同的&lt;strong&gt;发行版&lt;/strong&gt;，其中较为出名的有 Ubuntu、Fedora、UOS 等。不同发行版之间虽然大体相似，但是各自的使用方式又有着很大的不同。因此选择适合自己实际需求的发行版是很重要的。&lt;/p&gt;
&lt;p&gt;在本文中，我们将使用 Debian 这一发行版，其中大部分操作对于基于 Debian 的数十种主流发行版（如 Ubuntu、Mint 等）都适用。这里选择 Debian 主要基于其简单稳定、适合新手入门，同时又较为轻量的特点，你也可以根据你的需求使用其他发行版。&lt;/p&gt;
&lt;h4&gt;桌面环境（DE）与电传打字机（tty）&lt;/h4&gt;
&lt;p&gt;tty 就是 Linux 里的「纯文字界面」—— 屏幕只有黑底白字，没有图标、没有窗口，想让电脑干活只能用键盘敲命令（比如输 &lt;code&gt;ls&lt;/code&gt; 看文件），就像早期没有鼠标的老式电脑，这也是本文里我们和小主机交互的主要方式。&lt;/p&gt;
&lt;p&gt;而 Windows 和 macOS 的「桌面环境（DE）」，就是我们平时用的「图形界面」—— 能看到桌面图标、能拖放窗口、能用鼠标点 “此电脑”（Windows）或底部程序坞（macOS），靠点一点、拖一拖就能操作电脑，不用记命令。&lt;/p&gt;
&lt;p&gt;两者的关系很简单：它们都是 “人指挥电脑的工具”，只是操作方式不一样。就像叫外卖，tty 是 “手动输手机号下单”（敲命令），Windows/macOS 的 DE 是 “点屏幕上的商家头像下单”（图形操作），最终目的都是让电脑完成任务，但形式完全不同。&lt;/p&gt;
&lt;p&gt;需要特别说的是：不是有图形的 DE 就更高级。尤其在小主机、服务器上，tty 反而更实用 —— 它占用的内存、CPU 特别少，能省出资源给 QQ Bot 这类核心服务；而且熟练后敲命令比点鼠标快得多，并且可以使用他人为我们准备好的自动化脚本，一条命令能顶反复点鼠标几十次。事实上后面我们在 NapCat 和 MaiBot 的安装过程中，就能够体会到这种方式的便捷。&lt;/p&gt;
&lt;h4&gt;用户与权限&lt;/h4&gt;
&lt;p&gt;很多日常使用 Windows 或 macOS 的同学，对用户和权限概念的理解非常模糊。为了方便大家理解，这里我将用最简单的语言帮助读者了解用户与权限的相关规则。&lt;/p&gt;
&lt;p&gt;对于一般的读者来说，在 Linux 中有两种用户：普通用户和 root 用户（也称为超级管理员）。每个用户都有一个自己的目录，被称为 &lt;code&gt;home&lt;/code&gt; 目录，也称家目录，在终端中常常用 &lt;code&gt;~&lt;/code&gt; 来表示。对于普通用户来说，家目录位于 &lt;code&gt;/home/用户名&lt;/code&gt; 的位置；对于 root 用户来说，家目录位于 &lt;code&gt;/root&lt;/code&gt; 的位置。一般情况下，普通用户只能够对自己家目录下的文件进行修改。为了实现这一点，Linux 有一套权限管理机制。&lt;/p&gt;
&lt;p&gt;用 &lt;code&gt;ls -l&lt;/code&gt; 命令查看文件时，会看到类似这样的信息：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-rwxr-xr-- 1 user group 114514 Sep 11 07:21 file.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;开头的&lt;code&gt;-rwxr-xr--&lt;/code&gt;就是权限：
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;第 1 位&lt;code&gt;-&lt;/code&gt;：表示是文件（&lt;code&gt;d&lt;/code&gt;表示目录）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2-4 位&lt;code&gt;rwx&lt;/code&gt;：&lt;strong&gt;文件所有者（Owner）&lt;/strong&gt; 有读、写、执行权限（能随意操作这个文件）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;5-7 位&lt;code&gt;r-x&lt;/code&gt;：&lt;strong&gt;同组用户（Group）&lt;/strong&gt; 有读和执行权限（能看、能运行，但不能改）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;8-10 位&lt;code&gt;r--&lt;/code&gt;：&lt;strong&gt;其他用户（Others）&lt;/strong&gt; 只有读权限（只能看，不能改也不能运行）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简单来说，Linux 的用户和权限就是通过「给人分组、给文件设规则」，确保系统里的每个资源都被 「合适的人」以 「合适的方式」使用，既灵活又安全。&lt;/p&gt;
&lt;p&gt;我们来举个例子：可以把 Linux 系统理解为一个合租公寓，用户和权限机制就是管理公寓入住和房间使用规则的体系，核心可以简单总结为：「谁（用户）可以对什么东西（文件 / 目录）做什么操作（读 / 写 / 执行）」。&lt;/p&gt;
&lt;h5&gt;用户与用户组&lt;/h5&gt;
&lt;p&gt;Linux 中每一个操作必须由某个用户发起，就像公寓里面每件事都必须要由某个租客来完成。&lt;/p&gt;
&lt;p&gt;超级管理员（root）相当于「房东」，拥有整个公寓（系统）的&lt;strong&gt;最高权限&lt;/strong&gt;，可以随意进入任何房间（访问文件和目录）、修改任何规则（修改访问规则和所有权）、添置公寓设备（安装软件），甚至赶走其他租户（删除用户），拆掉整个公寓（删除系统）。&lt;/p&gt;
&lt;p&gt;普通用户相当于「租客」，只能在自己的房间（家目录）自由活动，对公共区域（如 &lt;code&gt;/usr&lt;/code&gt;、&lt;code&gt;/etc&lt;/code&gt;等目录）的操作会受到限制。&lt;/p&gt;
&lt;p&gt;同时，为了方便资源的管理，Linux 还有用户组（Group）的概念。&lt;/p&gt;
&lt;p&gt;用户组相当于一个「合租室友群」，可以让一个组群中的用户同时享有某些权限。把多个用户加入同一个组，就可以方便地管理他们的共同权限，比如让室友们都能使用客厅的饮水机（某个文件）。&lt;/p&gt;
&lt;h5&gt;权限&lt;/h5&gt;
&lt;p&gt;每个文件 / 目录都有 3 组固定权限，对应「文件所有者（Owner）、同组用户（Group）、其他用户（Others）」三类人，每组权限包含「读（r）、写（w）、执行（x）」三种操作，像房间门上的三把锁。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;读（r，数字 4）&lt;/strong&gt;：可以查看内容，比如打开房间门看一眼里面有什么。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;写（w，数字 2）&lt;/strong&gt;：可以修改内容，比如在房间里摆放家具或扔掉东西。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;执行（x，数字 1）&lt;/strong&gt;：可以运行 / 进入，比如执行一个程序（像启动房间里的洗衣机）或进入一个目录（像走进房间，但无读权限时，即使能进入也看不到里面的文件）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;有时候我们常常遇到 &lt;code&gt;Permission denied&lt;/code&gt; 这样的提示就是因为文件权限不足，这个时候我们一般有两种解决方案：第一种方法是修改文件或目录的权限，让我们可以直接进行操作，这种一般用于从网络下载的默认不允许执行的软件中；第二种方法则是「请」拥有相关权限的用户，通常是超级管理员，来帮我们完成操作，这一过程被称为&lt;strong&gt;提权&lt;/strong&gt;，在实际使用中，我们常常使用 &lt;code&gt;sudo&lt;/code&gt; 软件来帮助我们完成这一操作。&lt;/p&gt;
&lt;h4&gt;绝对路径与相对路径&lt;/h4&gt;
&lt;p&gt;我们要对某个文件或目录进行操作时，需要通过某种方式来定位目标的位置，这个时候就需要用到路径（Path）来表示文件或者目录的位置了。路径通常分为绝对路径和相对路径两种。&lt;/p&gt;
&lt;p&gt;绝对路径是从系统根节点开始的：在 Windows 中，以盘符为根节点，不同目录的层级关系使用反斜杠（&lt;code&gt;\&lt;/code&gt;）表示，如 &lt;code&gt;C:\&lt;/code&gt;；在 Linux 和 macOS 中，以统一的根目录（&lt;code&gt;/&lt;/code&gt;）为唯一根节点，不同目录的层级关系使用斜杠（&lt;code&gt;/&lt;/code&gt;）表示，如 &lt;code&gt;/home/Cecelia/Documents&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;使用绝对路径的好处是我们可以从系统最底层开始找，只要文件还在系统里，我们总能够顺藤摸瓜找到这个文件所在的位置。但是同时其问题也非常明显：如果我的文件所在的目录层数很深的时候，每次我们都要完整地输入一遍绝对路径，这显然是非常麻烦且不优雅的。聪明的人们想到，我能不能先让我位于某个目录的位置，然后从这个位置出发，去查找这个目标文件或目录呢？于是我们就有了另一种表示路径的方式：使用工作目录和相对路径来表示目标文件的位置。&lt;/p&gt;
&lt;p&gt;在相对路径中，我们使用 &lt;code&gt;.&lt;/code&gt; 来表示工作目录，即“当前所处的位置”；使用 &lt;code&gt;..&lt;/code&gt; 来表示上一级目录。用这种方法我们就可以在较深的目录中使用简短的路径。同时相对路径开头的 &lt;code&gt;./&lt;/code&gt; （Windows 中为 &lt;code&gt;.\&lt;/code&gt;）往往可以省略不写。例如我的工作目录为 &lt;code&gt;/home/Cecelia/Documents&lt;/code&gt; 时，想要分别访问 &lt;code&gt;Cecelia&lt;/code&gt; 目录下的 &lt;code&gt;Music&lt;/code&gt; 文件夹和 &lt;code&gt;Documents&lt;/code&gt; 目录下的 &lt;code&gt;Lolita.txt&lt;/code&gt; 时，我们可以用下面路径查找：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Music 文件夹
/home/Cecelia/Music # 绝对路径
../Music # 相对路径
# 圣经.txt
/home/Cecelia/Documents/Lolita.txt # 绝对路径
./Lolita.txt # 相对路径
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样对比下来，我们就能很明显感受到相对路径的简单了。&lt;/p&gt;
&lt;p&gt;不过相对路径对于工作目录的依赖性较高，并且访问浅层目录时可能比绝对路径更加繁琐，有些时候我们仍然需要使用绝对路径。&lt;/p&gt;
&lt;h4&gt;Linux 常用软件和命令&lt;/h4&gt;
&lt;p&gt;我是很不提倡去死记硬背这种东西的，实际上用多了就会发现常用的软件和命令就只有那么一些，下面我们就来介绍一些常用的软件和命令。&lt;/p&gt;
&lt;h5&gt;列出文件 ls&lt;/h5&gt;
&lt;p&gt;这应该是大多数 Linux 新手会接触到的第一个指令。&lt;code&gt;ls&lt;/code&gt; 的作用很简单，它会列出当前目录下的所有文件。同时可以配合其他参数使用，具体的参数感兴趣的读者可以自行查询，通常我们使用 &lt;code&gt;ls -al&lt;/code&gt; 即可，这个指令会列出所有当前目录下文件和文件夹的同时展示文件的大小、所有者、修改时间、权限等常用信息。&lt;/p&gt;
&lt;h5&gt;打印工作目录 pwd&lt;/h5&gt;
&lt;p&gt;这也是常用的一个命令，它的作用是在终端打印输出当前工作目录。&lt;/p&gt;
&lt;h5&gt;切换工作目录 cd&lt;/h5&gt;
&lt;p&gt;这个命令的作用是切换当前工作目录，支持绝对路径和相对路径。输入 &lt;code&gt;cd 目标目录&lt;/code&gt; 即可。&lt;/p&gt;
&lt;h5&gt;编辑文本 nano&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;nano&lt;/code&gt; 是 Debian 操作系统默认的命令行 TUI （TUI 指文本用户界面，区别于图形用户界面 GUI）文本编辑器，使用 &lt;code&gt;nano 文件路径&lt;/code&gt; 即可打开文件。相比于 vi 或者 vim 等编辑器更加适合新手使用。操作总体上和 GUI 下的编辑器相同，使用上下左右方向键移动光标，使用下方的命令进行复制、粘贴、保存、退出等操作。&lt;/p&gt;
&lt;p&gt;如果你想要使用 vim ，请自行查找相关教程，本文不作介绍。&lt;/p&gt;
&lt;h5&gt;移动 / 重命名 mv&lt;/h5&gt;
&lt;p&gt;这个命令的作用是用于移动和重命名文件或文件夹。使用 &lt;code&gt;mv 旧文件路径 新文件路径&lt;/code&gt; 的格式使用，也支持绝对路径和相对路径，可以同时实现文件移动和重命名。&lt;/p&gt;
&lt;h5&gt;复制 cp&lt;/h5&gt;
&lt;p&gt;这个命令的作用是复制文件，如果需要复制文件夹，需要添加 &lt;code&gt;-r&lt;/code&gt; 参数。其他用法和 &lt;code&gt;mv&lt;/code&gt; 完全一致。&lt;/p&gt;
&lt;h5&gt;新建文件夹 mkdir&lt;/h5&gt;
&lt;p&gt;这个命令的作用是新建文件夹，在后面加上要创建的文件夹的路径即可。&lt;/p&gt;
&lt;h5&gt;以管理员身份 sudo&lt;/h5&gt;
&lt;p&gt;这个命令的意义是加载其他命令前，然后使用 root 用户的身份运行这条命令。除非你明确遇到了权限问题，否则不应该使用 &lt;code&gt;sudo&lt;/code&gt; 来执行操作，尤其是删除等高危险操作。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;需要注意的是使用 &lt;code&gt;sudo&lt;/code&gt; 后，在路径中出现的 &lt;code&gt;~&lt;/code&gt; 会被解析为 root 用户的家目录 &lt;code&gt;/root&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;删除 rm&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;rm&lt;/code&gt; 命令的作用是删除文件。&lt;strong&gt;使用此命令删除的文件是不可恢复的！使用此命令删除的文件是不可恢复的！使用此命令删除的文件是不可恢复的！重要的事情说三遍。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果你要删除文件夹，和 &lt;code&gt;cp&lt;/code&gt; 一样请使用 &lt;code&gt;-r&lt;/code&gt; 参数。&lt;/p&gt;
&lt;p&gt;删除操作是极其危险的，如果你不知道你在做什么，不要使用 root 用户身份执行 &lt;code&gt;rm&lt;/code&gt; 命令！使用此命令删除的文件是不可恢复的！&lt;/p&gt;
&lt;h4&gt;包管理器（APT）&lt;/h4&gt;
&lt;p&gt;在Linux中很多应用程序并不能单独运行，它们可能需要使用其他应用的功能来完成一些自己的功能。举一个最简单的例子：如果你希望安装一个图形化的软件，那么你大概率需要先安装&lt;code&gt;qt&lt;/code&gt;、&lt;code&gt;gtk&lt;/code&gt;或者其他类似的图形平台来让软件能够实现图像化。与Windows和macOS上通常将软件本体及其所有依赖打包为一个单独的软件不同，在Linux上几乎所有软件（这里我们不讨论flatpak和AppImage等打包格式）都必须依赖于系统中的其他软件。这样做的好处很明显：假如两个软件A、B都依赖相同的软件C，我们就只需要安装一遍C，就可以同时使用A、B和C三个软件，大大节省磁盘空间。&lt;/p&gt;
&lt;p&gt;但是这样做的坏处也很明显：每次安装软件都需要额外处理大量依赖，这显然是非常庞大的工作量。这时，聪明的你发现，如果有一个程序能够自动读取和处理软件的依赖列表，和当前系统中已有的软件包进行对比，自动补充缺少的软件包，不就解决这个问题了吗？于是，能够自动处理软件安装依赖的工具就诞生了，你给这破玩意儿起名叫做&lt;strong&gt;包管理器&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;和日常用的电脑不同，Linux 操作系统很多时候不能像 Windows、Android 那样点安装包，也不能像 macOS 那样拖动复制安装，而是需要借助包管理器来安装软件。在 Debian 以及其他基于 Debian 的操作系统上，常用包管理工具是 &lt;code&gt;apt&lt;/code&gt;，这一工具我们会在后文多次使用。&lt;/p&gt;
&lt;p&gt;由于包管理器需要对于整个系统的公共文件进行修改，因此需要使用 root 用户权限运行，通常我们在运行时都需要搭配 &lt;code&gt;sudo&lt;/code&gt; 软件使用。&lt;/p&gt;
&lt;p&gt;这里列出一些常见的 &lt;code&gt;apt&lt;/code&gt; 指令：&lt;/p&gt;
&lt;h5&gt;1. 系统更新（前置必做）&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;指令&lt;/th&gt;
&lt;th&gt;功能说明&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;更新本地包索引，获取远程仓库软件最新版本信息（仅更新列表，不升级软件）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt update&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt upgrade&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;升级已安装软件（需手动确认，不删除旧包，不处理复杂依赖冲突）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt upgrade&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt full-upgrade&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;升级软件并自动处理依赖变化（可能删除不兼容旧包，适合跨版本升级）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt full-upgrade&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;2. 软件安装&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;指令&lt;/th&gt;
&lt;th&gt;功能说明&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt install [软件名]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;安装指定单个软件&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt install firefox&lt;/code&gt;（安装火狐浏览器）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt install [软件1] [软件2]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;同时安装多个软件&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt install git vim&lt;/code&gt;（安装 Git 和 Vim）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt install [软件名]=[版本号]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;安装软件指定版本（需先通过 &lt;code&gt;apt show&lt;/code&gt; 确认可用版本）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt install python3=3.8.10-0ubuntu1~20.04.7&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;3. 软件卸载&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;指令&lt;/th&gt;
&lt;th&gt;功能说明&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt remove [软件名]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;删除软件，保留配置文件（重新安装可沿用旧配置）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt remove chrome&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt purge [软件名]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;彻底删除软件及所有相关配置文件（无残留）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt purge chrome&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;4. 软件查询&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;指令&lt;/th&gt;
&lt;th&gt;功能说明&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apt list --installed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;列出系统所有已安装软件（可搭配 &lt;code&gt;grep&lt;/code&gt; 筛选）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apt list --installed | grep python&lt;/code&gt;（筛选已安装的 Python 相关包）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apt show [软件名]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看软件详细信息（版本、依赖、安装大小、描述等）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apt show ubuntu-desktop&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apt search [关键词]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在远程仓库搜索含关键词的软件&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apt search video player&lt;/code&gt;（搜索视频播放器）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apt policy [软件名]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看软件的安装来源和可用版本&lt;/td&gt;
&lt;td&gt;&lt;code&gt;apt policy nginx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;5. 系统清理&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;指令&lt;/th&gt;
&lt;th&gt;功能说明&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt autoremove&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;自动删除“无软件依赖”的无用包（如残留的临时依赖）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt autoremove&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt clean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;清理本地包缓存（删除 &lt;code&gt;/var/cache/apt/archives/&lt;/code&gt; 下所有 &lt;code&gt;.deb&lt;/code&gt; 安装包）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt clean&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt autoclean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;清理本地包缓存（仅删除远程仓库已不存在的旧版本 &lt;code&gt;.deb&lt;/code&gt; 文件）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt autoclean&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5&gt;6. 问题修复&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;指令&lt;/th&gt;
&lt;th&gt;功能说明&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sudo apt -f install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;修复因依赖损坏导致的安装/升级失败（自动补装缺失依赖）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sudo apt -f install&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;网络安全&lt;/h4&gt;
&lt;p&gt;这一部分主要是针对使用服务器或者有公网的用户。请使用服务器的用户务必认真阅读本节内容。&lt;/p&gt;
&lt;h5&gt;IP 地址&lt;/h5&gt;
&lt;p&gt;IP 地址是服务器在网络中的“门牌号”，分为&lt;strong&gt;公网 IP&lt;/strong&gt;和&lt;strong&gt;内网 IP&lt;/strong&gt;，两者在安全属性上差异显著。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心概念区分&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;内网 IP：仅在局域网内可访问（如服务器所在机房、家庭路由器下的 192.168.x.x、10.x.x.x），默认不暴露在公网，安全性较高。&lt;/p&gt;
&lt;p&gt;公网 IP：可被互联网中任意设备访问（如服务器绑定的独立 IP），是服务器与外界交互的入口，也是安全防护的核心靶点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;安全注意事项&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;避免“裸奔”暴露：不要将服务器的公网 IP 随意分享至公开平台（如论坛、社交软件），防止被恶意扫描工具抓取。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;警惕异常访问：定期通过服务器日志（如 Linux 的 &lt;code&gt;/var/log/auth.log&lt;/code&gt;）查看 IP 访问记录，若发现陌生 IP 频繁尝试登录（如 SSH 连接），需及时拦截。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;优选固定公网 IP：若使用云服务器，建议选择固定公网 IP 而非动态 IP，方便后续绑定防火墙规则、域名解析，减少 IP 变动带来的安全配置遗漏。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;防火墙&lt;/h5&gt;
&lt;p&gt;防火墙是服务器的“守门人”，通过预设规则控制进出服务器的网络流量，默认拒绝所有非必要访问，是公网服务器的第一道安全屏障。&lt;/p&gt;
&lt;p&gt;目前主流Linux发行版（如Debian、Ubuntu 20.04+）默认使用&lt;code&gt;ufw&lt;/code&gt;（简单防火墙），操作简单适合新手；部分系统也支持&lt;code&gt;iptables&lt;/code&gt;（功能更强大但配置较复杂），这里重点介绍&lt;code&gt;ufw&lt;/code&gt;的基础用法。&lt;br /&gt;
&lt;strong&gt;核心实操配置（以 ufw 为例）&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;基础状态控制&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;启用防火墙：&lt;code&gt;sudo ufw enable&lt;/code&gt;（启用后重启服务器仍生效，需确保已配置必要端口，避免自己无法登录）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;查看状态与规则：&lt;code&gt;sudo ufw status verbose&lt;/code&gt;（可查看当前允许/拒绝的端口、IP等规则）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关闭防火墙（紧急情况用）：&lt;code&gt;sudo ufw disable&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关键端口配置（遵循“最小必要原则”）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;允许SSH端口（远程登录必备，默认22端口，若修改过端口需替换）：&lt;code&gt;sudo ufw allow 22/tcp&lt;/code&gt;（仅允许TCP协议，减少UDP协议的攻击面）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;允许Web服务端口（如搭建海豹需开放3211端口）：&lt;code&gt;sudo ufw allow 3211/tcp&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;拒绝特定IP：若发现某IP恶意访问，可直接拦截：&lt;code&gt;sudo ufw deny from 192.168.1.100&lt;/code&gt;（将IP替换为实际恶意IP）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安全原则&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不开放无用端口：如服务器不提供FTP服务，就不要开放 21 端口；不开放 3001（NapCat ws 服务器默认端口）给公网，可限制仅允许特定内网 IP 连接。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;定期检查规则：若服务器功能调整（如停用 NapCat Web 服务），需及时删除对应端口规则：&lt;code&gt;sudo ufw delete allow 6099/tcp&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于使用阿里云等平台，需通过云控制台配置防火墙的用户，请自行参考服务商的文档设置安全组，注意事项同上。&lt;/p&gt;
&lt;p&gt;实际上，对于有时间学习的用户，若仅需基础远程登录与 Web 服务，建议只开放 22 端口、80 端口和 443 端口，并合理使用 nginx、caddy 等反向代理来提高安全性。具体操作请自行查找文档，此处不做介绍。&lt;/p&gt;
&lt;h5&gt;鉴权与 Token&lt;/h5&gt;
&lt;p&gt;鉴权是验证“访问者身份是否合法”的过程，Token（令牌）是常用的鉴权方式之一，尤其适用于API接口、Web服务等场景，比传统“账号密码”更灵活安全。&lt;/p&gt;
&lt;p&gt;鉴权的本质是“验证身份”，比如服务器判断登录的用户是否有操作某个文件的权限、某个API请求是否来自合法客户端。&lt;/p&gt;
&lt;p&gt;Token 是一段加密字符串，由服务器（NapCat ws 服务器、MaiBot ws 方向协议、海豹核心与 NapCat Web UI）生成或配置，客户端（如海豹 ws onebot 正向协议、NapCat ws 客户端、浏览器）获取 Token 后，后续访问时携带 Token，服务器通过验证 Token 的有效性来确认身份。&lt;/p&gt;
&lt;p&gt;对于使用服务器、有公网 IP 或使用内网穿透的用户来说，Token（密码）是必须配置的。2025年初以来的多次攻击事件已经给了我们很多血淋淋的教训：未配置 Token 的服务极易成为攻击目标，珍爱 Bot，好好设置 Token。&lt;/p&gt;
&lt;p&gt;关于 SSH：服务器厂商通常已预设安全策略，小主机用户通常无需开放公网 SSH，同时考虑到此内容对于新手来说较为难以理解，此处暂不展开，有余力的读者请自行查找相关文档学习。&lt;/p&gt;
&lt;h3&gt;系统安装与基础配置&lt;/h3&gt;
&lt;p&gt;这一部分中我们将完成 Debian 12 系统的安装。如果你是服务器用户，请直接在镜像中选择 Debian&lt;br /&gt;
12.x （任意 12 版本）后前往 &lt;a href=&quot;#%E5%8D%8F%E8%AE%AE%E7%AB%AF%E9%83%A8%E7%BD%B2&quot;&gt;下一部分&lt;/a&gt; 进行阅读。&lt;/p&gt;
&lt;p&gt;为了方便截图提高大家的阅读体验，安装过程我将使用虚拟机进行演示。针对实体机安装遇到的部分问题，我将单独说明。&lt;/p&gt;
&lt;p&gt;在正式安装前，确保你有以下设备或软件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一台可以工作的电脑&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个不少于 8 GB 的 U 盘或移动硬盘&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一台准备安装 Linux 的小主机&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个供小主机使用的键盘&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一台供小主机使用的显示器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以让小主机访问互联网的网络环境&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Debian 12 系统安装媒介（ISO 文件）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;准备安装引导程序与安装镜像&lt;/h4&gt;
&lt;p&gt;我们需要一个大小不少于8G且没有重要数据的U盘（U盘在制作启动盘时会被格式化，切记提前备份数据！）用来存放系统镜像，常用的这类工具有不少，这里我们以 &lt;a href=&quot;https://www.ventoy.net/cn/index.html&quot;&gt;Ventoy&lt;/a&gt; 为例。&lt;/p&gt;
&lt;p&gt;用这种方法的好处是在安装后如果出现系统级的崩溃和错误，连 tty 都无法进入时可以用安装镜像修复系统错误或者抢救数据。并且 Ventoy 在一次准备后可以存放多个系统镜像，把 Windows 安装媒介和 PE 都放进去，实在是居家旅行必备良品（雾）。&lt;/p&gt;
&lt;p&gt;Ventoy 的具体使用方法参考 &lt;a href=&quot;https://www.ventoy.net/cn/doc_start.html&quot;&gt;官网教程&lt;/a&gt; 或者网上其他文档，没有什么难度，这里不过多介绍。&lt;/p&gt;
&lt;h4&gt;系统安装&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;假如说你在安装过程中遇到了类似 「找不到安装镜像挂载点」之类的报错，大概率是因为你使用了没有分区且未被格式化的硬盘。这种情况下请使用 PE 或者其他设备&lt;strong&gt;格式化&lt;/strong&gt;该硬盘，之后应该就能正常工作了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;0.启动安装程序&lt;/h5&gt;
&lt;p&gt;将准备好的 Debian 安装媒介文件拷入 Ventoy 盘，插入小主机并启动电源。大概会看到下面的界面，部分 CPU 机器可能是 TUI 界面，但内容基本一致。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/ko88ej.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;选择准备好的 Debian 镜像，然后回车。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/kr72x0.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;选择「以正常模式启动」，继续回车。如果你因为某些原因这里失败了，使用第二项「使用 grub2 启动」。接下来进入安装页面。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/ks28g5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;选择第二项「安装」，使用 TUI 安装。个人认为图形化安装并不好用，如果你非要尝试也可以使用。操作是几乎一样的。&lt;/p&gt;
&lt;h5&gt;1.语言与时区&lt;/h5&gt;
&lt;p&gt;选择 English，大部分设备选择中文会出现满屏幕⬜的「口口相传」现象。输入回车确认操作。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/ktukif.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来选择地区，依次选择 &lt;code&gt;other/Asia/China&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lk0o4t.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lkff57.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/ll8sti.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后字符编码和键盘映射都使用默认的美国即可，改为中文会口口相传。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lmuad2.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lnmvis.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;h5&gt;2.网络配置&lt;/h5&gt;
&lt;p&gt;接下来如果你插好了网线，系统会自动为你分配好你的网络设置。如果你使用 Wi-Fi 连接，提前把家中 Wi-Fi 名称改为英文的，然后按照提示输入 Wi-Fi 名称和密码连接即可。&lt;/p&gt;
&lt;p&gt;网络连接这一步根据你的网络情况可能需要十几秒到几分钟，请耐心等待。&lt;/p&gt;
&lt;p&gt;然后进入主机名和域名的配置&lt;/p&gt;
&lt;p&gt;首先是配置主机名，一般默认的系统名即可，你也可以改一个自己喜欢的名字。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lqiufh.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后是域名，使用 localhost 即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lritzc.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;h5&gt;3.设置用户&lt;/h5&gt;
&lt;p&gt;设置并确认 root 密码，这个密码必须记住！这个密码必须记住！这个密码必须记住！如果丢失是很难找回或重置的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lscui6.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lty7q9.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来设置普通用户，输入你的用户名，这里建议全名和用户名都使用纯小写字母组成的短名字，这里我起名为 &lt;em&gt;syy&lt;/em&gt;。然后是同样的设置并确认密码，为了安全，这里请和 root 用户使用不同的密码。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lwe0os.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lwlkmt.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lx2h0g.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lxjr5g.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;h5&gt;4.设置时钟&lt;/h5&gt;
&lt;p&gt;这一步通常系统会自动完成。&lt;/p&gt;
&lt;h5&gt;5.磁盘分区&lt;/h5&gt;
&lt;p&gt;接下来我们要格式化磁盘并进行分区。我们选择「使用一整块硬盘并设置 LVM」。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lza95j.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;选择小主机自己的磁盘，也就是不是 U 盘那一块。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/lzihga.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;分卷这里使用推荐的默认选项即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/m05l4i.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;确认所选磁盘正确后选择 &lt;code&gt;Yes&lt;/code&gt; 和 &lt;code&gt;Continue&lt;/code&gt; 格式化并挂载磁盘。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/m15qwm.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/m1xb2h.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后完成分区并应用到目标磁盘，选择 &lt;code&gt;Yes&lt;/code&gt; 确认。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/m2j1bb.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/m369pz.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;h5&gt;6.安装系统&lt;/h5&gt;
&lt;p&gt;安装程序会自动安装基础系统。过程中会询问我们是否使用网络镜像，我们选择 &lt;code&gt;Yes&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/m4m3e2.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;选择使用的网络镜像源，这里我们选择 &lt;code&gt;China&lt;/code&gt;，如果你在其他地区，选择你所在的地区即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/szr5et.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;选择中科大镜像源（mirrors.ustc.edu.cn），如果速度较慢可以多试几个，选择速度最快的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/t10a4g.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来设置代理，一般留空即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/t1odo3.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来就是漫长的等待 apt 更新，这个过程视你的网络质量需要几十秒到几分钟。&lt;/p&gt;
&lt;p&gt;然后安装程序会询问是否参与 Debian 镜像改进计划，这里选 &lt;code&gt;Yes&lt;/code&gt; 或 &lt;code&gt;No&lt;/code&gt; 都可以。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/t2v882.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来安装程序会让我们勾选需要的软件。这里按 &lt;code&gt;空格&lt;/code&gt; 取消前两项桌面环境；如果你需要使用 SSH 可以勾选，不清楚 SSH 是什么的话只勾选最后一项即可。完成后回车。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/tsc72q.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来等待安装完成，视你的网络情况需要几分钟或者几十分钟。&lt;/p&gt;
&lt;p&gt;这个过程中提示我们安装引导程序界面，选择小主机的系统盘，&lt;strong&gt;不要&lt;/strong&gt;选择 U 盘。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/tua99r.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;耐心等待安装完成后。选择 &lt;code&gt;Continue&lt;/code&gt; 重启电脑，这个时候可以拔出你的 U 盘。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/tvbbdb.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;完成安装&lt;/h4&gt;
&lt;p&gt;重启电脑后，应该可以看到下面的 GRUB 引导界面。按下回车进入系统。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/tw57cz.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;进入登录页面，输入你的用户名，回车后输入密码。注意这里输入密码不会显示，直接回车确认即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/tx87av.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;出现下面的输出表明登录成功，可以开始使用了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/ty8751.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;安装基本软件工具&lt;/h4&gt;
&lt;p&gt;接下来我们安装一些常用软件，首先需要以 root 身份登录来安装 sudo。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;su - # 登录 root 用户

# 这里输入密码时同样不会有任何显示，输入完直接回车即可。

# 安装 sudo
apt install sudo

# 将你的用户加入 sudo 组，这里 syy 需要修改为你自己的用户名
usermod -aG sudo syy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来重新登录普通用户，安装其他软件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 登录用户
su syy # 这里 syy 替换为你的用户名
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在执行 &lt;code&gt;sudo&lt;/code&gt; 的时候会提示我们输入密码，注意这时需要输入当前用户的密码而非 root 用户的密码。&lt;/p&gt;
&lt;p&gt;首先我们要修改 apt 的镜像源，使用网络镜像源而非安装镜像中的软件源。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/apt/sources.list
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;删除第一行的内容即可，然后依次按下 &lt;code&gt;Ctrl + X&lt;/code&gt; 、 &lt;code&gt;Y&lt;/code&gt; 、&lt;code&gt;回车&lt;/code&gt; 保存并退出。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/upbu3p.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后更新软件源。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装中文字体和控制台配置工具，让 tty 能够显示中文。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install fonts-wqy-zenhei zhcon
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置系统 Locale 为 UTF-8。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo dpkg-reconfigure locales
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;找到其中的 &lt;code&gt;zh_CN.UTF-8&lt;/code&gt; 按下&lt;code&gt;Tab&lt;/code&gt; 选中。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/vnm74q.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后选择 &lt;code&gt;zh_CN.UTF-8&lt;/code&gt; 回车确认。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/vod7dv.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来启动 &lt;code&gt;zhcon&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;zhcon --utf8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来 tty 应该就可以正常显示中文了。&lt;/p&gt;
&lt;p&gt;安装 curl、wget 和 git 用于从网络下载文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install curl wget git
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;获取内网 IP 地址&lt;/h4&gt;
&lt;p&gt;后面有很多地方需要用到 Web UI 配置，因此需要先获取内网 IP 地址。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;ip a&lt;/code&gt; 命令查看本机网络配置。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/tb2eb.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里红线部分就是内网 IP 地址，把这个地址记住，后面配置 Web UI 会用到。&lt;/p&gt;
&lt;h3&gt;协议端部署&lt;/h3&gt;
&lt;h4&gt;安装 NapCat&lt;/h4&gt;
&lt;p&gt;这一部分我们简单介绍 NapCat 的安装和使用配置，参考了 &lt;a href=&quot;https://napneko.github.io/guide/boot/Shell#napcat-installer-linux-%E4%B8%80%E9%94%AE%E4%BD%BF%E7%94%A8%E8%84%9A%E6%9C%AC-%E6%94%AF%E6%8C%81ubuntu-20-debian-10-centos9&quot;&gt;NapCat 官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;在小主机中输入下面的命令安装 NapCat ：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -o \
napcat.sh \
https://nclatest.znin.net/NapNeko/NapCat-Installer/main/script/install.sh \
&amp;amp;&amp;amp; bash napcat.sh \
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一项直接回车，第二项输入 &lt;code&gt;y&lt;/code&gt; 后回车（这里图是错的，不用管它）。然后输入你的密码。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/w0bklf.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;耐心等待自动安装程序完成 NapCat 的安装。&lt;/p&gt;
&lt;p&gt;然后使用 &lt;code&gt;napcat help&lt;/code&gt; 查看文档。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/w4vh9s.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;NapCat 启动与网络配置&lt;/h4&gt;
&lt;p&gt;接下来使用 &lt;code&gt;napcat start {QQ}&lt;/code&gt; 启动 NapCat。然后使用 &lt;code&gt;napcat log {QQ}&lt;/code&gt; 查看。&lt;br /&gt;
&lt;img src=&quot;images/wffma.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;找到这里生成的 Token，然后打开浏览器，输入 &lt;code&gt;ip:6099&lt;/code&gt; 访问 Web UI。输入刚才的 Token 并登录。如果你是服务器用户，请前往防火墙或安全组放行 6099 端口入方向。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/xp1wg.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在登录页面选择二维码登录，并扫码登录 QQ 账号。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/1nv026.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;登录后就进入了 Web UI 管理页面。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/1otjxx.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来讲解如何配置代理。不管是 ws 协议还是 http 协议，不管是正向还是反向，配置都是大同小异的，下面我们以 ws 服务器（正向协议）说明如何创建网络配置。&lt;/p&gt;
&lt;p&gt;点击左侧 &lt;code&gt;网络配置/新建/Websocket服务器&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/1qn00p.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/1t1aqj.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;到这里 NapCat 的配置就完成了，去 Bot 应用端连接到协议端即可。&lt;/p&gt;
&lt;h3&gt;海豹核心部署&lt;/h3&gt;
&lt;p&gt;海豹核心在 Linux 上的部署极其简单。下面我们演示一遍完整流程。&lt;/p&gt;
&lt;h4&gt;下载与解压海豹核心&lt;/h4&gt;
&lt;p&gt;首先我们在家目录下创建一个文件夹用于存放海豹。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~
mkdir sealdice
cd sealdice
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后访问海豹官网，找到适宜自己架构的安装包（一般为x86），然后右键选择复制连接。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/1zhky5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在终端输入复制的地址，用 &lt;code&gt;wget&lt;/code&gt; 下载文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget https://d1.sealdice.com/sealdice-core_1.5.1_linux_amd64.tar.gz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;tar&lt;/code&gt; 解压文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tar -xzf ./sealdice-core_1.5.1_linux_amd64.tar.gz
ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;images/221pm1.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;chmod&lt;/code&gt; 为海豹添加可执行权限&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chmod +x ./sealdice-core
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;海豹就已经安装好了。&lt;/p&gt;
&lt;h5&gt;启动海豹核心&lt;/h5&gt;
&lt;p&gt;接下来我们为海豹添加自启动服务。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo ./sealdice-core -i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果没有报错，那么海豹核心就已经开始工作了。打开浏览器，输入 &lt;code&gt;ip:3211&lt;/code&gt; 访问 Web UI。输入刚才的 Token 并登录。如果你是服务器用户，请前往防火墙或安全组放行 3211 端口入方向。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/26a1g1.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果你使用公网服务器，请第一时间按照引导设置一个 Web UI 访问密码。&lt;/p&gt;
&lt;p&gt;接下来介绍一下海豹如何连接分类部署的 NapCat 协议端。&lt;/p&gt;
&lt;p&gt;首先确保你已经参考之前的设置配置好了 NapCat 的 ws 正向服务器。&lt;/p&gt;
&lt;p&gt;在海豹 Web UI 的账号管理处添加一个账号。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/29b75v.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里显示为已连接即为连接成功。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/29tav5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;其他操作和 Windows 上完全一致，不做过多讲解。&lt;/p&gt;
&lt;h5&gt;补充：关于文件管理&lt;/h5&gt;
&lt;p&gt;这里可能就有同学要问了。我如果骰子搬家，我之前的 data 文件夹怎么挂上去呢？&lt;/p&gt;
&lt;p&gt;诶，这个时候就需要我们万能的 NapCat 大人出场了。是的，NapCat 大人自带了一个文件管理面板，我们直接拖动上传即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/2fre65.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;请大家把「NapCat 牛逼！」打在公屏上。&lt;/p&gt;
&lt;p&gt;顺便再回答一下「Linux 上如何解压 &lt;code&gt;zip&lt;/code&gt; 格式文件」的问题。我们需要安装一个 &lt;code&gt;unzip&lt;/code&gt; 软件来解压。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
sudo apt install unzip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后使用 &lt;code&gt;unzip data.zip&lt;/code&gt; 解压即可。&lt;/p&gt;
&lt;p&gt;好了，到此为止关于海豹的常见问题应该就都解决了。&lt;/p&gt;
&lt;h3&gt;MaiBot 部署&lt;/h3&gt;
&lt;p&gt;接下来是 MaiBot 的部署，这里我们还是按照 &lt;a href=&quot;https://docs.mai-mai.org/manual/deployment/mmc_deploy_linux.html&quot;&gt;官方文档&lt;/a&gt; 的步骤来安装。本文只介绍基础安装流程，配置、插件等内容请自行查阅官方文档。&lt;/p&gt;
&lt;h4&gt;预备知识（python）&lt;/h4&gt;
&lt;p&gt;在这里我们要补充讲解一些关于 uv 和 python 的知识。还是老规矩，建议所有读者阅读。如果你非常赶时间或者已经有一定基础知识，可以 &lt;a href=&quot;#%E5%AE%89%E8%A3%85%E5%B9%B6%E9%85%8D%E7%BD%AE-maibot-%E5%8F%8A%E5%85%B6-napcat-%E9%80%82%E9%85%8D%E5%99%A8&quot;&gt;先跳过这一部分&lt;/a&gt;，等需要时再回来阅读。&lt;/p&gt;
&lt;p&gt;先把两个核心概念掰扯清楚：&lt;/p&gt;
&lt;p&gt;下文中，&lt;strong&gt;Python（大写）&lt;/strong&gt; 若无特殊说明，单指 Python 编程语言 —— 就像 “中文”“英文” 是交流的语言规则，Python 是写代码的 “语法规则”，而且只聊 Python 3 及以上版本（老版本早就没人用了，不用管）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;python（小写）&lt;/strong&gt; 则特指 Python 解释器 —— 它是一个实际的软件，作用类似 “翻译机”：你用 Python 语法写的代码（比如让 Bot 发消息、处理群聊的指令），电脑本身看不懂，需要 python 解释器逐行读、逐行解析，再转成电脑能执行的操作。没有它，写好的 Python 代码就是一堆没用的文字。&lt;/p&gt;
&lt;h5&gt;包管理&lt;/h5&gt;
&lt;p&gt;写代码时，没人会从零开始 “造轮子”。比如想让 Bot 发网络请求（调用 AI 接口）、存配置（像 Token、群号），甚至处理群消息里的表情符号，这些常用功能早有人写好了现成的代码，打包成 “工具集” 供人直接用 —— 这些 “工具集” 就是 &lt;strong&gt;Python 包&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;简单说，Python 包就是 “别人做好的代码轮子”。&lt;/p&gt;
&lt;p&gt;在 Python 程序开发和运行时，我们常常需要调用第三方包，而很多包之间也存在和 Linux 软件包类似的依赖关系（看不懂的话，可以回头看前文 &lt;a href=&quot;#%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8apt&quot;&gt;包管理器&lt;/a&gt; 的介绍）。于是人们专门开发了针对 Python 第三方包的包管理器，&lt;code&gt;pip&lt;/code&gt; 就是最典型的一个。&lt;/p&gt;
&lt;p&gt;接下来，你的一切工作似乎的非常顺利，直到……&lt;/p&gt;
&lt;h5&gt;依赖冲突&lt;/h5&gt;
&lt;p&gt;某一天，你运行 Python 程序时发现第三方包 C 用不了，检查后发现：它依赖包 D 的一个旧版本接口，但你系统里的其他包大多只需要 D 的新旧版本都有的接口。这就造成了 &lt;strong&gt;依赖冲突&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，你在依赖说明里添上符合要求的版本，把所有依赖 D 的包的需求取个交集 —— 比如算出来 1.14 版本的 D 刚好满足所有需求，于是用 Python 包管理器把 D 的版本改成了 1.14。&lt;/p&gt;
&lt;h5&gt;不可调和的依赖冲突与依赖污染&lt;/h5&gt;
&lt;p&gt;当某些依赖版本无法同时满足时，只靠“取交集”就不够了。于是你开始把开发依赖放进单独的目录，和系统自带依赖（&lt;code&gt;base&lt;/code&gt; 环境）彻底分开；同时，为每个项目准备独立的一套依赖。&lt;/p&gt;
&lt;p&gt;这个方法就是 &lt;strong&gt;虚拟环境&lt;/strong&gt;。从此，虚拟环境配合包管理器，依赖冲突和依赖污染的问题就好处理多了，可喜可贺～&lt;/p&gt;
&lt;h5&gt;uv&lt;/h5&gt;
&lt;p&gt;现在你已经了解了包管理、虚拟环境的基本概念，接下来介绍 &lt;code&gt;uv&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;uv 是一个 Python 包管理工具，同时具备 Python 版本管理、包管理、虚拟环境管理等功能，比 Python 官方工具更简单、更可靠。&lt;/p&gt;
&lt;p&gt;接下来，我们就用 uv 配置 Python 环境，让 MaiBot 顺利在设备上跑起来。&lt;/p&gt;
&lt;h4&gt;安装并配置 MaiBot 及其 NapCat 适配器&lt;/h4&gt;
&lt;p&gt;首先我们需要安装 uv。使用 uv 官方提供的安装脚本安装 uv。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.local/bin/env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;images/kj0swe.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;现在 uv 就被正确安装了。&lt;/p&gt;
&lt;p&gt;接下来我们使用 uv 安装 python3.12 版本——这是 MaiBot 官方推荐的版本。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;由于 Python 的一些问题，有时候使用最新版本的 Python 反而容易产生一些问题，如果你没有排查错误的能力，这里使用旧版本即可。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;uv python install 3.12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后我们下载 MaiBot 的代码到本地。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ~
mkdir ./maimai
cd ./maimai
git clone https://github.com/MaiM-with-u/MaiBot.git
git clone https://github.com/MaiM-with-u/MaiBot-Napcat-Adapter.git
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;安装依赖&lt;/h5&gt;
&lt;p&gt;首先为 MaiBot 核心创建虚拟环境并安装依赖。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uv venv --python 3.12
cd MaiBot
uv pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple --upgrade
# 创建文件夹
mkdir config
# 复制并重命名配置文件
cp template/bot_config_template.toml config/bot_config.toml
cp template/model_config_template.toml config/model_config.toml
cp template/template.env .env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来为 NapCat 适配器创建虚拟环境并安装依赖，同时启用配置文件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd ../MaiBot-Napcat-Adapter
uv pip install -i https://mirrors.aliyun.com/pypi/simple -r requirements.txt --upgrade
# 复制并重命名文件
cp template/template_config.toml config.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最终文件结构应该如图：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;maimai
├── .venv # 虚拟环境
├── MaiBot # MaiBot 核心
│&amp;amp;nbsp;&amp;amp;nbsp; ├── changelogs
│&amp;amp;nbsp;&amp;amp;nbsp; ├── config
│&amp;amp;nbsp;&amp;amp;nbsp; ├── data
│&amp;amp;nbsp;&amp;amp;nbsp; ├── depends-data
│&amp;amp;nbsp;&amp;amp;nbsp; ├── src
│&amp;amp;nbsp;&amp;amp;nbsp; │&amp;amp;nbsp;&amp;amp;nbsp; └── ...
│&amp;amp;nbsp;&amp;amp;nbsp; └── template
└── MaiBot-Napcat-Adapter # MaiBot NapCat 适配器
    ├── config.toml
    └── template
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;配置 NapCat&lt;/h5&gt;
&lt;p&gt;这里 NapCat 的配置方法已经在前文讲述此处不再赘述。&lt;/p&gt;
&lt;h5&gt;启动&lt;/h5&gt;
&lt;p&gt;之后的启动流程参考 &lt;a href=&quot;https://docs.mai-mai.org/manual/deployment/mmc_deploy_linux.html#%E5%90%AF%E5%8A%A8%E9%BA%A6%E9%BA%A6&quot;&gt;官方文档&lt;/a&gt; 的内容。&lt;/p&gt;
&lt;h5&gt;补充：编写自动化运行脚本&lt;/h5&gt;
&lt;p&gt;这里我们每次都输入一大堆指令显得非常麻烦，这里我为了偷懒编写了两份快速启动的脚本，贴出来供大家参考。&lt;/p&gt;
&lt;p&gt;使用本脚本前请先安装一些依赖：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
sudo apt install tmux
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后编写下面两个文件：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;maibot.sh&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# 定义会话名称
SESSION_NAME=&quot;maibot&quot;
# 定义执行命令的目录
EXECUTION_DIR=&quot;${HOME}/maimai&quot;
# 定义要执行的命令
COMMAND=&quot;.venv/bin/activate &amp;amp;&amp;amp; cd \&quot;${EXECUTION_DIR}/MaiBot\&quot; &amp;amp;&amp;amp; uv run python3 bot.py&quot;

# 检查执行目录是否存在
if [ ! -d &quot;$EXECUTION_DIR&quot; ]; then
    echo &quot;错误：执行目录 $EXECUTION_DIR 不存在！&quot;
    exit 1
fi

# 检查会话是否已经存在
if ! tmux has-session -t &quot;$SESSION_NAME&quot; 2&amp;gt;/dev/null; then
    # 会话不存在，创建新会话并在指定目录下运行命令（cd失败则退出）
    tmux new-session -d -s &quot;$SESSION_NAME&quot; \
        &quot;cd \&quot;$EXECUTION_DIR\&quot; &amp;amp;&amp;amp; $COMMAND || read -p &apos;命令执行失败，按任意键退出...&apos;&quot;
    echo &quot;会话 $SESSION_NAME 创建成功。&quot;
else
    # 会话已存在，提示信息
    echo &quot;会话 $SESSION_NAME 已存在，正在连接...&quot;
fi

# 连接到会话
tmux attach -t &quot;$SESSION_NAME&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;adapter.sh&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/bash

# 定义会话名称
SESSION_NAME=&quot;maibot&quot;
# 定义执行命令的目录（展开~为绝对路径，避免tmux环境中路径解析问题）
EXECUTION_DIR=&quot;${HOME}/maimai&quot;
# 定义要执行的命令（使用绝对路径更可靠）
COMMAND=&quot;.venv/bin/activate &amp;amp;&amp;amp; cd \&quot;${EXECUTION_DIR}/MaiBot-Napcat-Adapter\&quot; &amp;amp;&amp;amp; uv run python3 main.py&quot;

# 检查执行目录是否存在
if [ ! -d &quot;$EXECUTION_DIR&quot; ]; then
    echo &quot;错误：执行目录 $EXECUTION_DIR 不存在！&quot;
    exit 1
fi

# 检查会话是否已经存在
if ! tmux has-session -t &quot;$SESSION_NAME&quot; 2&amp;gt;/dev/null; then
    # 会话不存在，创建新会话并在指定目录下运行命令（cd失败则退出）
    tmux new-session -d -s &quot;$SESSION_NAME&quot; \
        &quot;cd \&quot;$EXECUTION_DIR\&quot; &amp;amp;&amp;amp; $COMMAND || read -p &apos;命令执行失败，按任意键退出...&apos;&quot;
    echo &quot;会话 $SESSION_NAME 创建成功。&quot;
else
    # 会话已存在，提示信息
    echo &quot;会话 $SESSION_NAME 已存在，正在连接...&quot;
fi

# 连接到会话
tmux attach -t &quot;$SESSION_NAME&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后启动时我们只需要运行这两个脚本即可。&lt;/p&gt;
&lt;p&gt;要从会话中退出，请使用 &lt;code&gt;Ctrl+b&lt;/code&gt; 然后输入 &lt;code&gt;d&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;结尾和碎碎念&lt;/h3&gt;
&lt;p&gt;这篇文章大概是我目前写过最长的一篇文章。可能有读者已经发现，很多地方都参考了各类软件的官方文档。但我写这篇文章的目的，还是希望用自己摸索出来的经验，帮助更多之前从未接触过 Linux 和命令行的新人学到一些基础知识。&lt;/p&gt;
&lt;p&gt;我在 2024 年初开始接触 Linux，就是因为搭 Bot 时听说 NapCat 在 Linux 上运行更稳定。于是便开始研究，但我既不是科班出身，身边也几乎没人使用 Linux 系统。可以说，我就是在“抓瞎”中一点点摸索出了一些基本知识。在这个过程中，也遭受过一些闲言碎语：「不会 Linux 你用什么 Linux？」「这些都是基础知识，你自己去看手册。」然后我一边在网上各种资料里翻找，一边拼凑出自己需要的那部分信息。可能是我不太聪明，大概在这种痛苦里挣扎了快两个月，才理解了一些相对底层的概念。&lt;/p&gt;
&lt;p&gt;因此，为了不让和当初的我一样、初次接触 Linux 的新手在面对海量资料时感到无所适从，我写了这篇文章。不解释太多额外知识，但尽量讲清楚一些最基础、最底层的概念，帮助新人理解大部分操作背后的意义，而不是只会复制粘贴代码然后对着报错发呆。&lt;/p&gt;
&lt;p&gt;当然，由于我个人能力有限和种种因素，本文也难免存在一些不足和错误，还请各位读者批评指正。&lt;/p&gt;
&lt;p&gt;希望大家都能搭出属于自己的 Bot。&lt;/p&gt;
</content:encoded></item><item><title>WinApps——Linux日用的最后一块拼图</title><link>https://blog.sheyiyuan.com/posts/winapps-linux%E6%97%A5%E7%94%A8%E7%9A%84%E6%9C%80%E5%90%8E%E4%B8%80%E5%9D%97%E6%8B%BC%E5%9B%BE/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/winapps-linux%E6%97%A5%E7%94%A8%E7%9A%84%E6%9C%80%E5%90%8E%E4%B8%80%E5%9D%97%E6%8B%BC%E5%9B%BE/</guid><pubDate>Tue, 07 Oct 2025 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;尽管目前 Linux 的软件生态已经是一片勃勃生机、万物竞发的景象犹在眼前，但是我们仍然面对 Office、Photoshop 等部分软件不得不使用 Windows 环境来运行的情况。Wine 对于部分软件来说仍然有兼容性问题，而直接使用虚拟机又显得不太方便。这个时候我们的 WinApps 出场了，WinApps 使用远程桌面协议（RDP）直接与我们需要使用的 Windows 软件交互，让我们可以不必打开 VM 就直接使用软件，也不用再在虚拟机内与 Windows 桌面交互了。&lt;/p&gt;
&lt;p&gt;下面我们以 &lt;code&gt;Photoshop&lt;/code&gt; 为例，演示 WinApps 的使用方法。&lt;/p&gt;
&lt;h2&gt;安装虚拟机管理器&lt;/h2&gt;
&lt;p&gt;首先我们要安装一个虚拟机管理器，这部分请参考&lt;a href=&quot;/posts/arch-linux%E4%B8%AD%E7%9A%84%E8%99%9A%E6%8B%9F%E6%9C%BAkvm-%E8%BD%AF%E4%BB%B6%E5%AE%89%E8%A3%85/&quot;&gt;上期内容&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;然后在虚拟机管理器的&lt;code&gt;编辑-首选项&lt;/code&gt;勾选前两项：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/txs4ug.png&quot; alt=&quot;在首选项中选择启用xml编辑和系统托盘图标&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;虚拟机安装 Windows&lt;/h2&gt;
&lt;h3&gt;准备安装镜像&lt;/h3&gt;
&lt;p&gt;我们需要准备两个安装镜像，一个是 Windows 系统安装镜像，另一个是 Windows 虚拟驱动的安装镜像 &lt;code&gt;virtio-win&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Windows 安装镜像请前往微软官网下载，而驱动这里我们选择 &lt;a href=&quot;https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.285-1/&quot;&gt;Fedora 的镜像站&lt;/a&gt; 下载其中的 &lt;code&gt;virtio-win.iso&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这里我以 Windows 11 为例进行安装。&lt;/p&gt;
&lt;h3&gt;安装过程&lt;/h3&gt;
&lt;p&gt;首先我们打开虚拟机管理器，选择 &lt;code&gt;文件-新建虚拟机-本地安装介质&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/u37dq2.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;选择本地 Windows 系统镜像；&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/u4i8ai.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来两步按照你的电脑配置自己确定大小，内存不建议低于4G；&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/u7sa1v.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;完成之后，我们还需要做一些别的配置：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在 &lt;code&gt;CPU&lt;/code&gt; 选项中启用 &lt;code&gt;复制主机CPU配置&lt;/code&gt; 并打开 XML，确保 &lt;code&gt;clock&lt;/code&gt; 一项与下面一致：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;  &amp;lt;clock offset=&quot;localtime&quot;&amp;gt;
    &amp;lt;timer name=&quot;rtc&quot; tickpolicy=&quot;catchup&quot;/&amp;gt;
    &amp;lt;timer name=&quot;pit&quot; tickpolicy=&quot;delay&quot;/&amp;gt;
    &amp;lt;timer name=&quot;hpet&quot; present=&quot;yes&quot;/&amp;gt;
    &amp;lt;timer name=&quot;hypervclock&quot; present=&quot;yes&quot;/&amp;gt;
  &amp;lt;/clock&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在&lt;code&gt;引导选项&lt;/code&gt;选项中，启用&lt;code&gt;主机引导时启动虚拟机&lt;/code&gt;；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;SATA Disk 1&lt;/code&gt; 选项中，选择&lt;code&gt;VirtIO&lt;/code&gt;作为磁盘总线；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在&lt;code&gt;NIC&lt;/code&gt;选项中，将&lt;code&gt;设备型号&lt;/code&gt;设置为&lt;code&gt;VirtIO&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;单击屏幕左下角的&lt;code&gt;添加硬件&lt;/code&gt;按钮，然后选择&lt;code&gt;存储-CDROM&lt;/code&gt;作为设备类型，然后在&lt;code&gt;管理&lt;/code&gt;处选择准备好的&lt;code&gt;virtio-win.iso&lt;/code&gt;文件；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;再添加一个TPM设备，否则无法安装win11。&lt;br /&gt;
&lt;img src=&quot;images/uijnok.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;配置好后点击左上按钮开始安装。&lt;/p&gt;
&lt;p&gt;无脑下一步+和我的“我没有产品密钥”说去吧。&lt;/p&gt;
&lt;p&gt;映像选择专业版。&lt;/p&gt;
&lt;p&gt;在安装win11的位置这里选择&lt;code&gt;Load Driver&lt;/code&gt;然后挂载驱动&lt;code&gt;E:\viostor\win11\amd64&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/vvft62.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/h6a6bx.png&quot; alt=&quot;截图 2025-10-07 19-29-52&quot; /&gt;&lt;/p&gt;
&lt;p&gt;选中后点击安装，接下来就能够找到磁盘了，继续安装即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/vxtxhf.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;进入引导页面后，我们开始配置win11&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/w0a5hh.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;按住&lt;code&gt;shift+f10&lt;/code&gt;打开命令提示符，输入&lt;code&gt;oobe\bypassnro&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/w2rep5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;选择&lt;code&gt;我没有网络连接&lt;/code&gt;&lt;br /&gt;
&lt;img src=&quot;images/w39ovr.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;之后设置账户和密码并拒绝所有隐私服务即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/w52igv.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;进入系统后我们安装虚拟驱动，打开文件管理器找到&lt;code&gt;E:/virtio-win-guest-tools&lt;/code&gt;安装驱动&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/h5oiy3.png&quot; alt=&quot;截图 2025-10-07 19-44-55&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;虚拟机的其他配置&lt;/h2&gt;
&lt;p&gt;用浏览器打开&lt;code&gt;https://github.com/Fmstrat/winapps/blob/main/install/RDPApps.reg&lt;/code&gt;，下载该文件。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/w9mdwx.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;打开文件，&lt;code&gt;右键-更多选项-合并&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/waek3m.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;修改完注册表后我们还要修改设备名称，前往&lt;code&gt;设置-系统-系统信息-重命名这台电脑&lt;/code&gt;为设备重命名为&lt;code&gt;RDPWindows&lt;/code&gt;，下一步，之后选择&lt;code&gt;稍后重新启动&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/wcm4rd.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;之后打开远程桌面，开启远程桌面，这里的名字还没有更改也没关系，等重启就好了。然后记得打开防火墙。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/wdwx19.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;现在我们可以安装需要的windows软件了，这里我安装了&lt;code&gt;PhotoShop&lt;/code&gt;，安装包使用的是学校提供的正版安装包。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/xu5v34.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接下来打开&lt;code&gt;cmd&lt;/code&gt;输入命令ipconfig查看虚拟机ip并记录。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/yrmzy7.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在做好所有准备工作后重启电脑，但不要登录。关闭查看器和虚拟机管理器。&lt;/p&gt;
&lt;h2&gt;准备WinApps For Linux&lt;/h2&gt;
&lt;p&gt;首先安装&lt;code&gt;freerdp&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S freerdp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后RDP测试连接是否正常：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;xfreerdp3 /u:&quot;用户名&quot; /p:&quot;密码&quot; /v:192.168.122.101 /cert:tofu #ip替换为你虚拟机的实际ip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果出现了窗口，说明连接正常，接下来关掉窗口开始安装&lt;code&gt;WinApps&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/yy0y18.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;创建&lt;code&gt;WinApps&lt;/code&gt;配置目录和配置文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir ~/.config/winapps
vim ~/.config/winapps/winapps.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将下面内容写入配置文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RDP_USER=&quot;用户名&quot; 
RDP_PASS=&quot;密码&quot;
RDP_IP=&quot;&quot;
VM_NAME=&quot;RDPWindows&quot;
WAFLAVOR=&quot;libvirt&quot;
RDP_SCALE=&quot;100&quot;
RDP_FLAGS=&quot;/cert:tofu /sound /microphone +home-drive&quot;
DEBUG=&quot;true&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改文件权限：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chmod 600 ~/.config/winapps/winapps.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行WinApps安装脚本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bash &amp;lt;(curl https://raw.githubusercontent.com/winapps-org/winapps/main/setup.sh)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前面三项依次选择：&lt;code&gt;Install&lt;/code&gt; &lt;code&gt;Current User&lt;/code&gt; &lt;code&gt;Manual&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;跳过官方软件：&lt;br /&gt;
&lt;img src=&quot;images/10ssy9p.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;手动选择其他软件：&lt;br /&gt;
&lt;img src=&quot;images/h4zzbl.png&quot; alt=&quot;截图 2025-10-07 22-25-38&quot; /&gt;&lt;/p&gt;
&lt;p&gt;按下空格勾选我们需要的软件：&lt;br /&gt;
&lt;img src=&quot;images/10u52fo.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里可能自动设置环境变量失败，如果失败了需要手动添加：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &apos;export PATH=~/.local/bin:$PATH&apos; &amp;gt;&amp;gt; ~/.zshrc &amp;amp;&amp;amp; source ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在我们就可以在菜单里看到PhotoShop了：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/12dhqmh.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>Arch Linux中的虚拟机</title><link>https://blog.sheyiyuan.com/posts/arch-linux%E4%B8%AD%E7%9A%84%E8%99%9A%E6%8B%9F%E6%9C%BAkvm-%E8%BD%AF%E4%BB%B6%E5%AE%89%E8%A3%85/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/arch-linux%E4%B8%AD%E7%9A%84%E8%99%9A%E6%8B%9F%E6%9C%BAkvm-%E8%BD%AF%E4%BB%B6%E5%AE%89%E8%A3%85/</guid><pubDate>Wed, 01 Oct 2025 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在很多时候我们会因为各种原因需要使用一些别的操作系统上的环境，在实体机上安装多个系统切换每次都需要开关机，而且文件传输也是一个问题，这个时候虚拟机就是我们的不二选择了。由于我最近正好在准备写关于系统安装的一些教程，虚拟机也能方便我准备图片素材，所以这一期我们就来讲解一下如何在Arch Linux上使用虚拟机。&lt;/p&gt;
&lt;h2&gt;硬件检查&lt;/h2&gt;
&lt;p&gt;在开始安装之前，我们首先要开启 CPU 对虚拟化的支持。KVM 依赖于 CPU 的虚拟化技术（如 Intel 的 &lt;code&gt;Intel VT-x&lt;/code&gt; 和 AMD 的 &lt;code&gt;AMD-V&lt;/code&gt;），使用下面的指令查看虚拟化是否开启：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grep -E &apos;vmx|svm&apos; /proc/cpuinfo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果出现了相关内容表示虚拟化已开启，否则需要手动进入BIOS开启虚拟化，由于各品牌主板进入BIOS的方法不同，具体设置方法也有差异，这里请读者在服务商网站上自行查找开启虚拟化的方法，此处不再赘述。&lt;/p&gt;
&lt;h2&gt;安装KVM及其依赖&lt;/h2&gt;
&lt;p&gt;输入下面指令更新并安装KVM需要的包：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -Syu
sudo pacman -S qemu-full libvirt virt-manager bridge-utils vde2 dnsmasq
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装好后启动并设置开机自启服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable --now libvirtd
sudo systemctl enable --now virtlogd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;自动开启网络：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo virsh net-start default
sudo virsh net-autostart default
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;添加用户权限&lt;/h2&gt;
&lt;p&gt;将当前用户添加到 &lt;code&gt;libvirt&lt;/code&gt; 组，避免每次使用 sudo：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo usermod -a -G libvirt $(whoami)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编辑配置文件提高权限：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/libvirt/qemu.conf
# 把 user = &quot;libvrit-qemu&quot; 改为 user = &quot;你的用户名&quot;
# 把 group = &quot;libvirt-qemu&quot; 改为 group = &quot;libvirt&quot;
# 取消这两行注释
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在shell配置文件中添加默认uri：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vim ~/.zshrc
# 在文件尾部写入： export LIBVIRT_DEFAULT_URI=&quot;qemu:///system&quot;
source ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来打开虚拟机管理器即可开始管理虚拟机。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;images/ka41fb.png&quot; alt=&quot;KVM可视化管理器&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>Arch Linux中的Conda</title><link>https://blog.sheyiyuan.com/posts/arch-linux%E4%B8%AD%E7%9A%84conda/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/arch-linux%E4%B8%AD%E7%9A%84conda/</guid><pubDate>Tue, 30 Sep 2025 08:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;说明：本文中的例子大多为了方便说明进行了简化，不代表实际问题情形和实际解决方案，如需要严谨的定义和解决方案，请自行查阅相关文档。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;使用前必读&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;conda&lt;/code&gt;是一个非常泛用且方便的包管理工具，尤其在科学计算、机器学习、统计分析等科研场景下，它可以帮助我们非常方便地处理各种依赖。&lt;/p&gt;
&lt;p&gt;但是在Linux中，&lt;strong&gt;在&lt;code&gt;base&lt;/code&gt;环境中使用&lt;code&gt;conda&lt;/code&gt;是非常危险的&lt;/strong&gt;，对于刚开始使用Linux的用户必须要清楚地意识到这一点。&lt;/p&gt;
&lt;p&gt;我们在正式开始学习如何在Arch Linux上使用&lt;code&gt;conda&lt;/code&gt;之前，请务必认真理解本节所讲述的内容。&lt;/p&gt;
&lt;h4&gt;包管理&lt;/h4&gt;
&lt;p&gt;在Linux中很多应用程序并不能单独运行，它们可能需要使用其他应用的功能来完成一些自己的功能，举一个最简单的例子，如果你希望安装一个图形化的软件，那么你大概率需要先安装&lt;code&gt;qt&lt;/code&gt;、&lt;code&gt;gtk&lt;/code&gt;或者其他类似的图形平台来让软件能够实现图像化。与Windows和macOS上通常将软件本体及其所有依赖打包为一个单独的软件不同，在Linux上几乎所有软件（这里我们不讨论flatpak和AppImage等打包格式）都必须依赖于系统中的其他软件，这样做的好处是很明显的，假如两个软件A、B都依赖相同的软件C，我们就只需要安装一遍C就可以实现同时使用A、B和C三个软件，大大节省了磁盘空间。&lt;/p&gt;
&lt;p&gt;但是这样做的坏处也很明显，我每次安装软件都需要去额外处理大量的依赖，这显然是非常庞大的工作量。这时，聪明的你发现，如果有一个程序能够自动读取和处理软件的依赖列表，和当前系统中已有的软件包进行对比，自动补充缺少的软件包，不就解决这个问题了吗。于是，能够自动处理软件安装依赖的工具就诞生了，你给这破玩意儿起名叫做&lt;strong&gt;包管理器&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;包管理器可以在安装软件时快速处理软件的依赖，让我们只用一行命令就可以完成安装。Linux的大部分软件需要我们使用包管理器来进行安装，例如在Arch Linux中，我们使用&lt;code&gt;pacman&lt;/code&gt;作为包管理器。&lt;/p&gt;
&lt;p&gt;在开发中，我们也常常需要调用第三方库来进行开发，而很多库之间也存在类似的依赖关系。聪明的你又想到，刚才的包管理器不也可以在这里使用吗？于是你又发明了一个额外的包管理器来处理开发中的第三方库，而&lt;code&gt;conda&lt;/code&gt;就是一个典型的此类包管理器。&lt;/p&gt;
&lt;p&gt;接下来，你的一切工作似乎都非常顺利，直到……&lt;/p&gt;
&lt;h4&gt;依赖冲突&lt;/h4&gt;
&lt;p&gt;某一天，你在开发时发现一个第三方库C似乎无法正常使用，你检查后发现你系统中的一个软件包D不符合它的需求，它依赖于另一个更老版本才提供的接口，然而，你的其他软件包大都只依赖新旧版本都有的接口。这就造成了&lt;strong&gt;依赖冲突&lt;/strong&gt;。&lt;br /&gt;
为了解决这个问题，你又想到一个办法，你只需要在依赖说明添加上符合要求的版本，然后将所有依赖这个包的软件的需求取一个交集不就能解决这个问题了吗？于是你一通计算，1.14版本的D刚好能够满足你的需要，于是你使用语言包管理器将D软件包的版本修改为了1.14。&lt;/p&gt;
&lt;h4&gt;不可调和的依赖冲突与依赖污染&lt;/h4&gt;
&lt;p&gt;某一天，你发现自己的某个软件A突然无法正常使用了，你检查后发现，软件A需要的一个依赖D必须是5.14以上的版本，然而现在它变成了1.14的版本。这两个软件所依赖的软件包的版本完全对立不兼容，这就引发了&lt;strong&gt;不可调和的依赖冲突&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;然后你一通检查发现你的其中一个包管理器在处理时由于使用了较旧的包，修改了D软件的版本，而你的另一个包管理器对此一无所知，因此也没有注意到异常，就导致你现在使用出现问题，在更新时也无法正常解决D软件包的问题。恭喜你，发现了&lt;strong&gt;依赖污染&lt;/strong&gt;问题。&lt;/p&gt;
&lt;p&gt;这次的问题就不像之前那样容易解决了。于是你决定从源头着手彻底解决这类问题。&lt;/p&gt;
&lt;h4&gt;虚拟环境&lt;/h4&gt;
&lt;p&gt;你开始把开发时需要的依赖存放在一个单独的文件夹中与系统依赖（&lt;code&gt;base&lt;/code&gt;&lt;br /&gt;
环境）彻底分开，这样两者就不会产生冲突，同时，针对不同的项目，你可以为每一个项目配置一份单独的依赖环境，彻底解决了上面的问题，你管这个新的发明叫做&lt;strong&gt;虚拟环境&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;从此，通过虚拟环境与包管理器的配合，你和Arch过上了幸福的生活，真是可喜可贺，可喜可贺……&lt;/p&gt;
&lt;h3&gt;安装与使用Conda&lt;/h3&gt;
&lt;p&gt;通过上面的神人小剧场，我相信你已经理解了包管理器和虚拟环境的意义，以及为什么不应该在 Linux 的 &lt;code&gt;base&lt;/code&gt; 环境中使用 conda。接下来我们开始解决问题：如何安装和正确使用 conda？&lt;/p&gt;
&lt;h4&gt;安装&lt;/h4&gt;
&lt;p&gt;我们通过官网脚本安装&lt;code&gt;miniconda3&lt;/code&gt;,这是一个最小的conda版本，不提供额外的依赖，防止conda直接破坏系统环境。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后一路 &lt;code&gt;yes&lt;/code&gt;即可。直到 &lt;code&gt;conda init&lt;/code&gt;的时候，选择 &lt;code&gt;no&lt;/code&gt;记录下安装的 &lt;code&gt;miniconda&lt;/code&gt; 的位置，一般默认 &lt;code&gt;~/miniconda3&lt;/code&gt; 下。接下来照着提示修改环境变量即可。&lt;/p&gt;
&lt;p&gt;添加环境变量，本来是 &lt;code&gt;PATH=~/miniconda3/bin:$PATH&lt;/code&gt;，修改为&lt;code&gt;PATH=$PATH:~/miniconda3/bin&lt;/code&gt;，因为在安装软件时使用 &lt;code&gt;conda&lt;/code&gt;&lt;br /&gt;
作为基础 Python 环境时会发生错误，要求使用系统自带的 Python3。&lt;/p&gt;
&lt;p&gt;使用vim编辑&lt;code&gt;.zshrc&lt;/code&gt;文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;eval &quot;$(~/miniconda3/bin/conda shell.zsh hook)&quot;
export PATH=$PATH:~/miniconda3/bin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;激活配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;source .zshrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们需要在新环境而不是 &lt;code&gt;base&lt;/code&gt; 环境中安装新软件包。为了避免 Conda 自动激活 &lt;code&gt;base&lt;/code&gt; 环境，编辑&lt;code&gt;~/.condarc&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;auto_activate_base: false
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;添加默认软件包&lt;/h4&gt;
&lt;p&gt;在 &lt;code&gt;~/.condarc&lt;/code&gt;中添加&lt;code&gt;create_default_packages&lt;/code&gt; 部分。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;create_default_packages:
  - pip
  - ipython
  - numpy
  - pandas 
  - scipy
  - libgcc-ng
  - mpich
  - rust
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;创建环境&lt;/h4&gt;
&lt;p&gt;要使用上一节中指定的默认软件包创建名为 &lt;code&gt;myenv&lt;/code&gt; 的新环境，请运行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; conda create --name myenv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要创建不带默认软件包的新环境，请运行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda create --no-default-packages --name myenv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要创建具有指定 Python 版本和软件包的环境，请运行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ conda create --name myenv python=3.9 numpy=1.23.5 astropy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要激活环境&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda activate myenv
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;列出环境&lt;/h4&gt;
&lt;p&gt;要列出所有环境&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda env list
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;克隆环境&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;conda create --name myenvclone --clone myenv
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;移除环境&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;$ conda remove --name myenv --all
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;导出和导入环境&lt;/h4&gt;
&lt;p&gt;要导出 &lt;code&gt;myenv&lt;/code&gt; 环境中的所有软件包&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda activate myenv
conda env export &amp;gt; myenv.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果您只想包含您显式安装的软件包，请在导出时添加 &lt;code&gt;--from-history&lt;/code&gt; 标志。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda env export --from-history &amp;gt; myenv.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要从 &lt;code&gt;myenv.yml&lt;/code&gt; 创建新环境，请运行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;conda env create -f myenv.yml
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Arch Linux 脚本安装与 GNOME 桌面环境配置指南</title><link>https://blog.sheyiyuan.com/posts/archlinux%E8%84%9A%E6%9C%AC%E5%AE%89%E8%A3%85%E4%B8%8Egnome%E6%A1%8C%E9%9D%A2%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E6%8C%87%E5%8D%97/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/archlinux%E8%84%9A%E6%9C%AC%E5%AE%89%E8%A3%85%E4%B8%8Egnome%E6%A1%8C%E9%9D%A2%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E6%8C%87%E5%8D%97/</guid><pubDate>Tue, 30 Sep 2025 08:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前情提要&lt;/h2&gt;
&lt;p&gt;这是主包第三次安装 Arch Linux。先交代一下前两次翻车的原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;第一次安装：&lt;/strong&gt; 跟着视频用 &lt;code&gt;archinstall&lt;/code&gt; 装的，能用但小问题不少。更关键的是当时没认真看 Arch Wiki，把引导分区放在了 Windows 磁盘上，后来 Windows 更新改了引导项，直接无法开机。那时也不会救援，只能重装。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;第二次安装：&lt;/strong&gt; 这次是按&lt;a href=&quot;https://arch.icekylin.online/guide/&quot;&gt;archlinux 简明指南&lt;/a&gt;、&lt;a href=&quot;https://github.com/shorinkiwata/Archlinux-Gnome-FullGuide-ShorinArchExperience/tree/main&quot;&gt;Archlinux-Gnome-FullGuide-ShorinArchExperience&lt;/a&gt;和 &lt;a href=&quot;https://wiki.archlinux.org/&quot;&gt;Arch Wiki&lt;/a&gt;手动安装，但因为没有完整记录操作步骤，后面出现了掉引导、掉驱动、掉声音、掉网络等问题，最终还是没救回来。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这篇文档的主干来自上面两篇指南，并补充了主包自己踩坑后总结的实战经验。由于本次是实体机安装，安装阶段图片会比较少（部分示意图来自原指南）；后续如果在虚拟机重装，会再补图完善。&lt;/p&gt;
&lt;h2&gt;阅读导航&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%89%8D%E6%9C%9F%E5%87%86%E5%A4%87&quot;&gt;前期准备&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%AE%89%E8%A3%85%E6%B5%81%E7%A8%8Barchinstall&quot;&gt;安装流程（archinstall）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E7%B3%BB%E7%BB%9F%E9%85%8D%E7%BD%AE%E9%A9%B1%E5%8A%A8%E6%A1%8C%E9%9D%A2%E4%B8%8E%E5%B8%B8%E7%94%A8%E5%B7%A5%E5%85%B7&quot;&gt;系统配置（驱动、桌面与常用工具）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E7%B3%BB%E7%BB%9F%E7%BB%B4%E6%8A%A4%E4%B8%8E%E6%9B%B4%E6%96%B0%E4%B9%A0%E6%83%AF&quot;&gt;系统维护与更新习惯&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E8%BF%9B%E9%98%B6%E7%BE%8E%E5%8C%96%E4%B8%8E%E4%B8%AA%E6%80%A7%E5%8C%96%E9%85%8D%E7%BD%AE&quot;&gt;进阶美化与个性化配置&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%94%B6%E5%B0%BE%E7%BB%99%E6%9C%AA%E6%9D%A5%E7%9A%84%E4%BD%A0%E7%95%99%E4%B8%80%E6%9D%A1%E5%9B%9E%E5%A4%B4%E8%B7%AF&quot;&gt;收尾：给未来的你留一条回头路&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;前期准备&lt;/h2&gt;
&lt;h3&gt;解决双系统导致的时间错乱&lt;/h3&gt;
&lt;p&gt;安装双系统的机器在 Linux 使用一段时间后切换回 Windows 就会出现时间错乱的情况，这是因为两个系统对硬件时钟的处理方式不同（&lt;a href=&quot;https://blog.csdn.net/zhouchen1998/article/details/108893660&quot;&gt;CSDN博客：双系统时间不一致解决方案&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;在 Windows 中以管理员身份运行 PowerShell，输入下面的命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Reg add HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation /v RealTimeIsUniversal /t REG_DWORD /d 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就能解决两个系统时间不同步的问题。&lt;/p&gt;
&lt;h3&gt;准备安装启动盘&lt;/h3&gt;
&lt;p&gt;我们需要一个不小于 8 GB 且没有重要数据的 U 盘（制作启动盘会格式化，务必提前备份），用来存放系统镜像。工具有很多，这里以 &lt;a href=&quot;https://www.ventoy.net/cn/index.html&quot;&gt;Ventoy&lt;/a&gt; 为例。&lt;/p&gt;
&lt;p&gt;用这种方法的好处是在安装后如果出现系统级的崩溃和错误，连 tty 都无法进入时也可以用安装镜像修复系统错误或者抢救数据。并且 Ventoy 在一次准备后可以存放多个系统镜像，把 Windows 安装媒介和 PE 都放进去，实在是居家旅行必备良品（雾）。&lt;/p&gt;
&lt;p&gt;Ventoy 的具体使用方法参考官网教程或其他文档即可，操作本身不复杂，这里不展开。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Arch Linux 会在每个月 1 号发布最新安装镜像。由于 Arch 是滚动更新，尽量使用你能拿到的最新镜像，旧镜像可能会出现奇怪错误。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;vi 基础操作说明&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;vi&lt;/code&gt; 是命令行文本编辑器，&lt;code&gt;vim&lt;/code&gt;、&lt;code&gt;neovim&lt;/code&gt; 的基础操作和它类似。安装系统时你基本绕不开它（虽然我更推荐后续装 &lt;code&gt;vim&lt;/code&gt; 或 &lt;code&gt;neovim&lt;/code&gt;）。这里先给最常用的按键：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;i&lt;/code&gt;：在光标位置进入编辑模式（编辑模式下按键就是普通输入）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Shift + A&lt;/code&gt;：跳到行尾并进入编辑模式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Esc&lt;/code&gt;：退出编辑模式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yy&lt;/code&gt;：复制当前行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dd&lt;/code&gt;：剪切（删除）当前行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p&lt;/code&gt;：粘贴&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:q&lt;/code&gt;：退出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:w&lt;/code&gt;：保存&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:wq&lt;/code&gt;：保存并退出&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/关键词&lt;/code&gt;：查找文本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里的冒号必须是英文冒号，中文冒号不会被识别。&lt;/p&gt;
&lt;h3&gt;记好笔记&lt;/h3&gt;
&lt;p&gt;搞清楚自己做过什么，把每一步操作都记下来。真的，别偷懒。&lt;/p&gt;
&lt;p&gt;不然你为什么会看到这篇文档呢（笑）&lt;/p&gt;
&lt;h2&gt;安装流程（archinstall）&lt;/h2&gt;
&lt;h3&gt;1. 连接网络&lt;/h3&gt;
&lt;p&gt;使用 &lt;code&gt;iwctl&lt;/code&gt; 工具连接无线网络，在命令行输入 &lt;code&gt;iwctl&lt;/code&gt; 后回车进入交互式命令行。需要注意这里只建议使用英文名 Wi‑Fi，使用中文可能乱码导致无法连接。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 启动交互式命令行
iwctl

# （可选）先扫描，再获取可用 Wi-Fi 列表 
station wlan0 scan
station wlan0 get-networks

# 连接网络
station wlan0 connect [wifi名称]
# 回车后输入密码，这里密码不会显示，直接输入完后回车

# 退出 iwctl
exit
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;可选：更新 archinstall&lt;/h3&gt;
&lt;p&gt;Arch 会在每个月第一天发布最新的安装镜像。如果你的镜像不是最新的镜像，建议在 Live 环境里更新 &lt;code&gt;archinstall&lt;/code&gt;，避免一些奇奇怪怪的错误。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 更新数据库（Live 环境临时用没问题；装好系统后尽量避免只用 -Sy 造成部分升级）
pacman -Syy
# 更新密钥与 archinstall
pacman -S --needed archlinux-keyring archinstall
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 使用 archinstall 安装&lt;/h3&gt;
&lt;p&gt;接下来输入 &lt;code&gt;archinstall&lt;/code&gt;，回车进入安装配置 TUI 界面：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;archinstall
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一项是脚本语言，第二项是系统本地化。建议保持英文，改成中文在某些环境可能乱码，直接看第三项即可。&lt;/p&gt;
&lt;h4&gt;Mirrors and repositories 设置镜像源&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;选择第一项 &lt;code&gt;Select regions&lt;/code&gt; 设置自己的所在地。加载会比较慢，耐心等一等。&lt;/li&gt;
&lt;li&gt;选择第三项 &lt;code&gt;optional repositories&lt;/code&gt;，回车激活 &lt;code&gt;multilib&lt;/code&gt;（32 位程序的源）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Disk configuration 磁盘分区&lt;/h4&gt;
&lt;p&gt;选择 partitioning 进入磁盘分区。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ 这里开始涉及真实磁盘写入操作。执行每一步前先确认目标磁盘型号与容量，避免误操作到数据盘。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;情况一：整块空闲硬盘安装 Arch&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;选择第一项进行自动分区 &amp;gt; 要使用的硬盘 &amp;gt; btrfs（文件系统） &amp;gt; yes（是否使用推荐子卷布局） &amp;gt; use compression（透明压缩）&lt;/li&gt;
&lt;li&gt;选择 btrfs snapshots（快照软件） &amp;gt; Snapper，选择 back 返回。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;情况二：和其他系统共享同一块硬盘：选择第二项手动分区 &amp;gt; 要使用的硬盘&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;创建启动分区：选中要使用的空闲空间 &amp;gt; Size（分区大小）1024MB &amp;gt; Filesystem（文件系统）FAT32 &amp;gt; Mountpoint（挂载点）/boot&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;创建 swap 分区（可选）：&lt;strong&gt;如果你不需要“休眠到硬盘（hibernate）”的话可以跳过这一步&lt;/strong&gt;。休眠指把系统当前状态写入硬盘，然后电脑完全断电，下一次开机恢复到休眠前的状态。swap 交换空间与虚拟内存和休眠有关。建议设置 zram 作为日常 swap，&lt;strong&gt;仅在需要休眠时再配置硬盘 swap&lt;/strong&gt;。swap 有分区或文件两种方式：分区更简单，文件更灵活。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;内存&lt;/th&gt;
&lt;th&gt;不需要睡眠&lt;/th&gt;
&lt;th&gt;需要睡眠&lt;/th&gt;
&lt;th&gt;不建议超过&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1GB&lt;/td&gt;
&lt;td&gt;1GB&lt;/td&gt;
&lt;td&gt;2GB&lt;/td&gt;
&lt;td&gt;2GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2GB&lt;/td&gt;
&lt;td&gt;2GB&lt;/td&gt;
&lt;td&gt;3GB&lt;/td&gt;
&lt;td&gt;4GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3GB&lt;/td&gt;
&lt;td&gt;3GB&lt;/td&gt;
&lt;td&gt;5GB&lt;/td&gt;
&lt;td&gt;6GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4GB&lt;/td&gt;
&lt;td&gt;4GB&lt;/td&gt;
&lt;td&gt;6GB&lt;/td&gt;
&lt;td&gt;8GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5GB&lt;/td&gt;
&lt;td&gt;2GB&lt;/td&gt;
&lt;td&gt;7GB&lt;/td&gt;
&lt;td&gt;10GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6GB&lt;/td&gt;
&lt;td&gt;2GB&lt;/td&gt;
&lt;td&gt;8GB&lt;/td&gt;
&lt;td&gt;12GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8GB&lt;/td&gt;
&lt;td&gt;3GB&lt;/td&gt;
&lt;td&gt;11GB&lt;/td&gt;
&lt;td&gt;16GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12GB&lt;/td&gt;
&lt;td&gt;3GB&lt;/td&gt;
&lt;td&gt;15GB&lt;/td&gt;
&lt;td&gt;24GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16GB&lt;/td&gt;
&lt;td&gt;4GB&lt;/td&gt;
&lt;td&gt;20GB&lt;/td&gt;
&lt;td&gt;32GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;24GB&lt;/td&gt;
&lt;td&gt;5GB&lt;/td&gt;
&lt;td&gt;29GB&lt;/td&gt;
&lt;td&gt;48GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;32GB&lt;/td&gt;
&lt;td&gt;6GB&lt;/td&gt;
&lt;td&gt;38GB&lt;/td&gt;
&lt;td&gt;64GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;64GB&lt;/td&gt;
&lt;td&gt;8GB&lt;/td&gt;
&lt;td&gt;72GB&lt;/td&gt;
&lt;td&gt;128GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;128GB&lt;/td&gt;
&lt;td&gt;11GB&lt;/td&gt;
&lt;td&gt;139GB&lt;/td&gt;
&lt;td&gt;256GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;256GB&lt;/td&gt;
&lt;td&gt;16GB&lt;/td&gt;
&lt;td&gt;272GB&lt;/td&gt;
&lt;td&gt;512GB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;512GB&lt;/td&gt;
&lt;td&gt;23GB&lt;/td&gt;
&lt;td&gt;535GB&lt;/td&gt;
&lt;td&gt;1TB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1TB&lt;/td&gt;
&lt;td&gt;32GB&lt;/td&gt;
&lt;td&gt;1056GB&lt;/td&gt;
&lt;td&gt;2TB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2TB&lt;/td&gt;
&lt;td&gt;46GB&lt;/td&gt;
&lt;td&gt;2094GB&lt;/td&gt;
&lt;td&gt;4TB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4TB&lt;/td&gt;
&lt;td&gt;64GB&lt;/td&gt;
&lt;td&gt;4160GB&lt;/td&gt;
&lt;td&gt;8TB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8TB&lt;/td&gt;
&lt;td&gt;91GB&lt;/td&gt;
&lt;td&gt;8283GB&lt;/td&gt;
&lt;td&gt;16TB&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt; Size参考上面的表 &amp;gt; linux-swap
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;创建 root 分区：Size 部分直接回车分配全部空间 &amp;gt; btrfs &amp;gt; 选中刚刚创建的 btrfs 回车。选择 Mark/Unmark as compressed 设置透明压缩；再选择 Set subvolumes（创建子卷）&amp;gt; Add subvolume，至少创建 root 子卷和 home 子卷：Subvolume name 设为 &lt;code&gt;@&lt;/code&gt;，对应 mountpoint 为 &lt;code&gt;/&lt;/code&gt;；&lt;code&gt;@home&lt;/code&gt; 对应 &lt;code&gt;/home&lt;/code&gt;。最后 confirm and exit &amp;gt; confirm and exit &amp;gt; back 退出硬盘分区。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Swap（zram交换空间）&lt;/h4&gt;
&lt;p&gt;这一步会自动帮你配置 zram 交换空间，选择 &lt;code&gt;Yes&lt;/code&gt; 开启即可。&lt;/p&gt;
&lt;h4&gt;Bootloader引导系统&lt;/h4&gt;
&lt;p&gt;最常用的是 GRUB，选择 GRUB 即可；有其他需求再按需查文档。&lt;/p&gt;
&lt;h4&gt;Hostname主机名&lt;/h4&gt;
&lt;p&gt;不用改，你想要改成其他名字也行&lt;/p&gt;
&lt;h4&gt;Authentication身份认证&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Root password&lt;/code&gt;：设置管理员密码。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;User account &amp;gt; Add a user&lt;/code&gt;：创建普通用户。&lt;code&gt;Should &quot;xxx&quot; be a superuser (sudo)&lt;/code&gt; 是在问要不要给该用户管理员权限，通常选择 &lt;code&gt;Yes&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;U2F login setup&lt;/code&gt;：物理密钥登录，有需要再配置。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Profile&lt;/h4&gt;
&lt;p&gt;这里可以选择自动安装桌面、最小化安装等配置。既然都用 &lt;code&gt;archinstall&lt;/code&gt; 了，桌面也可以顺手装上。如果你还没想好，先在 GNOME 和 KDE Plasma 里二选一：KDE 更接近 Windows 习惯，资源占用更低、可定制性更强；GNOME 中文输入法体验更稳定，更接近 macOS 的交互逻辑，整体更统一。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Type &amp;gt; Desktop &amp;gt; 想安装的桌面环境或者窗口管理器&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Graphics driver&lt;/code&gt;（自动安装显卡驱动）：AMD 选择 &lt;code&gt;AMD/ATi (opensource)&lt;/code&gt;；NVIDIA 先去 &lt;a href=&quot;https://nouveau.freedesktop.org/CodeNames.html&quot;&gt;CodeNames · freedesktop.org&lt;/a&gt; 查显卡对应的 NV family。通常 NV160 及以后可选 &lt;code&gt;NVIDIA (open kernel module …)&lt;/code&gt;；NV110~NV160 可选 &lt;code&gt;NVIDIA (proprietary)&lt;/code&gt;；更早型号用 &lt;code&gt;NVIDIA (open-source nouveau …)&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不过这里自动装的桌面通常会附带不少你不一定用得上的软件。追求干净系统的话，建议走最小化安装，再手动补齐自己要的组件。&lt;/p&gt;
&lt;h4&gt;Applications（蓝牙和音视频）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Bluetooth &amp;gt; Yes&lt;/code&gt;：自动安装蓝牙组件。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Audio &amp;gt; pipewire&lt;/code&gt;：自动安装音视频服务。PipeWire 是当前主流方案，兼容旧的 PulseAudio 等服务，直接选 &lt;code&gt;pipewire&lt;/code&gt; 即可。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Kernel（系统内核）&lt;/h4&gt;
&lt;p&gt;按 &lt;code&gt;Tab&lt;/code&gt; 键切换选项。偏续航可选 &lt;code&gt;linux&lt;/code&gt;，偏性能可选 &lt;code&gt;linux-zen&lt;/code&gt;。&lt;/p&gt;
&lt;h4&gt;Network configuration （网络配置）&lt;/h4&gt;
&lt;p&gt;建议选第三项 &lt;code&gt;NetworkManager&lt;/code&gt;，它和 GNOME / KDE Plasma 集成最好。&lt;/p&gt;
&lt;h4&gt;Additional packages（自定义安装其他软件包）&lt;/h4&gt;
&lt;p&gt;按 &lt;code&gt;/&lt;/code&gt; 进行搜索，按 &lt;code&gt;Tab&lt;/code&gt; 键选择。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里的包选择会直接影响后续引导与联网体验，至少保证 &lt;code&gt;vim&lt;/code&gt;、&lt;code&gt;os-prober&lt;/code&gt; 这类基础组件被选中。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;必须安装：vim（任意文本编辑器）、os-prober（双系统需要）&lt;/p&gt;
&lt;p&gt;如果你安装了其他内核，比如我使用 linux-zen，可以把头文件 &lt;code&gt;linux-zen-headers&lt;/code&gt; 勾选上。&lt;/p&gt;
&lt;p&gt;可选安装中文字体：wqy-zenhei（文泉驿字体）、noto-fonts（谷歌开源字体）、noto-fonts-emoji（表情）&lt;/p&gt;
&lt;h4&gt;Timezone（时区）&lt;/h4&gt;
&lt;p&gt;左斜杠键搜索Shanghai，这里没有北京，不要找北京了。&lt;/p&gt;
&lt;h4&gt;Automatic time sync (NTP) （自动启用网络时间同步）&lt;/h4&gt;
&lt;p&gt;默认开启，不用修改&lt;/p&gt;
&lt;h4&gt;Install&lt;/h4&gt;
&lt;p&gt;选择 &lt;code&gt;Install&lt;/code&gt; 开始安装。&lt;/p&gt;
&lt;h3&gt;3. 双系统&lt;/h3&gt;
&lt;p&gt;安装完成后配置 Windows 和 Linux 的双系统。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;选择 &lt;code&gt;Exit archinstall&lt;/code&gt;，退出安装器。&lt;/li&gt;
&lt;li&gt;挂载 Windows 的 EFI 启动分区（ESP，FAT32）。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   lsblk -pf #列出当前分区情况
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;找到 Windows 所在磁盘上的 EFI System Partition（FAT32，常见类似 &lt;code&gt;nvme0n1p1&lt;/code&gt;/&lt;code&gt;nvme1n1p1&lt;/code&gt;）。可以用 &lt;code&gt;fdisk -l&lt;/code&gt;（小写字母 l）看更详细信息。确认无误后再挂载到 &lt;code&gt;/mnt&lt;/code&gt; 下任意目录（例如 &lt;code&gt;/mnt/winboot&lt;/code&gt;）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;设备名仅为示例，务必按你机器的实际输出填写，别直接照抄。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;   mount /dev/nvme1n1p1 /mnt/winboot 
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;arch-chroot&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   arch-chroot /mnt #进入刚刚安装的系统
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;编辑 GRUB 配置启用 &lt;code&gt;os-prober&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   vim /etc/default/grub 

   i键进入编辑模式

  确保存在并设置：GRUB_DISABLE_OS_PROBER=false（取消注释或新增一行）

   esc退出编辑模式

   :wq 冒号小写wq保存并退出
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;禁用 watchdog：在 &lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT=&quot;&quot;&lt;/code&gt; 里添加参数&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   nowatchdog modprobe.blacklist=sp5100_tco
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Intel CPU 用户把 &lt;code&gt;sp5100_tco&lt;/code&gt; 换成 &lt;code&gt;iTCO_wdt&lt;/code&gt;。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;将 &lt;code&gt;GRUB_DEFAULT=0&lt;/code&gt; 改成 &lt;code&gt;GRUB_DEFAULT=saved&lt;/code&gt;，再取消 &lt;code&gt;GRUB_SAVEDEFAULT=true&lt;/code&gt; 的注释。这一步用于记住上一次开机选择。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;生成 GRUB 配置文件&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   grub-mkconfig -o /boot/grub/grub.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;exit 退出 chroot&lt;/li&gt;
&lt;li&gt;reboot 重启&lt;/li&gt;
&lt;li&gt;如有需要，进入 BIOS/UEFI 调整启动项顺序。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;系统配置（驱动、桌面与常用工具）&lt;/h2&gt;
&lt;h3&gt;网络连接&lt;/h3&gt;
&lt;p&gt;设置开机自启并立即启动 &lt;code&gt;NetworkManager&lt;/code&gt; 服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl enable --now NetworkManager
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若为无线连接，则需要在启动 &lt;code&gt;NetworkManager&lt;/code&gt; 后使用 &lt;code&gt;nmtui&lt;/code&gt; 连接网络：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nmtui
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;可选：安装 fastfetch&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;fastfetch&lt;/code&gt; 可以把系统信息和发行版 Logo 一并打印出来。通过 &lt;code&gt;pacman&lt;/code&gt; 安装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pacman -S fastfetch
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;显卡驱动和硬件编解码&lt;/h3&gt;
&lt;p&gt;以 4060 和 780M 为例。&lt;/p&gt;
&lt;p&gt;参考链接：&lt;a href=&quot;https://wiki.archlinux.org/title/NVIDIA&quot;&gt;NVIDIA - ArchWiki&lt;/a&gt;、&lt;a href=&quot;https://wiki.archlinux.org/title/AMDGPU&quot;&gt;AMDGPU&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;检查头文件&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S linux-zen-headers
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;把 &lt;code&gt;linux&lt;/code&gt; 替换成你正在使用的内核名；例如 Zen 内核对应 &lt;code&gt;linux-zen-headers&lt;/code&gt;。&lt;/p&gt;
&lt;h4&gt;安装显卡驱动&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Intel 核显&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S mesa lib32-mesa vulkan-intel lib32-vulkan-intel
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Nvidia&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S --needed nvidia-dkms nvidia-settings nvidia-utils lib32-nvidia-utils
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;显卡驱动的选择：先在&lt;a href=&quot;https://nouveau.freedesktop.org/CodeNames.html&quot;&gt;CodeNames · freedesktop.org&lt;/a&gt;搜索自己的显卡，确认对应的 family；然后在&lt;a href=&quot;https://wiki.archlinux.org/title/NVIDIA&quot;&gt;NVIDIA - ArchWiki&lt;/a&gt;查对应驱动。NV160 family 往后的显卡通常可用 &lt;code&gt;nvidia-open&lt;/code&gt;；NV110~NV190 如果 &lt;code&gt;nvidia-open&lt;/code&gt; 表现不佳可以使用 &lt;code&gt;nvidia&lt;/code&gt;。注意：非 stable 内核要安装的驱动包可能不同，具体看 wiki，例如 zen 内核常见是 &lt;code&gt;nvidia-open-dkms&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AMD 显卡一般不需要额外安装专有驱动，确认 Vulkan 相关包即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;  sudo pacman -S --needed vulkan-radeon vulkan-mesa-layers
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;硬件编解码&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;NVIDIA&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;  sudo pacman -S libva-nvidia-driver
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;AMD 自带，无需额外安装。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重启激活显卡驱动和字体&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;  reboot 
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;GNOME&lt;/h3&gt;
&lt;h4&gt;安装 GNOME 最小环境&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S --needed gnome-shell gdm gnome-control-center gnome-software flatpak
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;终端模拟器可按需安装（例如 &lt;code&gt;ghostty&lt;/code&gt;/&lt;code&gt;gnome-console&lt;/code&gt; 等）。&lt;/p&gt;
&lt;p&gt;如果在安装音频相关组件时提示选择 JACK provider，一般选择 &lt;code&gt;pipewire-jack&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gnome-shell GNOME 桌面最小核心
gdm 是显示管理器（GNOME Display Manager）
ghostty 是一个可高度自定义的终端模拟器（terminal emulator)
gnome-control-center 是设置中心
gnome-software 是软件商城
flatpak 是跨发行版通用的软件打包形式，通常版本更新会更及时
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;临时开启GDM&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;systemctl start gdm 
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;正常启动后设置 gdm 开机自启&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable gdm
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;安装声音固件和声音服务&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;安装声音固件&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S --needed sof-firmware alsa-firmware alsa-ucm-conf
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;安装声音服务&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S --needed pipewire pipewire-pulse pipewire-alsa pipewire-jack wireplumber
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;启用服务&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;systemctl --user enable --now pipewire pipewire-pulse wireplumber
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;可选：安装GUI（图形界面管理工具）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S pavucontrol 
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;启用蓝牙&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S --needed bluez bluez-utils
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable --now bluetooth
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;安装高级网络配置工具nm-connection-editor&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S --needed network-manager-applet dnsmasq
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;配置 archlinuxcn 源&lt;/h4&gt;
&lt;p&gt;这里先配置 &lt;code&gt;archlinuxcn&lt;/code&gt; 源，后面的代理工具和 AUR 助手会用到。&lt;/p&gt;
&lt;p&gt;AUR 上很多包在无代理环境下很难下载，所以建议先把网络环境准备好。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  sudo vim /etc/pacman.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;文件底部写入（ctrl+shift+V粘贴）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  [archlinuxcn]
  Server = https://mirrors.ustc.edu.cn/archlinuxcn/$arch 
  Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch 
  Server = https://mirrors.hit.edu.cn/archlinuxcn/$arch 
  Server = https://repo.huaweicloud.com/archlinuxcn/$arch 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同步数据库并安装 archlinuxcn 密钥&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  sudo pacman -Syu --needed archlinuxcn-keyring
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装代理软件 clash-verge-rev 和 AUR 助手 yay：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;paru&lt;/code&gt; 也是 AUR 助手，但部分场景下兼容性不如 &lt;code&gt;yay&lt;/code&gt;。建议固定使用一个助手，不要混用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;  sudo pacman -S clash-verge-rev yay 
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;安装微软字体&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;yay -S ttf-ms-win11-auto-zh_cn
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;本地化设置&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/locale.gen 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;左斜杠键搜索，取消zh_CN.UTF-8的注释&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo locale-gen
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;配置 Flatpak 源&lt;/h4&gt;
&lt;p&gt;如果 Flatpak 下载慢或加载异常，可以切换国内镜像源。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo flatpak remote-modify flathub --url=https://mirror.sjtu.edu.cn/flathub
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;fcitx5输入法&lt;/h4&gt;
&lt;p&gt;已知问题：在某些应用里面会吞字，或者某个按键没能被输入法获取直接变成英文字母输入。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S fcitx5-im # 输入法基础包组
sudo pacman -S fcitx5-chinese-addons # 官方中文输入引擎
sudo pacman -S fcitx5-mozc # 日文输入引擎
sudo pacman -S fcitx5-pinyin-moegirl # 萌娘百科词库。二刺猿必备（archlinuxcn）
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在商店搜索 &lt;code&gt;Extension Manager&lt;/code&gt;，安装蓝色图标的那个。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装扩展：input method panel&lt;br /&gt;
https://extensions.gnome.org/extension/261/kimpanel/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编辑环境变量&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/environment
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;XIM=fcitx # 解决 WeChat 可能用不了输入法的问题
GTK_IM_MODULE=fcitx
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx
XDG_CURRENT_DESKTOP=GNOME #解决某些软件里面输入法吞字的问题
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;卸载 fcitx5&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;删除包&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   sudo pacman -Rns fcitx5-im fcitx5-mozc fcitx5-rime rime-ice-pinyin-git
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;删除残留文件&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   sudo rm -rfv ~/.config/fcitx5 ~/.local/fcitx5
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;清理环境变量&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;   sudo vim /etc/environment
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;如果之前禁用过系统设置里的打字快捷键记得恢复&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;自定义安装软件&lt;/h4&gt;
&lt;p&gt;下面是主包自己常装的一批软件，你可以按需裁剪。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;安装软件后没显示图标的话登出一次&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pacman&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;  sudo pacman -S --needed mission-center gnome-text-editor gnome-disk-utility gnome-font-viewer loupe snapshot baobab celluloid fragments file-roller foliate chromium gst-plugin-pipewire gst-plugins-good pacman-contrib decibels papers
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;  mission-center 类似 Windows 11 的任务管理器，强烈推荐
  gnome-text-editor GNOME 标配记事本
  gnome-disk-utility 磁盘管理工具，可以调节分区大小和格式化分区等等
  gnome-font-viewer 方便安装和查看字体
  loupe 图片查看工具
  snapshot 相机，摄像头
  baobab 磁盘使用情况分析工具
  celluloid 是基于 mpv 的视频播放器
  fragments 是符合 GNOME 设计风格的种子下载器（也可换 qBittorrent）
  file-roller 压缩解压缩
  foliate 电子书阅读器
  chromium 是开源 Chromium 浏览器，兼容 Chrome 插件生态；偏好 Firefox 可自行替换
  gst-plugin-pipewire gst-plugins-good 对 GNOME 自带录屏有帮助，安装后建议登出一次
  pacman-contrib 提供 pacman 额外功能，比如 `checkupdates` 用于检查更新
  decibels 是可以显示波形的音频播放器，这只是个音频播放器，不是音乐播放器
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;从 AUR 安装常用软件（示例）&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;yay -S linuxqq-appimage wechat-appimage wps-office-cn wps-office-mui-zh-cn obsidian-appimage albert
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;  linuxqq Linux 版 QQ
  wechat-appimage 是 AppImage 版微信
  wps-office-cn 是 WPS
  wps-office-mui-zh-cn 是 WPS 中文语言包
  obsidian-appimage 是 Markdown 编辑器
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;关于 WPS 打开文件的问题&lt;br /&gt;
WPS 在 Linux 上可能出现“设置打开方式后仍无法通过双击打开文档”的问题。一般在设置里切换窗口管理模式，改成“多组件模式”后即可双击打开；之后再切回原来的模式通常也不影响文件打开。（Linux，很神奇吧）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关于字体：从网上下载常用办公字体后，解压并存放到 &lt;code&gt;~/.local/share/fonts&lt;/code&gt;（建议分目录整理），然后刷新字体缓存：&lt;code&gt;fc-cache --force&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Flatpak 这一组都是比较实用的小工具，可以在商店搜，也可以直接命令安装。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;  flatpak install flathub be.alexandervanhee.gradia io.github.Predidit.Kazumi io.gitlab.theevilskeleton.Upscaler com.github.unrud.VideoDownloader io.github.ilya_zlobintsev.LACT com.geeks3d.furmark io.github.flattool.Warehouse com.github.tchx84.Flatseal com.dec05eba.gpu_screen_recorder
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;  gradia 用于截图编辑
  kazumi 用于追番
  upscaler 用于图片超分
  video downloader 支持下载 YouTube/Bilibili 144p～8k 视频
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Gradia 可以对截图做文字、马赛克、图表、背景等轻编辑。设置自定义快捷键时可使用：&lt;code&gt;flatpak run be.alexandervanhee.gradia --screenshot=INTERACTIVE&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;快捷键配置&lt;/h4&gt;
&lt;p&gt;路径：设置 &amp;gt; 键盘 &amp;gt; 查看与自定义快捷键。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;导航&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;super+shift+数字键 #将窗口移到工作区
super+shift+A/D #将窗口左右移动工作区
super+shift+Q/E #移动到左/右工作区
PS：GNOME 默认 `Super + 鼠标滚轮上下` 可以切换工作区。
alt+tab #切换应用程序
alt+` #在应用程序的窗口之间切换窗口
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;截图&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;ctrl+alt+A #交互式截图
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;无障碍&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;屏幕阅读 禁用
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;窗口&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;super+Q #关闭窗口
super+F #切换最大化
super+alt+F #切换全屏
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;系统&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;ctrl+super+S #打开快速设置菜单
super+G #显示全部应用
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;自定义快捷键&amp;lt;快捷键&amp;gt; &amp;lt;命令&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;super+B   chromium
super+T   ghostty
super+`    missioncenter
super+D   nautilus
ctrl+alt+S gnome-control-center
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;功能性扩展&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;警告：GNOME 大版本更新时，扩展很可能大面积失效。遇到大版本更新，先禁用扩展再升级。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;从商店安装蓝色的扩展管理器&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;flatpak install flathub com.mattjakeman.ExtensionManager
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;AppIndicator and KStatusNotifierItem Support 面板上显示后台应用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;caffeine 防止熄屏&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;lock keys 装 kazimieras.vaina 的那个。OSD 会显示大写锁定和小键盘锁定；设置里把指示器风格改成 &lt;code&gt;show/hide cap-locks only&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fuzzy Application Search 模糊搜索&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;steal my focus window 如果打开窗口时窗口已经被打开则置顶&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tiling shell 窗口平铺。tiling shell 是布局式平铺；另一个 forge 更像 Hyprland 那种自动平铺，但在部分机器上会卡。主包更推荐 tiling shell。可自定义快捷键：&lt;code&gt;Super+W/A/S/D&lt;/code&gt; 上下左右移动窗口，&lt;code&gt;Super+Alt+W/A/S/D&lt;/code&gt; 上下左右扩展窗口，&lt;code&gt;Super+Z&lt;/code&gt; 取消平铺，&lt;code&gt;Super+C&lt;/code&gt; 窗口居中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tiling assistant 这个扩展提供最基础的四角平铺和上下左右半屏平铺功能。设置里 gaps 和 tiling shell 调成一样的，禁用 keybinds 里 general 一项的第 1/2/4 项，仅保留 restore window size。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可选：forge。如果你更喜欢无预设布局的自动平铺，可以安装 forge。装了 forge 就不要再装 tiling shell 和 tiling assistant 了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;color picker 用来吸取屏幕颜色，对自定义很实用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Arch Linux Updates Indicator 在面板上显示一个和arch更新相关的图标。要安装pacman-contrib。设置取消始终显示，高级设置里命令改成&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;  ghostty -e sudo pacman -Syu
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;quick settings tweaks 让右上角快速设置更合理：可把通知迁移到快速设置、缩小时间面板占位、把免打扰开关移到快速设置，还能单独调应用音量。扩展设置里 &lt;code&gt;menu&lt;/code&gt; 页面有两项可开启：第一项让音量菜单悬浮显示，第二项增加动画。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;clipboard indicator 剪贴板历史。可在设置里把菜单快捷键改成 &lt;code&gt;Super+V&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;睡眠到硬盘&lt;/h5&gt;
&lt;p&gt;硬盘上必须有交换空间才能睡眠到硬盘&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;添加 hook&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo vim /etc/mkinitcpio.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;在 `HOOKS()` 里添加 `resume`，注意要放在 `udev` 后面。
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;重新生成initramfs&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo mkinitcpio -P
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;reboot&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;reboot
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;使用命令进行睡眠&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;systemctl hibernate
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;open in any terminal&lt;/h5&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Stunkymonkey/nautilus-open-any-terminal&quot;&gt;GitHub - Stunkymonkey/nautilus-open-any-terminal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是一个在文件管理器“右键在此处打开终端”的功能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果用的是ghostty&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S nautilus-python
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;其他终端仿真器&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;yay -S nautilus-open-any-terminal 
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo glib-compile-schemas /usr/share/glib-2.0/schemas 
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S dconf-editor
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;修改配置，路径为/com/github/stunkymonkey/nautilus-open-any-terminal
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重载nautilus&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nautilus -q 
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;性能模式切换工具 power-profiles-daemon&lt;/h5&gt;
&lt;p&gt;性能模式有三个档位：&lt;code&gt;performance&lt;/code&gt;（性能）、&lt;code&gt;balanced&lt;/code&gt;（平衡）、&lt;code&gt;power-saver&lt;/code&gt;（省电）。日常一般用平衡档就够了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S power-profiles-daemon
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable --now power-profiles-daemon 
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;实用插件扩展&lt;/h5&gt;
&lt;p&gt;power tracker：显示电池充放电&lt;br /&gt;
auto power profile：配合 power-profiles-daemon 自动切换模式&lt;br /&gt;
power profile indicator：在面板显示当前模式&lt;/p&gt;
&lt;h4&gt;安装优化&lt;/h4&gt;
&lt;p&gt;安装优化软件进行调整：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S gnome-tweaks
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在商店搜索 Refine，可开启更多缩放比例。&lt;/p&gt;
&lt;h5&gt;显卡切换&lt;/h5&gt;
&lt;p&gt;更推荐使用 switcheroo-control 进行管理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S --needed switcheroo-control
sudo systemctl enable --now switcheroo-control
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样可以在运行软件时右键选择使用哪个显卡运行&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;另外的方法（不推荐）：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ASUS 电脑可安装 supergfxctl 与对应扩展：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yay -S supergfxctl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装扩展supergfxctl switch&lt;/p&gt;
&lt;h4&gt;快照&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;快照相当于恢复点，每次试验什么之前最好都创建一下快照&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S snapper snap-pac btrfs-assistant 
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;snapper 是创建快照的主要程序
snap-pac 是利用钩子在进行一些pacman命令的时候自动创建快照
btrfs-assistant 是图形化管理btrfs和快照的软件
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;自动生成快照启动项&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S grub-btrfs inotify-tools
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;reboot
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable --now grub-btrfsd
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;具体使用方法&lt;/h5&gt;
&lt;p&gt;打开 btrfs-assistant，切到 Snapper Settings 页面。由于前面创建了 &lt;code&gt;@&lt;/code&gt;（root）和 &lt;code&gt;@home&lt;/code&gt;（home）两个子卷，所以需要分别建两个 config。之后在 Snapper 的 New/Delete 页面管理快照，在 Browse/Restore 页面选中快照后点 restore 即可恢复。若要同时快照 root 与 home，就分别创建并分别恢复。&lt;/p&gt;
&lt;h2&gt;系统维护与更新习惯&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;滚挂：Arch Linux 是滚动发行版（rolling release），新版本会持续推送，由用户自己管理更新。滚挂指更新后系统异常，常见原因是误操作、忽略公告、跨版本依赖冲突。通常普通软件更新问题不大；&lt;strong&gt;但涉及 keyring、内核、驱动、固件、引导程序的更新要更谨慎&lt;/strong&gt;，可以先观望社区反馈再更新。反过来，长期不更新也会因为依赖断层导致软件不可用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;良好的使用习惯：Btrfs 已经很稳定，但仍建议谨慎操作。使用时遵循以下几点：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;别第一时间更新，也别长时间不更新；重要程序更新前创建快照；密钥相关更新多留意&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;明白自己的行为会造成怎样的后果；做不了解的事情前创建快照&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定期清理较旧的快照，保持系统整洁，否则可能会导致硬盘整个被快照占满&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;进阶美化与个性化配置&lt;/h2&gt;
&lt;h4&gt;zsh&lt;/h4&gt;
&lt;p&gt;我们安装 zsh 替代 bash，并加几个实用插件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S zsh zsh-syntax-highlighting # zsh 与语法高亮插件
sudo pacman -S thefuck # 命令纠错工具，输错后执行 fuck 可获取建议命令
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装 starship 美化 zsh：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S starship
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更改账户的默认 Shell：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chsh -s /usr/bin/zsh # 修改当前账户的默认 Shell
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关闭终端后重新打开，确认已经进入 zsh。然后创建并编辑 &lt;code&gt;.zshrc&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vim ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入下面的内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HISTSIZE=10000
SAVEHIST=10000
HISTFILE=.zsh_history
setopt HIST_IGNORE_DUPS
eval &quot;$(starship init zsh)&quot;
eval $(thefuck --alias)
source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;starship&lt;/code&gt; 更多主题可在官网查看。&lt;/p&gt;
&lt;h4&gt;壁纸&lt;/h4&gt;
&lt;p&gt;安装扩展：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Lock screen background&lt;/code&gt;用于修改锁屏壁纸&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Blur my Shell&lt;/code&gt;可以让黑边变为模糊效果，同时可以对窗口元素进行修改&lt;/p&gt;
&lt;h5&gt;可选：动态壁纸&lt;/h5&gt;
&lt;p&gt;安装 &lt;code&gt;hidamari&lt;/code&gt; 作为动态壁纸引擎，它支持把视频或网页设置为动态壁纸。&lt;/p&gt;
&lt;p&gt;这个软件对性能有一定要求，低配电脑建议跳过这一步。&lt;/p&gt;
&lt;h4&gt;GRUB主题&lt;/h4&gt;
&lt;p&gt;使用 yay 安装 &lt;code&gt;grub-customizer&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;然后就可以快速设置你喜欢的主题了&lt;/p&gt;
&lt;h4&gt;音乐播放器&lt;/h4&gt;
&lt;p&gt;由于网易云音乐的 Linux 官方客户端长期缺乏维护，这里使用第三方播放器 &lt;code&gt;netease-cloud-music-gtk4&lt;/code&gt;。它是用 Rust 构建的轻量第三方网易云播放器，除了不能添加/编辑歌单以外，使用体验很好。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# archlinuxcn repo
sudo pacman -Syu --needed netease-cloud-music-gtk4
# AUR
yay -S netease-cloud-music-gtk4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个播放器的缺点是 GNOME 下没有托盘，需要第三方 MPRIS 插件控制。主包这里用官方推荐的 &lt;code&gt;Media Controls&lt;/code&gt;，你也可以直接用通知中心控制播放。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;为什么不使用 &lt;code&gt;yesplaymusic&lt;/code&gt;？&lt;/p&gt;
&lt;p&gt;yesplaymusic 在使用时经常会出现账号风控的情况，较为不稳定，故这里不做推荐。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;游戏&lt;/h4&gt;
&lt;p&gt;现在 Steam 安装很简单，开启 32 位源后直接用 pacman 安装即可：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S steam
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果要玩其他游戏，可以在 Steam 库中添加非 Steam 游戏的 &lt;code&gt;.exe&lt;/code&gt;，然后在 &lt;code&gt;属性-兼容性&lt;/code&gt; 勾选强制使用 Steam 运行时环境。主包用这套方法跑过 PVZ、魔裁等游戏，暂时没遇到明显异常。&lt;/p&gt;
&lt;h2&gt;收尾：给未来的你留一条回头路&lt;/h2&gt;
&lt;p&gt;如果你能看到这里，恭喜你：你已经不只是“把 Arch 装上了”，而是把一套可维护、可回滚、可持续折腾的工作流搭起来了。&lt;/p&gt;
&lt;p&gt;最后给你一个收尾检查单，供你参考：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;网络可用&lt;/strong&gt;：&lt;code&gt;NetworkManager&lt;/code&gt; 正常、重启后能自动联网。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;引导可用&lt;/strong&gt;：GRUB 能进 Linux，双系统用户能看到 Windows 启动项。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;驱动可用&lt;/strong&gt;：显卡驱动和硬件编解码正常，常用软件启动无异常。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;输入可用&lt;/strong&gt;：fcitx5 正常工作，常用应用不吞字。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回滚可用&lt;/strong&gt;：Snapper / btrfs-assistant 可创建并恢复快照。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;更新有策略&lt;/strong&gt;：大版本与关键组件更新前先看公告、先做快照。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Linux 这条路的核心从来不是“永不翻车”，而是“翻车后能自己把车扶起来”。&lt;/p&gt;
&lt;p&gt;祝你折腾顺利，系统稳定，少掉引导，少炸驱动，多写点自己的经验文档。&lt;/p&gt;
</content:encoded></item><item><title>CSS 盒模型</title><link>https://blog.sheyiyuan.com/notes/css-%E7%9B%92%E6%A8%A1%E5%9E%8B/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/notes/css-%E7%9B%92%E6%A8%A1%E5%9E%8B/</guid><pubDate>Fri, 23 May 2025 02:48:00 GMT</pubDate><content:encoded>&lt;h1&gt;盒子模型&lt;/h1&gt;
&lt;p&gt;所有的元素都被一个个的「盒子」包围着，学会盒子模型可以实现准确布局、处理元素排列的关键。&lt;/p&gt;
&lt;p&gt;在 CSS 中我们有几种类型的盒子，一般分为区块盒子（block boxes）和行内盒子（inline boxes）&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;区块盒子&lt;/th&gt;
&lt;th&gt;行内盒子&lt;/th&gt;
&lt;th&gt;行内块盒子&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;换行行为&lt;/td&gt;
&lt;td&gt;会产生换行，独占一行&lt;/td&gt;
&lt;td&gt;不会产生换行，与其他行内元素并排&lt;/td&gt;
&lt;td&gt;不会产生换行，与其他行内元素并排&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;宽高属性&lt;/td&gt;
&lt;td&gt;&lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt; 属性可以生效&lt;/td&gt;
&lt;td&gt;&lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt; 属性不起作用&lt;/td&gt;
&lt;td&gt;&lt;code&gt;width&lt;/code&gt; 和 &lt;code&gt;height&lt;/code&gt; 属性可以生效&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;默认宽度&lt;/td&gt;
&lt;td&gt;不设置宽度时，默认占满父元素宽度的 100%&lt;/td&gt;
&lt;td&gt;宽度由内容本身决定&lt;/td&gt;
&lt;td&gt;宽度由内容或设置的 &lt;code&gt;width&lt;/code&gt; 决定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内外边距&lt;/td&gt;
&lt;td&gt;内边距、外边距和边框在所有方向都会撑大元素&lt;/td&gt;
&lt;td&gt;垂直方向的内边距、外边距不起效果；水平方向的内边距、外边距有效&lt;/td&gt;
&lt;td&gt;内边距、外边距和边框在所有方向都会撑大元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;常见元素&lt;/td&gt;
&lt;td&gt;&lt;code&gt;div&lt;/code&gt;、&lt;code&gt;p&lt;/code&gt;、&lt;code&gt;h1&lt;/code&gt;~&lt;code&gt;h6&lt;/code&gt;、&lt;code&gt;ul&lt;/code&gt;、&lt;code&gt;table&lt;/code&gt; 等&lt;/td&gt;
&lt;td&gt;&lt;code&gt;span&lt;/code&gt;、&lt;code&gt;em&lt;/code&gt;、&lt;code&gt;a&lt;/code&gt;、&lt;code&gt;strong&lt;/code&gt; 等&lt;/td&gt;
&lt;td&gt;&lt;code&gt;img&lt;/code&gt;、&lt;code&gt;input&lt;/code&gt;、&lt;code&gt;button&lt;/code&gt; 等，或通过 &lt;code&gt;display: inline-block&lt;/code&gt; 设置的元素&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;盒子模型组成&lt;/h2&gt;
&lt;p&gt;CSS 盒模型整体上适用于区块盒子，包含盒子内容、内边距、外边距、边框四部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;盒子内容。显示内容的区域，由内容或者指定高度来决定内容大小。&lt;/li&gt;
&lt;li&gt;内边距 padding。显示内容距离边框的距离。&lt;/li&gt;
&lt;li&gt;边框 border。边框盒子包住内容和内边距。&lt;/li&gt;
&lt;li&gt;外边距 margin。该盒子与其他元素之间的距离。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;images/box-model.png&quot; alt=&quot;CSS 盒模型&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;边框&lt;/h2&gt;
&lt;h3&gt;基础边框&lt;/h3&gt;
&lt;p&gt;border 属性用于设置盒子边框。可以设置四条或者单独边框。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*border: 边框粗细 边框样式 边框颜色*/
/*用三部分属性值组成，中间必须空格隔开*/
/*三部分属性值没有先后顺序*/
div {
  /*1像素 实线 颜色*/
  border: 1px solid #66ccff;
  /*dotted 点状边框 dashed 虚线边框 solid 实线边框 double 双线*/
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;border 也可以用于设置不同的边框，或者用于制作分割线等效果。&lt;/p&gt;
&lt;p&gt;属性（方位名词）：border-top border-bottom border-left border-right&lt;/p&gt;
&lt;h3&gt;圆角边框&lt;/h3&gt;
&lt;p&gt;border-radius 允许你设置边框圆角（或圆形）。常用于胶囊按钮、圆角、圆形裁剪。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.button {
  /*属性值为数字或百分比*/
  border-radius: 10px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;胶囊圆角：矩形设置圆角为短边的一半&lt;/p&gt;
&lt;p&gt;圆形：正方形设置圆角为边长的一半或者 50%&lt;/p&gt;
&lt;p&gt;特殊情况：单个的圆角&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;圆角写法&lt;/th&gt;
&lt;th&gt;作用（对应四个角：左上 → 右上 → 右下 → 左下）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;border-radius: 10px;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;四个角的圆角半径均为 &lt;strong&gt;10px&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;border-radius: 10px 20px;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;左上、右下为 &lt;strong&gt;10px&lt;/strong&gt;，右上、左下为 &lt;strong&gt;20px&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;border-radius: 10px 20px 30px;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;左上为 &lt;strong&gt;10px&lt;/strong&gt;，右上、左下为 &lt;strong&gt;20px&lt;/strong&gt;，右下为 &lt;strong&gt;30px&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;border-radius: 10px 20px 30px 40px;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;左上 &lt;strong&gt;10px&lt;/strong&gt;，右上 &lt;strong&gt;20px&lt;/strong&gt;，右下 &lt;strong&gt;30px&lt;/strong&gt;，左下 &lt;strong&gt;40px&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;border-radius&lt;/code&gt; 的值遵循 &lt;strong&gt;顺时针&lt;/strong&gt; 顺序：左上 → 右上 → 右下 → 左下。&lt;/li&gt;
&lt;li&gt;当值的数量少于 4 个时，会按以下规则复用：
&lt;ul&gt;
&lt;li&gt;1 个值：四个角相同。&lt;/li&gt;
&lt;li&gt;2 个值：第 1 个值作用于左上和右下，第 2 个值作用于右上和左下。&lt;/li&gt;
&lt;li&gt;3 个值：第 1 个值作用于左上，第 2 个值作用于右上和左下，第 3 个值作用于右下。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;内边距&lt;/h2&gt;
&lt;p&gt;内边距位于边框和内容区域之间。可以让盒子内容和边框保留一定距离，更美观。&lt;/p&gt;
&lt;p&gt;内边距的属性与圆角一样，多个值用空格隔开。顺时针顺序。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;内边距写法&lt;/th&gt;
&lt;th&gt;作用（对应四个方向：上 → 右 → 下 → 左）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;padding: 10px;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;上、右、下、左四个方向的内边距均为 &lt;strong&gt;10px&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;padding: 10px 20px;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;上、下内边距为 &lt;strong&gt;10px&lt;/strong&gt;，右、左内边距为 &lt;strong&gt;20px&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;padding: 10px 20px 30px;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;上内边距为 &lt;strong&gt;10px&lt;/strong&gt;，右、左内边距为 &lt;strong&gt;20px&lt;/strong&gt;，下内边距为 &lt;strong&gt;30px&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;padding: 10px 20px 30px 40px;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;上 &lt;strong&gt;10px&lt;/strong&gt;，右 &lt;strong&gt;20px&lt;/strong&gt;，下 &lt;strong&gt;30px&lt;/strong&gt;，左 &lt;strong&gt;40px&lt;/strong&gt;（顺时针）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;单边设置同 border 一致，通过方位名词来控制：&lt;/p&gt;
&lt;p&gt;padding-top padding-bottom padding-left padding-right&lt;/p&gt;
&lt;h2&gt;外边距&lt;/h2&gt;
&lt;p&gt;外边距是盒子周围一圈看不到的空间，会把其他元素推离盒子，也就是不同盒子之间的碰撞体积，用来设置盒子间的间距。&lt;/p&gt;
&lt;p&gt;外边距的写法和内边距完全一致。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;行内元素的左右外边距生效，上下外边距无效。&lt;/li&gt;
&lt;li&gt;行内元素的宽度和高度设置也无效。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;块级元素可以利用 margin 实现水平居中：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;块级盒子必须有宽度&lt;/li&gt;
&lt;li&gt;只需要设置左右外边距为 auto 即可&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;.box1 {
  /*左侧占满，右对齐*/
  margin-left: auto;
}

.box2 {
  /*右侧占满，左对齐*/
  margin-right: auto;
}

.box1 {
  /*两侧占满，居中对齐*/
  margin: 0 auto;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;外边距折叠&lt;/h3&gt;
&lt;p&gt;区块元素上下外边距会出现折叠（合并）情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;并列关系（兄弟）的区块元素。&lt;/li&gt;
&lt;li&gt;两个上下边距将合并为一个外边距，其大小等于最大的单个外边距&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;.boxA{
  width: 100px;
  height: 100px;
  background-color: pink;
  margin-bottom: 100px;
}

.boxB{
  width: 100px;
  height: 100px;
  background-color: pink;
  margin-top: 50px;
}

/*这里两个元素的上下外边距为 100px*/
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;外边距塌陷&lt;/h3&gt;
&lt;p&gt;区块元素上下外边距会出现塌陷情况。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;嵌套关系（父子）的区块元素&lt;/li&gt;
&lt;li&gt;给子盒子设置上下外边距会让父盒子塌陷移动。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;子元素的上外边距会变为父元素的上外边距让父元素一起塌陷移动。&lt;/p&gt;
&lt;p&gt;当发生塌陷时，最终的外边距遵循以下规则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;全是正数：&lt;/strong&gt; 取最大值（例如 20px 和 30px 塌陷后是 30px）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一正一负：&lt;/strong&gt; 取两者相加的和（例如 20px 和 -10px 塌陷后是 10px）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全是负数：&lt;/strong&gt; 取绝对值最大的那个（例如 -20px 和 -30px 塌陷后是 -30px）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可以通过以下方法打破塌陷条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;创建 BFC（块级格式化上下文）：&lt;/strong&gt; 设置 &lt;code&gt;overflow: hidden;&lt;/code&gt; 或 &lt;code&gt;display: flow-root;&lt;/code&gt;（最推荐）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;添加阻隔物：&lt;/strong&gt; 给父元素添加 &lt;code&gt;border&lt;/code&gt; 或 &lt;code&gt;padding&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;改变定位/浮动：&lt;/strong&gt; 使用 &lt;code&gt;float&lt;/code&gt; 或 &lt;code&gt;position: absolute;&lt;/code&gt; / &lt;code&gt;fixed;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用 Flex 或 Grid 布局：&lt;/strong&gt; Flexbox 和 Grid 容器中的子元素不会发生外边距塌陷。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;尺寸计算&lt;/h2&gt;
&lt;p&gt;在 CSS 盒子模型的默认定义里，除了宽度和高度增加盒子大小之外，padding 和 margin 都会让盒子变大。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.box {
  width: 200px;
  border: 5px;
  padding: 10px;
}
/*盒子的实际宽度为： 200+5+5+10+10=230px*/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;box-sizing&lt;/code&gt; 用于定义元素的盒子模型计算方式，控制元素的 width 和 height 是否包含 padding 和 border。&lt;/p&gt;
&lt;p&gt;语法：&lt;code&gt;box-sizing: 属性值&lt;/code&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;属性值&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;content-box&lt;/td&gt;
&lt;td&gt;默认值。元素的 width 和 height 仅包含内容区域，不包含 padding 和 border。理解：width = 内容的宽度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;border-box&lt;/td&gt;
&lt;td&gt;元素的 width 和 height 包含内容、padding 和 border。理解：width = border + padding + 内容的宽度&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;标准盒模型与怪异盒模型&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;标准盒模型：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.box {
  box-sizing: content-box; /* 默认值 */
  width: 200px;
  padding: 20px;
  border: 5px solid #000;
}
/* 盒子实际宽度 = 200 + 20*2 + 5*2 = 250px */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;怪异盒模型：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.box {
  box-sizing: border-box;
  width: 200px;
  padding: 20px;
  border: 5px solid #000;
}
/* 盒子实际宽度 = 200px */
/* 内容宽度 = 200 - 20*2 - 5*2 = 150px */
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;怪异盒模型起源于早期浏览器（IE5 及以下版本）的非标准实现。CSS3 引入 &lt;code&gt;box-sizing&lt;/code&gt; 属性后，开发者可以自由选择使用哪种盒模型。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;推荐全局使用 border-box：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*,
*::before,
*::after {
  box-sizing: border-box;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;计算更直观：设置的宽度就是盒子的实际宽度。&lt;/li&gt;
&lt;li&gt;布局更稳定：添加 padding 或 border 不会撑大盒子。&lt;/li&gt;
&lt;li&gt;响应式友好：百分比宽度布局时，不用担心溢出。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;BFC（块级格式化上下文）&lt;/h2&gt;
&lt;p&gt;BFC（Block Formatting Context，块级格式化上下文）是 Web 页面中一个独立的渲染区域，拥有一套独立的布局规则。&lt;/p&gt;
&lt;h3&gt;BFC 的触发条件&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;属性/值&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;值不为 &lt;code&gt;none&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;position&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;值为 &lt;code&gt;absolute&lt;/code&gt; 或 &lt;code&gt;fixed&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;display&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;值为 &lt;code&gt;inline-block&lt;/code&gt;、&lt;code&gt;table-cell&lt;/code&gt;、&lt;code&gt;table-caption&lt;/code&gt;、&lt;code&gt;flow-root&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;overflow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;值不为 &lt;code&gt;visible&lt;/code&gt;（如 &lt;code&gt;hidden&lt;/code&gt;、&lt;code&gt;auto&lt;/code&gt;、&lt;code&gt;scroll&lt;/code&gt;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;display: flex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Flex 子项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;display: grid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Grid 子项&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;推荐使用 &lt;code&gt;display: flow-root&lt;/code&gt;&lt;/strong&gt;：这是专门用于创建 BFC 的属性值，无副作用，语义清晰。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;BFC 的特性&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;独立的布局环境：BFC 内部的元素不会影响外部元素。&lt;/li&gt;
&lt;li&gt;计算高度时包含浮动元素：可以清除浮动。&lt;/li&gt;
&lt;li&gt;不会与浮动元素重叠：可以实现自适应两栏布局。&lt;/li&gt;
&lt;li&gt;阻止外边距塌陷：不同 BFC 的元素外边距不会塌陷。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;BFC 的应用场景&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;清除浮动：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当子元素浮动时，父元素高度会塌陷。创建 BFC 可以让父元素包含浮动子元素：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.parent {
  display: flow-root; /* 推荐 */
  /* 或 overflow: hidden; */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;阻止外边距塌陷：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.parent {
  display: flow-root; /* 或 overflow: hidden */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;自适应两栏布局：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;BFC 区域不会与浮动元素重叠：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.sidebar {
  float: left;
  width: 200px;
}

.main {
  display: flow-root; /* 不与浮动元素重叠 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;margin 负值的应用&lt;/h2&gt;
&lt;p&gt;margin 负值是一个强大的布局技巧。&lt;/p&gt;
&lt;h3&gt;基本行为&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方向&lt;/th&gt;
&lt;th&gt;效果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin-left: -10px&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素向左移动 10px&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin-right: -10px&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素右侧边界向内收缩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin-top: -10px&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素向上移动 10px&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin-bottom: -10px&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素下方边界向内收缩&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;常见应用场景&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;元素重叠效果：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.card {
  margin-left: -20px; /* 向左重叠 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;等分布局中的边框处理：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;多个元素等分排列时，每个元素都有边框会导致边框重复：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.item {
  border-right: 1px solid #ccc;
  margin-right: -1px; /* 负边框宽度 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;圣杯布局/双飞翼布局：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;经典的三栏布局中，margin 负值用于调整列的位置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.main {
  width: 100%;
  float: left;
}

.left {
  width: 200px;
  float: left;
  margin-left: -100%; /* 移动到最左侧 */
}

.right {
  width: 150px;
  float: left;
  margin-left: -150px; /* 移动到最右侧 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;水平垂直居中：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;结合定位实现居中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.box {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 200px;
  height: 100px;
  margin-top: -50px;  /* 高度的一半 */
  margin-left: -100px; /* 宽度的一半 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;padding 百分比的特性&lt;/h2&gt;
&lt;p&gt;padding 使用百分比时，有一个重要特性：&lt;strong&gt;百分比相对于父元素的宽度计算&lt;/strong&gt;（无论方向）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.parent {
  width: 300px;
}

.child {
  padding-top: 10%;    /* 30px */
  padding-right: 10%;  /* 30px */
  padding-bottom: 10%; /* 30px */
  padding-left: 10%;   /* 30px */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;实际应用&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;等比例盒子：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;利用 padding 百分比特性，可以创建固定宽高比的容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* 16:9 视频容器 */
.video-container {
  width: 100%;
  padding-top: 56.25%; /* 9/16 = 0.5625 */
  position: relative;
}

.video-container video {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

/* 1:1 正方形 */
.square {
  width: 100px;
  padding-top: 100%;
}

/* 4:3 比例 */
.ratio-4-3 {
  width: 100%;
  padding-top: 75%; /* 3/4 = 0.75 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;响应式图片占位：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;图片加载前保持占位空间，避免布局抖动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.image-placeholder {
  width: 100%;
  padding-top: 66.67%; /* 2:3 比例 */
  background: #f0f0f0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;这种设计是为了保持水平和垂直方向的一致性，使得宽高比例在不同屏幕尺寸下保持不变。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;行内块元素的空白符问题&lt;/h2&gt;
&lt;p&gt;多个行内块元素之间会出现莫名其妙的间隙。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因：&lt;/strong&gt; HTML 中的换行符、空格、制表符等空白字符在渲染时会产生一个空格大小的间隙（约 4px，取决于字体）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
  &amp;lt;span class=&quot;item&quot;&amp;gt;项目1&amp;lt;/span&amp;gt;
  &amp;lt;span class=&quot;item&quot;&amp;gt;项目2&amp;lt;/span&amp;gt;
  &amp;lt;span class=&quot;item&quot;&amp;gt;项目3&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;解决方法&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;方法一：去除 HTML 中的空白符&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&quot;container&quot;&amp;gt;
  &amp;lt;span class=&quot;item&quot;&amp;gt;项目1&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;item&quot;&amp;gt;项目2&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;item&quot;&amp;gt;项目3&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;方法二：父元素 font-size: 0&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container {
  font-size: 0; /* 消除空白符间隙 */
}

.item {
  display: inline-block;
  font-size: 16px; /* 恢复子元素字体大小 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;方法三：负边距&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.item {
  display: inline-block;
  margin-right: -4px; /* 消除间隙 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;方法四：使用 Flex 布局（推荐）&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.container {
  display: flex;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常见问题与调试技巧&lt;/h2&gt;
&lt;h3&gt;常见问题&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;width: 100% + padding 导致溢出：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* 问题代码 */
.box {
  width: 100%;
  padding: 20px; /* 实际宽度超出父容器 */
}

/* 解决方法 */
.box {
  box-sizing: border-box;
  width: 100%;
  padding: 20px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;margin: 0 auto 失效的原因：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;元素没有设置 &lt;code&gt;width&lt;/code&gt;（块级元素默认占满宽度）&lt;/li&gt;
&lt;li&gt;元素设置了 &lt;code&gt;float&lt;/code&gt;、&lt;code&gt;position: absolute&lt;/code&gt; 或 &lt;code&gt;position: fixed&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;元素是 &lt;code&gt;display: inline&lt;/code&gt; 或 &lt;code&gt;inline-block&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;父元素设置了 &lt;code&gt;display: flex&lt;/code&gt;（应使用 &lt;code&gt;justify-content: center&lt;/code&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;子元素 margin 影响父元素：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;给子元素设置 margin-top 时，父元素跟着移动（外边距塌陷）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.parent {
  overflow: hidden; /* 或 display: flow-root */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;border-radius 对不规则形状的影响：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;border-radius&lt;/code&gt; 只对有背景或边框的区域生效。如果没有背景或边框，看不到圆角效果。&lt;/p&gt;
&lt;h3&gt;调试技巧&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;使用浏览器开发者工具：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;右键元素 → 检查（或按 F12）&lt;/li&gt;
&lt;li&gt;在 Elements 面板查看盒模型图示&lt;/li&gt;
&lt;li&gt;可以直观看到 content、padding、border、margin 的大小&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;可视化盒模型：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* {
  outline: 1px solid rgba(255, 0, 0, 0.5);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;全局 border-box 设置：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*,
*::before,
*::after {
  box-sizing: border-box;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;现代 CSS 相关&lt;/h2&gt;
&lt;h3&gt;aspect-ratio 属性&lt;/h3&gt;
&lt;p&gt;CSS 新增的 &lt;code&gt;aspect-ratio&lt;/code&gt; 属性可以直接设置宽高比，无需依赖 padding 百分比技巧：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* 传统方法 */
.video-old {
  width: 100%;
  padding-top: 56.25%;
  position: relative;
}

/* 新方法 */
.video-new {
  width: 100%;
  aspect-ratio: 16 / 9;
}

/* 正方形 */
.square {
  width: 100px;
  aspect-ratio: 1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;兼容性：现代浏览器已广泛支持（Chrome 88+, Firefox 89+, Safari 15+）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;逻辑属性&lt;/h3&gt;
&lt;p&gt;CSS 逻辑属性提供了基于书写方向的属性，支持国际化布局：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;物理属性&lt;/th&gt;
&lt;th&gt;逻辑属性&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin-top&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;margin-block-start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;块级方向起始边距&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin-bottom&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;margin-block-end&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;块级方向结束边距&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin-left&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;margin-inline-start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;行内方向起始边距&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin-right&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;margin-inline-end&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;行内方向结束边距&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;padding-top&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;padding-block-start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;块级方向起始内边距&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;width&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inline-size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;行内方向尺寸&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;height&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;block-size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;块级方向尺寸&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;.box {
  /* 传统写法 */
  margin: 10px 20px;
  
  /* 逻辑属性写法 */
  margin-block: 10px;
  margin-inline: 20px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;优势：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;自动适应不同的书写模式（如从右到左的语言）。&lt;/li&gt;
&lt;li&gt;无需为不同语言方向编写多套样式。&lt;/li&gt;
&lt;li&gt;更好的国际化支持。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;gap 属性&lt;/h3&gt;
&lt;p&gt;在 Flexbox 和 Grid 布局中，&lt;code&gt;gap&lt;/code&gt; 属性可以替代传统的 margin 实现间距：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* Flexbox */
.flex-container {
  display: flex;
  gap: 10px 20px; /* 行间距 列间距 */
}

/* Grid */
.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;优势：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;无需处理外边距塌陷。&lt;/li&gt;
&lt;li&gt;不会在首尾元素产生多余间距。&lt;/li&gt;
&lt;li&gt;代码更简洁直观。&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>CSS 文本样式</title><link>https://blog.sheyiyuan.com/notes/css-%E6%96%87%E6%9C%AC%E6%A0%B7%E5%BC%8F/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/notes/css-%E6%96%87%E6%9C%AC%E6%A0%B7%E5%BC%8F/</guid><pubDate>Thu, 15 May 2025 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CSS 文本样式用于控制网页中文字的外观，包括字体、颜色、对齐、间距等，主要分为两大类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字体样式
&lt;ul&gt;
&lt;li&gt;使用哪种字体，字体大小、字体粗体、斜体，等等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;文本布局
&lt;ul&gt;
&lt;li&gt;文本对齐、行高、字间距、首行缩进等等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：CSS 不能直接“选中纯文本节点”来设置样式，通常是给承载文本的 HTML 元素设置样式，文本随元素样式变化。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;字体样式&lt;/h2&gt;
&lt;p&gt;给文字设置颜色、大小、粗体、装饰等效果。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字体样式&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;color&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;设置字体颜色&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;font-family&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;字体族&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;font-size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;字体大小&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;font-style&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;字体风格&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;font-weight&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;字体粗体&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;text-decoration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;字体装饰&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;字体颜色（color）&lt;/h2&gt;
&lt;p&gt;常用十六进制，如 &lt;code&gt;#66ccff&lt;/code&gt; ，部分时候使用 &lt;code&gt;rgb&lt;/code&gt; 和 &lt;code&gt;rgba&lt;/code&gt; ，&lt;code&gt;rgba&lt;/code&gt; 的最后一个数值取 0~1 表示透明度，0 完全透明，1 完全不透明，如 &lt;code&gt;rgba(155,0,0,0.3)&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;字体族（font-family）&lt;/h2&gt;
&lt;p&gt;字体族可以用字体名称设置。可以给定一个有先后顺序的，由字体名字或字体族名组成的列表来为选定的元素设置字体。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
  /*属性值用逗号隔开。浏览器会选择列表中第一个该计算机上安装的字体，没有则使用默认*/
  font-family: Arial, Helvetica, sans-serif;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;字体大小（font-size）&lt;/h2&gt;
&lt;p&gt;字体大小可以用 px 设置。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;CSS 像素（CSS pixel，即 px）是 CSS 中用于指定长度、尺寸的单位，是绝对单位。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不同浏览器默认字体大小不一样，Chrome 默认 16px，建议给 &lt;code&gt;body&lt;/code&gt; 标签统一指定大小，做到浏览器统一。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
  font-size: 16px;
}

.font12 {
  font-size: 12px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;字体风格（font-style）&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;font-style&lt;/code&gt; 用来打开和关闭文本斜体（Italic）。&lt;/p&gt;
&lt;p&gt;属性值： &lt;code&gt;normal&lt;/code&gt; / &lt;code&gt;italic&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;常见用法：让 em 或 i 标签取消默认倾斜&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;em {
  font-style: normal;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;字体粗细（font-weight）&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;font-weight&lt;/code&gt; 设置文字粗细。&lt;/p&gt;
&lt;p&gt;使用场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;很多标题是不要加粗的，此时利用 CSS 取消加粗。&lt;/li&gt;
&lt;li&gt;大段文本也可以通过 CSS 统一设置粗细。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;属性值： &lt;code&gt;normal&lt;/code&gt; / &lt;code&gt;bold&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;**数字属性值（常用）：**400（正常粗细）/ 700（加粗）（取值 100-900 之间，常用400 和 700）&lt;/p&gt;
&lt;h2&gt;字体装饰（text-decoration）&lt;/h2&gt;
&lt;p&gt;设置 / 取消字体上的文本装饰&lt;/p&gt;
&lt;p&gt;使用场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;最常见设置下划线，比如取消超链接下划线。&lt;/li&gt;
&lt;li&gt;特殊情况添加删除线。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;属性值&lt;code&gt;none&lt;/code&gt; （无装饰）/ &lt;code&gt;underline&lt;/code&gt; （下划线）/ &lt;code&gt;overline&lt;/code&gt; （上划线）/ &lt;code&gt;line-through&lt;/code&gt; (删除线)&lt;/p&gt;
&lt;h2&gt;文本布局&lt;/h2&gt;
&lt;p&gt;作用于文本的对齐、缩进、间距等布局功能的属性。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;文本属性&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;text-align&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;文本对齐（不适用于普通行内元素）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;text-indent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;首行缩进（不适用于普通行内元素）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;letter-spacing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;文本字符间距&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;line-height&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;行高&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;文本对齐（text-align）&lt;/h2&gt;
&lt;p&gt;控制文本在它所在的块级盒子内如何&lt;strong&gt;水平对齐&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;使用场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;文本 / 图片在盒子水平对齐&lt;/li&gt;
&lt;li&gt;使文章文字两端对齐&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;属性值： &lt;code&gt;left&lt;/code&gt; （左对齐，默认）/ &lt;code&gt;right&lt;/code&gt; （右对齐）/ &lt;code&gt;center&lt;/code&gt; （居中对齐）/ &lt;code&gt;justify&lt;/code&gt; （两端对齐）&lt;/p&gt;
&lt;h2&gt;首行缩进（text-indent）&lt;/h2&gt;
&lt;p&gt;设置块级元素中文本首行缩进的长度。&lt;/p&gt;
&lt;p&gt;属性值：数字&lt;/p&gt;
&lt;p&gt;常见单位是 em，相对单位，本元素的字体大小。如果当前元素没有大小，按照父元素文字大小。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;p {
  /*首行缩进两字符*/
  text-indent: 2em;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;字间距（letter-spacing）&lt;/h2&gt;
&lt;p&gt;用于设置文本字符的间距。调整字与字之间的距离。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;p {
  /*字间距可以为负*/
  letter-spacing: 2px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;行高（line-height）&lt;/h2&gt;
&lt;p&gt;设置文本每行之间的高度。&lt;/p&gt;
&lt;p&gt;使用场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;设置多行文本之间的上下间距。&lt;/li&gt;
&lt;li&gt;让单行文本垂直居中&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;属性值常见写法：&lt;code&gt;px&lt;/code&gt; / &lt;code&gt;em&lt;/code&gt; / 无单位数字（推荐）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;p {
  /*若当前文字大小为 10px，则行高为15px*/
  line-height: 1.5;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用行高可以实现单行文本垂直居中。&lt;/p&gt;
&lt;p&gt;原理：行高的组成是文字自身大小加上上下间距共同构成的。行高调整的本质是同样大小调整上下间距。当&lt;strong&gt;行高和盒子的高度一致&lt;/strong&gt;时就可以实现&lt;strong&gt;单行文本&lt;/strong&gt;垂直居中。&lt;/p&gt;
&lt;h2&gt;font 简写&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;font&lt;/code&gt; 简写属性可以在一个声明中设置多个字体相关属性。&lt;/p&gt;
&lt;p&gt;使用场景：给整个页面设置相关字体样式&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;body {
  font: font-style font-weight font-size/line-height font-family;
  /*font-size 和 font-family 必须写*/
  /*其他可以省略，默认显示*/
  /*这种写法有严格的书写顺序，不能调换*/
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;CSS 继承性（inherit）&lt;/h2&gt;
&lt;p&gt;子元素会自动继承父元素的某些 CSS 样式属性。&lt;/p&gt;
&lt;p&gt;主要继承和文字相关的样式，比如字体、颜色、文本对齐等。&lt;/p&gt;
&lt;h2&gt;常用补充（实战高频）&lt;/h2&gt;
&lt;p&gt;除了上面这些，日常开发里还有一批非常常用的文本样式：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;属性&lt;/th&gt;
&lt;th&gt;常见用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;white-space&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;控制是否换行、是否保留空白&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;text-overflow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;单行文本溢出省略号&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;word-break&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;长单词/长字符串换行策略&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;overflow-wrap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;避免超长单词撑破容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;text-transform&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;英文大小写转换（标题、按钮常用）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;text-shadow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;文本阴影（强调文字层次）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;white-space（空白与换行）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/* 常见：正常换行 */
p {
    white-space: normal;
}

/* 不换行，常用于单行省略 */
.single-line {
    white-space: nowrap;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;text-overflow（文本溢出）&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;text-overflow: ellipsis&lt;/code&gt; 需要和 &lt;code&gt;overflow: hidden&lt;/code&gt;、&lt;code&gt;white-space: nowrap&lt;/code&gt; 配合使用。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.single-line-ellipsis {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;word-break / overflow-wrap（长文本换行）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;.content {
    /* 英文长单词或超长 URL 更容易换行 */
    overflow-wrap: break-word;

    /* CJK 和英文混排时可按需使用 */
    word-break: break-word;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;text-transform（英文大小写）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;.btn {
    text-transform: uppercase;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;常见属性值：&lt;code&gt;none&lt;/code&gt; / &lt;code&gt;uppercase&lt;/code&gt; / &lt;code&gt;lowercase&lt;/code&gt; / &lt;code&gt;capitalize&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;text-shadow（文字阴影）&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;.hero-title {
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;语法顺序一般是：&lt;code&gt;水平偏移 垂直偏移 模糊半径 颜色&lt;/code&gt;。&lt;/p&gt;
</content:encoded></item><item><title>CSS 选择器</title><link>https://blog.sheyiyuan.com/notes/css-%E9%80%89%E6%8B%A9%E5%99%A8/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/notes/css-%E9%80%89%E6%8B%A9%E5%99%A8/</guid><pubDate>Wed, 14 May 2025 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CSS 选择器是 CSS 规则的一部分，用于选择 HTML 元素。&lt;/p&gt;
&lt;p&gt;CSS 属性采用键值对形式：&lt;code&gt;&amp;lt;属性名&amp;gt;: &amp;lt;属性值&amp;gt;;&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*p是选择器*/
p {
  /*属性*/
  color: red;
  font-size: 14px;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;CSS选择器：选择标签&lt;/li&gt;
&lt;li&gt;CSS属性：修改样式&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;选择器分类&lt;/h2&gt;
&lt;p&gt;根据使用场景不同，选择器分类也不同。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基础选择器&lt;/li&gt;
&lt;li&gt;关系选择器&lt;/li&gt;
&lt;li&gt;分组选择器&lt;/li&gt;
&lt;li&gt;伪类和伪元素&lt;/li&gt;
&lt;li&gt;属性选择器&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;基础选择器&lt;/h2&gt;
&lt;p&gt;基础选择器是指由单个选择器组成，常见的有下面几种：&lt;/p&gt;
&lt;h3&gt;类型选择器&lt;/h3&gt;
&lt;p&gt;选择某个类型的元素，也成为标签选择器&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*选择所有div标签样式*/
div {
  color: red;
}

/*选择所有span标签样式*/
span {
  color: yellow;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;层叠性：多个 CSS 规则可以同时作用于同一个元素，浏览器会优先执行最近的元素样式，后面的 CSS 会覆盖前面的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;类选择器&lt;/h3&gt;
&lt;p&gt;类选择器用于选择一个或多个元素&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/* blue 为类名，用 . 开头 */
.blue {
  color: blue;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul&amp;gt;
  &amp;lt;li&amp;gt;牌烧完了我打什么？&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;转来转去像个小丑&amp;lt;/li&amp;gt;
  &amp;lt;li class=&quot;blue&quot;&amp;gt;故障机器人最强故障机器人最&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;哎，诶诶&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;谁要用谁调用，类选择器需要显式声明。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意事项&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;类名建议使用有语义的英文，不建议使用纯数字&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多个单词组成尽量使用 &lt;code&gt;-&lt;/code&gt; 连接&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;class属性可以有多个类名，中间用空格隔开&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h3&gt;ID 选择器&lt;/h3&gt;
&lt;p&gt;选择 HTML 中具有特定 id 属性的唯一元素&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*#开头*/
#header {
  color: red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;ul id=&quot;header&quot;&amp;gt;
  &amp;lt;li&amp;gt;牌烧完了我打什么？&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;转来转去像个小丑&amp;lt;/li&amp;gt;
  &amp;lt;li class=&quot;blue&quot;&amp;gt;故障机器人最强故障机器人最&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;哎，诶诶&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;类选择器和ID选择器的区别&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;类选择器&lt;/th&gt;
&lt;th&gt;ID 选择器&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;语法&lt;/td&gt;
&lt;td&gt;以 . 开头，后跟类名&lt;/td&gt;
&lt;td&gt;以 # 开头，后跟 id 名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;作用&lt;/td&gt;
&lt;td&gt;选择 class 属性的一个或多个元素&lt;/td&gt;
&lt;td&gt;选择特定 id 属性的唯一元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;特点&lt;/td&gt;
&lt;td&gt;可以使用多次&lt;/td&gt;
&lt;td&gt;同一页面中，id 值必须唯一&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;场景&lt;/td&gt;
&lt;td&gt;后期修改样式基本都是类选择器&lt;/td&gt;
&lt;td&gt;后期主要是配合JavaScript添加交互效果&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;通配符选择器&lt;/h3&gt;
&lt;p&gt;通配符选择器可以选择 HTML 中所有的标签，进行样式修改&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* {
  margin: 0;
  padding: 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;特殊情况下通过通配符清除所有元素的默认边距和填充，统一不同浏览器的默认样式。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* {
  margin: 0; /*去除所有元素的外边距*/
  padding: 0; /*去除所有元素的内边距*/
  box-sizing: border-box; /*统一盒模型*/
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;选择器类型&lt;/th&gt;
&lt;th&gt;语法示例&lt;/th&gt;
&lt;th&gt;匹配范围&lt;/th&gt;
&lt;th&gt;复用性&lt;/th&gt;
&lt;th&gt;典型使用场景&lt;/th&gt;
&lt;th&gt;注意事项&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;类型选择器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;div { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配所有指定 HTML 标签元素&lt;/td&gt;
&lt;td&gt;某一类型标签&lt;/td&gt;
&lt;td&gt;全局样式重置、基础标签样式（如 body, p）&lt;/td&gt;
&lt;td&gt;避免滥用，可能导致样式冲突&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;类选择器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.nav { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配所有含指定 class 的元素&lt;/td&gt;
&lt;td&gt;多次使用&lt;/td&gt;
&lt;td&gt;多元素共享样式&lt;/td&gt;
&lt;td&gt;优先使用，避免与 ID 选择器冲突&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ID 选择器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#header { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配唯一含指定 id 的元素&lt;/td&gt;
&lt;td&gt;唯一性&lt;/td&gt;
&lt;td&gt;唯一元素标识&lt;/td&gt;
&lt;td&gt;必须唯一，避免样式覆盖风险&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;通配符选择器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;* { ... }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配所有元素&lt;/td&gt;
&lt;td&gt;全局覆盖&lt;/td&gt;
&lt;td&gt;全局样式重置&lt;/td&gt;
&lt;td&gt;性能较差，慎用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;大部分情况下，&lt;strong&gt;类选择器&lt;/strong&gt;是最重要的。&lt;/p&gt;
&lt;h2&gt;关系选择器&lt;/h2&gt;
&lt;p&gt;关系选择器通过位置关系来选择目标元素（标签），可以更精准选择某些元素。常见的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;后代选择器&lt;/li&gt;
&lt;li&gt;子代选择器&lt;/li&gt;
&lt;li&gt;邻接兄弟选择器&lt;/li&gt;
&lt;li&gt;通用兄弟选择器&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;后代选择器&lt;/h3&gt;
&lt;p&gt;选择某个元素的后代元素（不限层级，包括子元素、孙元素等）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*选择 box 类内部的所有 p 标签，父级和后代间用空格隔开*/
/*父级作用是限定，不会修改父级本身样式*/
/*父级和后代可以是两个任意类型的基础选择器*/
/*可以多级嵌套，只修改符合全部条件后代的选择器*/
.box p {
  color: skyblue;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;子代选择器&lt;/h3&gt;
&lt;p&gt;选择某个元素的直接子代元素，只限第一层的子代元素，不影响子代的后代。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.box &amp;gt; p {
  color: green;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;兄弟选择器&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;/*邻接兄弟选择器*/
/*选择 h2 后面的第一个同层级 p 标签*/
h2 + p {
  color: pink;
}
/*通用兄弟选择器*/
/*选择 h2 后面的所有同层级 p 标签*/
h2 ~ p {
  color: pink;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;总结&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;选择器&lt;/th&gt;
&lt;th&gt;语法&lt;/th&gt;
&lt;th&gt;选择范围&lt;/th&gt;
&lt;th&gt;实例&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;后代选择器（重点，最常用）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;所有后代（跨层级）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ul li { color: pink; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;子代选择器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A &amp;gt; B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;直接子元素（仅一层）&lt;/td&gt;
&lt;td&gt;&lt;code&gt;div &amp;gt; span { color: pink; }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;邻接兄弟选择器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A + B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;紧邻的下一个同级元素&lt;/td&gt;
&lt;td&gt;&lt;code&gt;h2 + p { ... }&lt;/code&gt; 标题后的第一个 &lt;code&gt;p&lt;/code&gt; 元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;通用兄弟选择器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A ~ B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A 之后的所有同级元素&lt;/td&gt;
&lt;td&gt;&lt;code&gt;h2 ~ p { ... }&lt;/code&gt; 标题后的所有 &lt;code&gt;p&lt;/code&gt; 元素&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;分组选择器&lt;/h2&gt;
&lt;p&gt;将不同的选择器组合在一起。使用逗号分隔。&lt;/p&gt;
&lt;p&gt;也称为并集选择器。&lt;/p&gt;
&lt;p&gt;使用场景：多个元素具备相同样式。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;p,
h1 {
  color: red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;伪类选择器&lt;/h2&gt;
&lt;p&gt;选择元素的特定状态或结构位置。符号是冒号（:）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;状态伪类&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据用户交互或状态变化选择。&lt;/li&gt;
&lt;li&gt;比如：鼠标经过链接、表单获得焦点等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;结构伪类&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据元素的位置选择。&lt;/li&gt;
&lt;li&gt;比如：选择第五个元素、选择前三个元素等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;表单伪类&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;针对表单元素的状态。&lt;/li&gt;
&lt;li&gt;比如：表单禁用、选中复选框等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;链接伪类&lt;/h3&gt;
&lt;p&gt;链接伪类用于根据链接的不同状态（如未访问、悬停、点击等）为其添加样式，从而提升用户体验和界面交互性。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;链接伪类&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a:link&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;未访问链接的默认样式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a:visited&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;已访问链接的样式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a:hover&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;鼠标悬停在链接上时的反馈样式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;a:active&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;链接被点击时的瞬时状态（按下到松开）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;伪类顺序规则（LVHA顺序，顺序不能变，原理是同级 CSS 样式的就近原则）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;a:link {
  color: #000000;
  text-decoration: none;
}
a:visited {
  color: #66ccff;
  text-decoration: none;
}
a:hover {
  color: #ee82ee;
  text-decoration: underline;
}
a:active {
  color: #f4004f;
  text-decoration: none;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;状态伪类&lt;/h3&gt;
&lt;p&gt;用户以某种方式和文档交互的时候应用，也称动态伪类。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;动态伪类&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:hover&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;鼠标经过元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:focus&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;获得焦点的元素（表单）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;.box {
  width: 300px;
  height: 300px;
  background-color: red; 
}

/*注意这里没有空格*/
.box:hover {
  background-color: skyblue;
}

.search:focus {
  background-color: rgba(255,0,0,0.2)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;结构伪类&lt;/h3&gt;
&lt;p&gt;根据元素的位置选择目标元素。&lt;/p&gt;
&lt;p&gt;使用场景：选择多个元素中的任意特定位置的元素。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;结构伪类&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:first-child&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;一组兄弟元素中的第一个元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:last-child&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;一组兄弟元素中的最后一个元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:nth-child(n)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;一组兄弟元素列表中的第 n 个元素&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这里n的取值可以是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数字。从1开始&lt;/li&gt;
&lt;li&gt;关键字。odd 奇数；even 偶数&lt;/li&gt;
&lt;li&gt;公式。
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;:nth-child(3n)&lt;/code&gt; 3 的倍数，第 3,6,9…个元素&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:nth-child(n+2)&lt;/code&gt; 第 2 个以及以后的元素&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:nth-child(-n+3)&lt;/code&gt; 前三个元素&lt;/li&gt;
&lt;li&gt;注意公式的 n 的取值从 0 开始计算&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;ul li:first-child {
  color: pink;
  /* 第一个li元素的字体颜色为粉色 */
}

ul li:nth-child(2) {
  color: blue;
  /* 第二个li元素的字体颜色为蓝色 */
}

ul li:last-child {
  color: green;
  /* 最后一个li元素的字体颜色为绿色 */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;表单伪类&lt;/h3&gt;
&lt;p&gt;针对表单元素的状态&lt;/p&gt;
&lt;p&gt;使用场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;表单禁用的时候，调整颜色&lt;/li&gt;
&lt;li&gt;复选框选中修改样式&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;表单伪类&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:disabled&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;表单禁用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:checked&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;选中状态，单选 / 复选按钮&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;button:disabled {
  /*透明度，让整个元素透明*/
  opacity: .4;
}

input:checked+label {
  color: #ff6900;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;伪元素选择器&lt;/h3&gt;
&lt;p&gt;选择元素的特定部分。（使用双冒号::）&lt;/p&gt;
&lt;p&gt;使用场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;让表单里的 placeholder 文字改变颜色。&lt;/li&gt;
&lt;li&gt;做很多的修饰效果。&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;伪元素选择器&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::first-line&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;选择元素的首行文本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::first-letter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;选择元素的首字母（或首字符）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::placeholder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;选择 &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; 或 &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; 的占位符文本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::before&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素内插入伪元素，作为第一个元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::after&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元素内插入伪元素，作为最后一个元素&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;p::first-line {
  color: #66ccff;
}

p::first-letter {
  font-size: 28px;
}

div::before {
  content: &quot;start&quot;;
  color: red;
}

div::after {
  content: &quot;end&quot;;
  color: red;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;::before&lt;/code&gt; 和 &lt;code&gt;::after&lt;/code&gt; 是插入的伪元素，特性类似内联元素。&lt;/p&gt;
&lt;p&gt;content 属性是必须，不能省略，没有内容空字符串即可。&lt;/p&gt;
&lt;p&gt;常用于实现小图标和各种装饰效果。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;属性选择器&lt;/h2&gt;
&lt;p&gt;根据元素的属性来精准定位元素，从而实现更灵活的样式控制。&lt;/p&gt;
&lt;p&gt;使用场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;表单样式控制。&lt;/li&gt;
&lt;li&gt;图标字体控制。&lt;/li&gt;
&lt;li&gt;i18n 国际化适配等等&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;属性选择器&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[属性]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配包含指定属性的所有元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[属性=值]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配属性值&lt;strong&gt;完全等于&lt;/strong&gt;指定值的元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[属性^=值]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配属性值&lt;strong&gt;以指定字符串开头&lt;/strong&gt;的元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[属性$=值]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配属性值&lt;strong&gt;以指定字符串结尾&lt;/strong&gt;的元素&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[属性*=值]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;匹配属性值在&lt;strong&gt;任意位置包含指定子串&lt;/strong&gt;的元素&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;选择器的优先级&lt;/h2&gt;
&lt;p&gt;优先级由选择器的权重决定，权重高的规则覆盖权重低的规则。&lt;/p&gt;
&lt;p&gt;浏览器通过优先级来判断哪些属性与一个元素最为相关。优先级基于不同种类选择器组成的匹配规则。&lt;/p&gt;
&lt;p&gt;原则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;优先级相同的时候，CSS 中最后声明的那个样式会被应用到元素上。（层叠遵循就近原则）&lt;/li&gt;
&lt;li&gt;其余判断哪个选择器权重高，优先执行那个样式。&lt;/li&gt;
&lt;li&gt;权重是四位一组，是分开的层级，不能进位。&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;选择器类型&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;th&gt;权重值&lt;/th&gt;
&lt;th&gt;优先级说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;!important&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;color: red !important;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;无限大&lt;/td&gt;
&lt;td&gt;强制覆盖所有规则（慎用）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内联样式&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;div style=&quot;color: red&quot;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(1, 0, 0, 0)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;行内样式权重最高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ID 选择器&lt;/td&gt;
&lt;td&gt;&lt;code&gt;#myId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0, 1, 0, 0)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;每个 ID 增加 &lt;code&gt;0,1,0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;类 / 属性 / 伪类&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.class&lt;/code&gt;, &lt;code&gt;[type=&quot;text&quot;]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0, 0, 1, 0)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;每个类 / 属性 / 伪类增加 &lt;code&gt;0,0,1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;类型（标签）/ 伪元素&lt;/td&gt;
&lt;td&gt;&lt;code&gt;div&lt;/code&gt;, &lt;code&gt;::after&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0, 0, 0, 1)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;每个标签 / 伪元素增加 &lt;code&gt;0,0,0,1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;通配符 / 继承&lt;/td&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt;, 继承的样式&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(0, 0, 0, 0)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;通配符和继承权重最低&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;权重叠加：&lt;br /&gt;
权重是累加的，每个选择器的层级权重相加。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;选择器 &lt;code&gt;#nav .item a&lt;/code&gt; 由三部分组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;#nav&lt;/code&gt;：ID 选择器，权重为 &lt;code&gt;(0, 1, 0, 0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.item&lt;/code&gt;：类选择器，权重为 &lt;code&gt;(0, 0, 1, 0)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt;：类型（元素）选择器，权重为 &lt;code&gt;(0, 0, 0, 1)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将各部分权重对应位相加：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第 1 位：&lt;code&gt;0 + 0 + 0 = 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;第 2 位：&lt;code&gt;1 + 0 + 0 = 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;第 3 位：&lt;code&gt;0 + 1 + 0 = 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;第 4 位：&lt;code&gt;0 + 0 + 1 = 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，&lt;code&gt;#nav .item a&lt;/code&gt; 的最终权重为 &lt;strong&gt;(0, 1, 1, 1)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>邂逅</title><link>https://blog.sheyiyuan.com/posts/%E9%82%82%E9%80%85/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/%E9%82%82%E9%80%85/</guid><pubDate>Mon, 24 Feb 2025 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;夏末，已是快开学的时候，天气并不显得很热。&lt;/p&gt;
&lt;p&gt;一个女孩独自一人在姜大附中的公园之中静静地坐着，周围的花丛弥漫着一阵让人感到很舒适的清香。许多蜜蜂循着花香赶来，在夏季的盛花丛中呼朋引伴，和着一旁小溪的流水潺潺，跳起欢快的圆圈舞。周围的鸟儿在枝头成双成对，唱着婉转的曲子，随着风的和声，在花丛中与舞者们的节拍交织回响。&lt;/p&gt;
&lt;p&gt;女孩坐在一旁的石板凳上，欣赏着这一场夏日舞会。但这份热闹并不属于女孩，她反而比花丛中的艺术家们更像是背景的一部分。女孩的呼吸与空气里混合的蝉鸣鸟语饱和，在公园中氤氲着，让时间的流逝也变得和她的身影一样有些模糊了。一切都是难得的宁静，直到……&lt;/p&gt;
&lt;p&gt;没有任何征兆，一只麻雀跌跌撞撞地闯进了花丛，受到惊吓的艺术家们也四散而逃，只留下一片狼藉。这个不速之客摔倒在女孩的脚边，像青绿背景被泼倒的墨水沾染上了一抹极其刺眼的灰红色。地上的麻雀不停扑腾着翅膀想要重新飞起来，但总是以失败结尾。&lt;/p&gt;
&lt;p&gt;终究只是一点小插曲，艺术家们很快又重新在花丛中聚集起来，恢复了先前的欢快演出。而地上扑腾的麻雀与石板凳上静坐的女孩一起成为了这场演出背景板的一部分。&lt;/p&gt;
&lt;p&gt;不久，女孩低下头从脚边拾起那只麻雀，才看见它的翅膀受了伤，沾满鲜血。似乎是感受到了女孩的温度的缘故，刚才还在不断扑腾着的麻雀安静下来。女孩从包里取出水替它清洗了伤口，涂上药，撕开一张创可贴轻轻贴在它的伤口处。&lt;/p&gt;
&lt;p&gt;麻雀很快恢复了活力，在几次尝试之后又一次飞了起来，围着公园快乐地转着圈。&lt;/p&gt;
&lt;p&gt;女孩的脸上闪过一丝亮光，但很快又暗了下去。她艰难地支撑着自己的身体从石板凳上站起，抓起放在一边的拐杖，拖着自己的左腿，走出了在夏日余晖照耀下的公园。&lt;/p&gt;
&lt;p&gt;花丛中的艺术家们对这一切浑然不觉，接着奏乐接着舞，继续着这一场夏日舞会。&lt;/p&gt;
&lt;p&gt;女孩沿着一条窄路缓缓前行，拐杖在地面上发出轻微的敲击声。夕阳的余晖渐渐隐没在地平线上，一抹淡淡的紫色渐渐弥漫了天空。吹过的一阵偏西风将她的发丝拂乱，将麻雀的叫声传递到她的耳边，指引着她走向校园的角落。女孩把头低下，弯着腰，拖着自己的身体，看不见前面的路，只是顺着风的讯息向前彳亍着。不知过了多久，她走入了一片阴影，看见了地上的台阶。女孩抬起头，映入眼帘的是一座巨大的建筑——那是姜大附中的图书馆。那只贴着创可贴的麻雀正在微微敞了一条缝的图书馆大门口蹦蹦跳跳，时不时发出一两声啾啾的鸣声。&lt;/p&gt;
&lt;p&gt;女孩在门口用那根瘦削的拐杖支持着她同样瘦弱的身体，干枯的影子被建筑的阴影吞没。她静静地伫立了一两分钟，随后推开了图书馆的门，走了进去，惊飞了门口的麻雀。&lt;/p&gt;
&lt;p&gt;出乎她意料的是，图书馆里一片寂静，什么人也没有，连图书管理员也不见踪影。&lt;/p&gt;
&lt;p&gt;女孩先是一脸疑惑，在阅览室内来回踱步观察，确认没有人之后，长舒了一大口气，转身慢慢走向了通向楼顶的楼梯，一步一步地支撑着往上爬着，缓缓地穿过无人的走廊，在尽头转角处慢慢上楼梯，推开楼梯尽头的一扇门，来到了图书馆的最高层。通往外面的门没有锁，女孩伸出手，但还没有拉开它，吹过的偏西风却已经替她将门推开，映入眼帘的是空旷的天台。&lt;/p&gt;
&lt;p&gt;再次出乎她的意料，天台上还有其他人。她的目光落在另一个女孩身上，那女孩身着图书管理员的制服，静静地坐在天台边缘，眼神凝望远方，仿佛在寻找着什么。似乎是听见了背后的声音，那女孩转过身来。两个女孩就这样相互注视着。&lt;/p&gt;
&lt;p&gt;一时间，天台上只听得见风的声音。&lt;/p&gt;
&lt;p&gt;“你好，你也来这里逃避城市的喧嚣吗？” 在一阵寂静后，拄着拐杖的女孩打破了沉默，略微有点颤抖的声音轻柔而充满了疑惑。&lt;/p&gt;
&lt;p&gt;“是……是的，”图书管理员打扮的女孩从边缘起身退了一步，眼神有些飘忽不定，“这里的宁静让我感到……很舒服，以及……这里的景色很不错。我喜欢在这里看书。”&lt;/p&gt;
&lt;p&gt;图书管理员打扮的女孩苍白的脸上泛起一点红晕，像氢气在氯气中点燃的火焰，在夕阳的余晖下显得渺小而无力，显得虚假而脆弱。&lt;/p&gt;
&lt;p&gt;“我也是，和你……一样呢，”拄着拐杖的女孩笑了笑，右手在兜里攥紧了一张写满了她绝望的笔记，以舒缓她此刻的不知所措，“你在看什么书呀？”&lt;/p&gt;
&lt;p&gt;“啊，我、我……”图书管理员打扮的女孩匆匆合上了手里的那本书。&lt;/p&gt;
&lt;p&gt;书本被沾污的褐色封皮上文字已经难以辨认，而中间被夹着的一张纸页露出了一大半，上面的笔记与拄着拐杖的女孩一样，字里行间皆是恐惧、无助与绝望。两人都明白了什么，但一时间都只是一言不发地低头面对面站着，连仅吹给两个她们的偏西风也住了。&lt;/p&gt;
&lt;p&gt;她内心深处的某个角落里，曾经种下的那颗信念的种子，在一段长夜后的这一刻，迎着夕阳，在绝望的余烬中开出了一朵小小的希望之花。&lt;/p&gt;
&lt;p&gt;“我可以，和你做朋友吗？”不知过了多久，拄着拐杖的女孩又一次开口了，她抬起头，眼前的风景已经变得朦胧，图书管理员打扮的女孩的身影与背后的夕阳连成一片，在铺着灰色水泥地的天台上仿佛一朵在岩石上盛放的花朵。&lt;/p&gt;
&lt;p&gt;“和我这样的人成为朋友，会给你带来麻烦的……”图书管理员打扮的女孩轻轻啜泣着。&lt;/p&gt;
&lt;p&gt;拄着拐杖的女孩握住了对方的手，即使隔着一层衣物，她也能感受到对方手上的伤痕。她望着对方的双眸，泪水朦胧的脸上画上了一抹微笑：“没关系的，每个人都难免会有自己的苦衷，我也和你一样，就让我们一起度过这个夏天吧。”&lt;/p&gt;
&lt;p&gt;“嗯……”图书管理员打扮的女孩哽咽着点了点头，在对方的眼中仿佛那朵花在风中摇晃。&lt;/p&gt;
&lt;p&gt;两个女孩一起搀扶着走到天台边坐下，轻轻擦干了脸上的泪痕。&lt;/p&gt;
&lt;p&gt;在夕阳的余晖中，她们坐在天台上。风起，迎面吹来的风拂过面庞，带来了公园里艺术家们的歌声，也将她们的故事铭记。周围环绕着暮色渐浓的氛围，仿佛时间在这一刻凝固。她们彼此的存在成为了对方生命中的一丝温暖，一份慰藉。&lt;/p&gt;
&lt;p&gt;天台上的偏西风没有止住，万物的信使，将这一切传唱成歌，飘向远处。&lt;/p&gt;
&lt;p&gt;此地，长存。&lt;/p&gt;
</content:encoded></item><item><title>遥远的重逢</title><link>https://blog.sheyiyuan.com/posts/%E9%81%A5%E8%BF%9C%E7%9A%84%E9%87%8D%E9%80%A2/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/%E9%81%A5%E8%BF%9C%E7%9A%84%E9%87%8D%E9%80%A2/</guid><pubDate>Mon, 10 Jun 2024 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;林诗的郊野是极其有韵味的，这里四处是大片大片的青紫色幽幻草地，一条条若隐若现的河流沟渠犹如青紫色地毯上的绸缎带，而星星点点的山岩就像大大小小的宝石点缀着空白的地方，舒缓了重复单调的风景。在风的吹拂下，高高的幽幻草在风儿双手的轻拂下起伏不定，在青紫色海面上迭起阵阵浪涛。&lt;/p&gt;
&lt;p&gt;你行走在这样一片青紫色的大地上，寻找着一处所有地图上都没有标记的庇护所。周围氤氲的雾气让你有些迷失了自己的方向，但你并不在意这些，只是在这幅恬静的风景画中看似漫无目的地徒步旅行。反正也不知道目的地在何处，不如让双脚引领自己走向下一个地方。&lt;/p&gt;
&lt;p&gt;你经历过许多，足以关乎改变一切，可是还有一件事在你的心里久久挥之不去。而此行的目的，就是为了将那件最后的东西毁掉。&lt;/p&gt;
&lt;p&gt;继续向前走着。最近天色好晴朗。山野还没有被雨水唤醒，但植被已长得十分青葱，透露着旺盛的生命力，叫人沉醉不已。碎石的马路拐弯了，爬坡了，又拐弯了，又爬坡了。不时有渡鸦在啼叫，你的精神已经飘忽在这山野之中了。不知走了多久，远处地平线的尽头隐约出现了一抹青灰色，渐渐显出了一座小房子的轮廓。&lt;/p&gt;
&lt;p&gt;虽然不知道这里是否是你要找寻的地方，但找一个可以落脚的地方总是好的。你加快步伐，穿过最后一段曲折的小路，终于来到了那座院子前。它坐落在一片开阔地的边缘，四周是郁郁葱葱的树木，为它遮挡了大部分风雨。院子里虽不大，却显得十分坚固，仿佛能经受住岁月的洗礼。一切如此安静，连风也在此处住了。&lt;/p&gt;
&lt;p&gt;你停住了脚步，在门口静静伫立了一会儿，随即轻轻叩响了那扇门。&lt;/p&gt;
&lt;p&gt;一阵有些犹豫的脚步声传来，有些沉重的门缓缓地打开了。一张你很熟悉却又无比陌生的面庞映入了你的眼中。女孩穿着一身像是某个中学图书管理员的制服，眼里闪过一丝紧张与错愕。&lt;/p&gt;
&lt;p&gt;“老奶奶，请问您找谁？”深吸一口气后，女孩朝你问道。&lt;/p&gt;
&lt;p&gt;“孩子，我是一个路过此地的旅人。想要找个地方歇歇脚，可以让我在这里休整一小会儿吗？”你朝着和曾经的你一样怕生的女孩解释道。尽管已经基本确定，但是你并没有说出自己的真实目的。&lt;/p&gt;
&lt;p&gt;“好…好的，您请进，我去给您找一间房间。”女孩把大门完全打开，然后朝着屋子里喊，“洛华，来客人了。”&lt;/p&gt;
&lt;p&gt;院子被打理得很好，中间一条碎石子铺就的小径将这个小空间一分为二，两边种着一些葱蒜和香芹。空地上还摆着一张桌子和几把椅子。&lt;/p&gt;
&lt;p&gt;接着，里面的屋子里走出来另一个女孩，踩着轻快的脚步，跳舞一般地从屋子里走了出来，面容和你印象中天使的模样别无二致。&lt;/p&gt;
&lt;p&gt;“奶奶，这里没有多的客房了，我把这边的隔间收拾收拾给您铺张床。您现在先在院子里坐坐。”名叫洛华的女孩帮你把行囊放在了院子中的一张桌子旁，示意你坐下。随即她转身走进了屋内。&lt;/p&gt;
&lt;p&gt;不一会儿，两个女孩为你端来一壶茶，你笑着说了声谢谢。&lt;/p&gt;
&lt;p&gt;“绫星，去帮忙把奶奶的房间收拾出来。”名叫洛华的女孩朝着另一个女孩笑了笑，名叫绫星的女孩转身进了屋子。&lt;/p&gt;
&lt;p&gt;“你是，叶洛华？”在名叫绫星的女孩走进屋内后，你笑着看向坐在你旁边的为你斟茶的女孩。&lt;/p&gt;
&lt;p&gt;“诶？奶奶认识我吗？”女孩有些惊讶。&lt;/p&gt;
&lt;p&gt;“我此前有一位朋友，你此前救助过她。”你端起茶杯喝了一小口。这清亮的茶汤里混着一股茶叶长时间保存发酵后的酸涩，如同腐败的没有生命气息的味道。&lt;/p&gt;
&lt;p&gt;“您的朋友？嗯……哦，我想起来了！您是马普尔小姐的朋友，之前我也只是在外散步时碰巧遇见她迷路了，才将她送回了家中。”女孩顿了顿，然后想起什么似的开始滔滔不绝起来。她也端起茶杯喝了一口。&lt;/p&gt;
&lt;p&gt;“这是好茶啊。”你冲着她挤出一个笑容。&lt;/p&gt;
&lt;p&gt;“当然，这是上等的茉莉花茶，清甜爽口，是上等佳品哦。奶奶果然也很喜欢吧。”女孩有些得意地笑了笑。&lt;/p&gt;
&lt;p&gt;“奶奶来这里做什么呢？”不多时，女孩打听起你的来历。已偏西的太阳从厚重的云层背后探出了头，清朗的阳光把院墙的影子拉得老长老长，将你轻轻拥抱。女孩水灵的眼睛里映照出黄昏温暖的金色。&lt;/p&gt;
&lt;p&gt;“我要前去救赎一个曾经救赎我的人，正好路过此地。”你叹了口气，“唉——”&lt;/p&gt;
&lt;p&gt;“奶奶不要担心，奶奶的朋友帮助过奶奶，她一定是好人。妈妈告诉过我，好人一定会有好运的，所以奶奶一定能再次见到那位朋友的。”女孩的脸上露出一个你无比熟悉而又意味深长的微笑。&lt;/p&gt;
&lt;p&gt;“洛华啊，你是什么时候开始住在这里的？”&lt;/p&gt;
&lt;p&gt;你突然发问让女孩的表情僵住了，一阵沉默过后，她才再一次开口：“我也记不太清了，应该很久了吧，其实，我并不是本地人，我和我的朋友在很久以前走散了，后来，我们找了好久，才重新找到对方。”她的手紧紧攥住，似乎想要抓住什么东西。“不过现在，我们也重新过上平静的生活了。”&lt;/p&gt;
&lt;p&gt;“挺好的呀。”似乎是想缓和一下气氛，你拍了拍她的肩膀，“这样也是一种幸福吧。”&lt;/p&gt;
&lt;p&gt;夕阳已经落在了地平线上，把一切都染成一片紫红色，风开始吹过夜空，屋子门口一只风铃开始响了起来。天空中的星星开始显露出来，像是被守夜人点亮的一盏一盏街灯。&lt;/p&gt;
&lt;p&gt;“也…也是呢……”她想笑，可是肌肉已然有些僵硬。&lt;/p&gt;
&lt;p&gt;你从包里取出一个匣子，推到了女孩的面前。&lt;/p&gt;
&lt;p&gt;“这个东西，是我的那位朋友留给我最后的东西，现在我把它给你。”&lt;/p&gt;
&lt;p&gt;“这不是对奶奶来说很重要的东西吗？怎么可以送给我呢？”&lt;/p&gt;
&lt;p&gt;你没有说话，只是将匣子打开，里面躺着一支黑色的骨笛，上面刻着一行小字，无言诉说着主人的身份。&lt;/p&gt;
&lt;p&gt;沉默之中，女孩脸上的泪珠倒影着你因折射扭曲的脸庞。&lt;/p&gt;
&lt;p&gt;“洛华，梦该醒了。”&lt;/p&gt;
&lt;p&gt;“绫星……你……原来还……活着呢……”女孩抱着你哭了起来。&lt;/p&gt;
&lt;p&gt;周围的院子开始扭曲，房屋变为了一地瓦砾，而原来的房里那个叫绫星的女孩所在的地方，只留下一份乐谱。&lt;/p&gt;
&lt;p&gt;你慢慢站起身，挪着脚步靠过去，又些颤抖着弯下腰，拾起那张已经泛黄却仍被好好保存的乐谱。&lt;/p&gt;
&lt;p&gt;“洛华现在还保留着这个啊？”&lt;/p&gt;
&lt;p&gt;“那是我……那是我仅剩的和绫星相关的东西了……我怎么会不好好……好好保管……”&lt;/p&gt;
&lt;p&gt;大地开始震动，女孩的身体开始分崩离析，一团黑雾开始从那具躯壳中溢散出来。地面上的黑雾化为一双双手开始缠绕摧残一切。&lt;/p&gt;
&lt;p&gt;你从口袋里取出那把银钥匙，嘴里开始吟诵起那曾无数回响过的咒语……&lt;/p&gt;
&lt;p&gt;黑雾散去，女孩已经崩解的躯壳散落在原地。那么真实，那么脆弱。&lt;/p&gt;
&lt;p&gt;“绫……星……想……你……歌……”女孩的嘴里吐出几个不成词句的音节。&lt;/p&gt;
&lt;p&gt;你看着那一张谱子，开始轻轻歌唱了起来。&lt;/p&gt;
&lt;p&gt;歌声回荡着，仿佛那一天的情景。&lt;/p&gt;
&lt;p&gt;两个女孩一起搀扶着走到天台边坐下，轻轻擦干了脸上的泪痕。&lt;/p&gt;
&lt;p&gt;在夕阳的余晖中，你们坐在天台上。风起，迎面吹来的风拂过面庞，带来了公园里艺术家们的歌声，也将你们的故事铭记。周围环绕着暮色渐浓的氛围，仿佛时间在这一刻凝固。彼此的存在成为了对方生命中的一丝温暖，一份慰藉。&lt;/p&gt;
&lt;p&gt;现在，你们在这片荒原上，重逢了。&lt;/p&gt;
&lt;p&gt;曲终。&lt;/p&gt;
&lt;p&gt;林诗的荒原依然长期无人问津，只有一块小小的石碑矗立于此，面前放着一支折断的骨笛。&lt;/p&gt;
&lt;p&gt;石碑上只有一行字：&lt;/p&gt;
&lt;p&gt;“我们重逢于此”&lt;/p&gt;
&lt;p&gt;此刻，永恒。&lt;/p&gt;
</content:encoded></item><item><title>星光寥落之夜</title><link>https://blog.sheyiyuan.com/posts/%E6%98%9F%E5%85%89%E5%AF%A5%E8%90%BD%E4%B9%8B%E5%A4%9C/</link><guid isPermaLink="true">https://blog.sheyiyuan.com/posts/%E6%98%9F%E5%85%89%E5%AF%A5%E8%90%BD%E4%B9%8B%E5%A4%9C/</guid><pubDate>Wed, 16 Nov 2022 08:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;她在夜空的孤岛中重获新生&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;文by 社·令寄了·澄闪歪了·我歪三次·亦园&lt;br /&gt;
封面 &lt;a href=&quot;https://www.pixiv.net/artworks/77820485&quot;&gt;アスタシア&lt;/a&gt; by &lt;a href=&quot;https://www.pixiv.net/users/19920821&quot;&gt;Saclia&lt;/a&gt;&lt;br /&gt;
原作 明日方舟&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这片大地的夜晚并不宁静。如果你独自站在罗德岛的舰桥上感受从大陆内部吹来的风，就可以听见大地的脉搏。从移动城邦的轰鸣引擎，到绿野山间的潺潺溪流；从大地上源石蜗牛的蠕动到地底源石矿脉的蔓延。当你抬起头仰望星空，有繁星璀璨，亦有星光寥落。而千百年来，唯一不变的，是生命在苦难面前的渺小。&lt;/p&gt;
&lt;p&gt;倘若放在平时，这样的画面会给我的心灵带来许多触动。但现在我望着这样一幅画面，我的内心竟毫无波澜了。因为在这平静之中，我的内心又有了些许的希望了。&lt;/p&gt;
&lt;p&gt;我又忆起了那一天发生的事。&lt;/p&gt;
&lt;p&gt;在一个星光寥落的夜晚，月亮的光辉渐渐隐在了云后。大地暗了下来。而罗德岛的大部分干员在这个难得的没有任务的日子里，已进入了安宁的梦境。&lt;/p&gt;
&lt;p&gt;但我不能休息，那一夜我还有更重要的事情要做。&lt;/p&gt;
&lt;p&gt;穿过无人的走廊，在转角处走上楼梯，推开尽头的一扇门，我来到了舰上的最高层。映入眼帘的是空旷的甲板。位于甲板的对侧一间小屋在星光下静静伫立在弥漫着清芳气味的空气之中。我的耳旁传来一阵若有若无的旋律。我竭力避免鞋底与甲板发出的令人不悦的声音打断这一段旋律，轻轻地走向那间小屋。站在小屋门口，听着旋律在风中的交织回响，我仿佛听见了有谁在哭泣。&lt;/p&gt;
&lt;p&gt;门没有锁。我伸出手，但还没有推开它。风却已经替我将门开。&lt;/p&gt;
&lt;p&gt;但我却没有看到我自己认为的情景。&lt;/p&gt;
&lt;p&gt;小小的房间里，各种东西被主人摆放得很整齐。门口摆了几只精致的箱子，靠门的地方放着一张简单的气垫床。房间中央的桌子上，左侧整齐地排列着各种仪器，右边的桌上放着一个小小的茶杯，里面的红茶冒着点点的白汽。房间另一侧的墙上开着一扇落地的玻璃窗，窗开着，窗前放着一架望远镜，一只小鸟正在窗前歌唱着一首夜曲。&lt;/p&gt;
&lt;p&gt;我依然轻轻地敲了敲门。阿丝忒希娅放下手中的纸笔，转过头看向门口，在满屋的繁星之中微笑着。喧嚣的风从门口涌入，翻起她手中的稿纸哗哗作响，拨动她蓝色的发丝，撩拂她轻盈的裙摆。&lt;/p&gt;
&lt;p&gt;她问，博士这么晚到这里来有什么事吗？我说，没什么，只是顺便路过，来看看。她告诉我说，我刚才还在记录星象数据，她晃晃手中的纸笔，小心地把那份手稿叠起来，文字向下摆在桌面上。我问她埃琳娜为什么不在，她只是摇摇头，说莱茵出了点岔子，本来和她没什么关系，但她还是执意要回去。说完，她又感叹道，埃琳娜现在也回莱茵了，自己一个人在这边，实在，是没有什么意思啊。&lt;/p&gt;
&lt;p&gt;我听懂她话中的意味了。再看看她现在的房间，我大概也知道她打算干什么了。就算今天埃琳娜离开之前没有专门嘱托我，我也绝对不会允许这种事发生在她身上。&lt;/p&gt;
&lt;p&gt;几天前趁着阿丝忒希娅出外勤时，埃琳娜带我来过一次，混乱，没什么词能更好地描述它的状态，所有东西以一种近乎崩坏的方式被随意地扔在各处。我横看竖看，终于从这一室狼藉中看出两个大字。&lt;/p&gt;
&lt;p&gt;绝望。彻头彻尾的绝望。这就是当一个人曾坚定信仰的一样东西被推翻之后的那种感觉。阿丝忒希娅的信仰与未来都在染上矿石病之后砸得粉碎，她眼中的星空从那以后也变得模糊不堪。&lt;/p&gt;
&lt;p&gt;我拍了拍她的肩膀对她说，阿丝忒希娅，你不要为埃琳娜的事难过，那不是你的错，也不是她的错。她只是笑了笑说，博士，我没有难过。但我却看见她的瞳孔在痛苦地震动，眼睛是不会说谎的。&lt;/p&gt;
&lt;p&gt;痛苦和绝望中的人如何会把房间布置得如此整洁？除了那种事，我想不出合理的解释。我必须阻止她，为了我，为了她，为了埃琳娜。&lt;/p&gt;
&lt;p&gt;我看着她的眼睛，但她的双眸竭力躲避着我的目光。我告诉她，埃琳娜她一直都爱着你这个姐姐，事实上，她应该和你一样难过。&lt;/p&gt;
&lt;p&gt;我努力地试着让她去拯救自己，我不想揭穿她的想法。她却还是坚持着说，博士，这都是天命，我不该再违背什么了。&lt;/p&gt;
&lt;p&gt;看来她还是没有分清坚强和倔强，不能辨清执着与偏执。&lt;/p&gt;
&lt;p&gt;我把目光重新投向了桌上的那一杯红茶，它静静地躺在桌上，散发着一阵白汽。它看上去是那样温暖，但我却感到一阵恶寒。&lt;/p&gt;
&lt;p&gt;大概是注意到我在看着那个茶杯，她勉强挤出一个微笑，用有些微微发抖的声音问我，博士需要来一杯茶吗，我可以再给博士倒一杯。&lt;/p&gt;
&lt;p&gt;我端起了桌上的茶杯，杯壁有些发凉，杯中的液体看上去异常清澈，散发出淡淡的白汽。果然是这样吗，我心想。于是我心一横，竟径直将那茶杯送到嘴边，准备一口饮下。我说，就这杯就好。&lt;/p&gt;
&lt;p&gt;她伸出手想要夺下我手中的茶杯，大喊道，博士，不可以。&lt;/p&gt;
&lt;p&gt;我停住了手中的动作，问道，这杯茶有什么问题吗？&lt;/p&gt;
&lt;p&gt;也许是意识到自己的反应有些过激，她又深吸了口气，说，这一杯我刚才已经喝过两口了，博士，请允许我重新为你再倒一杯吧。&lt;/p&gt;
&lt;p&gt;她重新为我斟上一杯红茶，双手捧着递到我的面前，那茶汤有些浑浊，却清晰地倒映出她渐渐朦胧的双眸。她几乎是一种哀求，请喝这一杯。&lt;/p&gt;
&lt;p&gt;我们就这样沉默着，连风也不再喧嚣了。后来，我看见那杯中泛起了涟漪，那是她的泪水。&lt;/p&gt;
&lt;p&gt;我端起那杯红色透明溶液走到火炉边将它洒入微弱的火焰之中。火焰立刻变得更加旺盛，发出明亮的蓝绿色的光芒，那的确不是应该装在一个精致茶杯里的饮料。我走到她的身边，拿出手巾俯下身替她擦干眼泪。我看着她蓝色的瞳孔，向她为我的无礼道歉，对不起，阿丝忒希娅，原谅我刚才的失礼，但你的生命比礼节更加重要。&lt;/p&gt;
&lt;p&gt;她扑进我的怀里，抽着气，不，说对不起的应该是我。&lt;/p&gt;
&lt;p&gt;我轻轻拍了拍她的后背，说，乌比卡小姐，你不必掉眼泪，罗德岛正是为了你们这样的感染者而斗争的，我们绝不会抛下埃琳娜和你在内的每一个感染者，埃琳娜更不会抛下你，但请你一定不要自暴自弃，可以吗？&lt;/p&gt;
&lt;p&gt;她点点头，终于忍不住哭出了声。&lt;/p&gt;
&lt;p&gt;我没有说一句安慰的话，只是听着她不断地倒着内心的苦水。都说出来就好了，我心想。她也应该有一个地方倾诉自己内心的软弱，不用再在大家面前故作坚强。在此期间，她拿起了那份手稿，或者说她尚未写完的遗书，撕成碎片扔进了火炉里。&lt;/p&gt;
&lt;p&gt;等到她的情绪渐渐平复已是午夜。我本打算离开，但她要留我一起看星星。说来也怪，原先星光寥落的夜空不知在什么时候已然变得繁星闪烁。&lt;/p&gt;
&lt;p&gt;阿丝忒希娅看着那星空，说，满天繁星在撑起我内心的夜空，照亮阴郁的角落，告诉我有更多的感染者都没有放弃希望，我如此幸运遇见罗德岛的大家，遇见博士你，更应该好好努力活下去。&lt;/p&gt;
&lt;p&gt;当然，我们都要努力。我回答她。&lt;/p&gt;
&lt;p&gt;那个……博士……我……&lt;/p&gt;
&lt;p&gt;怎么了？&lt;/p&gt;
&lt;p&gt;我……快看博士，是流星雨。&lt;/p&gt;
&lt;p&gt;她伸出了手指向天边。我顺着她手指的方向，看见了十颗流星在地平线附近画出了一道道光，前九颗星星是蓝色，后面紧跟着一颗紫色的星星，这场景十分美丽。&lt;/p&gt;
&lt;p&gt;博士，我爱你。就在这场流星雨临近结束时，她说出了后半句话。&lt;/p&gt;
&lt;p&gt;我愣住了，因为我不知如何回应她，但想了想，我还是把实情告诉了她。我对她说，我从一开始见到你，我就喜欢上你了。然后我才发现你的内心与你在大家面前表现出来的那个你并不一样。否则，我今天也不会在这里了。所以……&lt;/p&gt;
&lt;p&gt;我顿了顿，阿丝忒希娅·乌比卡，星极，我也爱你。说完，我看见阿丝忒希娅对着我笑了。&lt;/p&gt;
&lt;p&gt;博士，把眼睛闭上，可以吗？&lt;/p&gt;
&lt;p&gt;我照做了。大概两分钟后，她的声音传入我的耳中，可以睁开眼睛了，博士。&lt;/p&gt;
&lt;p&gt;我睁开眼睛，阿丝忒希娅换上了她的生日礼服站在我的面前，璀璨的繁星缀成她的上衣，洁白的月光织出她的裙摆，蓝色的发丝披到肩上，在风中撩动，清澈的双眸透露着热情与欢喜。她脸上泛起红晕，微笑着问我，博士，愿意与我共舞一曲夜的华尔兹吗？&lt;/p&gt;
&lt;p&gt;我答应了。她体态轻盈的跳动着，一边和着节拍唱起一支夜曲，在房间中回响。&lt;/p&gt;
&lt;p&gt;一曲终焉，阿丝忒希娅告诉我，她在我来之前，曾做过一次星象占卜，占卜说今夜会有人来救赎她，但当时近乎绝望的她没有相信。&lt;/p&gt;
&lt;p&gt;而且后面还有半句，她补充道。&lt;/p&gt;
&lt;p&gt;是什么？&lt;/p&gt;
&lt;p&gt;我和救我的那个人在一起过上了幸福的生活。&lt;/p&gt;
&lt;p&gt;我趴在她柔软的身体上，很快进入了梦乡。&lt;/p&gt;
&lt;p&gt;我依稀记得，那个夜晚很是宁静。&lt;/p&gt;
</content:encoded></item></channel></rss>