<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>LunaPath</title>
    <link>http://localhost:3000</link>
    <description>LunaPath 的博客，记录思考和分享知识的地方</description>
    <language>zh-CN</language>
    <lastBuildDate>Sun, 28 Jun 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="http://localhost:3000/feed.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title><![CDATA[只狼：影逝二度 — 从新手到剑圣的完全攻略]]></title>
      <link>http://localhost:3000/posts/sekiro-guide</link>
      <guid isPermaLink="true">http://localhost:3000/posts/sekiro-guide</guid>
      <pubDate>Sun, 28 Jun 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[只狼的核心是弹刀而非闪避。本文涵盖战斗系统解析、必备技能、Boss 打法要点和实用技巧，助你从菜鸟蜕变为剑圣。]]></description>
      <content:encoded><![CDATA[<h2 id="核心理念架势条-血量" class="heading-with-anchor">核心理念：架势条 > 血量<a href="#核心理念架势条-血量" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>只狼和传统动作游戏最大的区别在于：<strong>击杀敌人靠的是打满架势条（Posture），而非削血</strong>。</p>
<ul>
<li>架势条会随时间恢复，但恢复速度取决于敌人血量——血越少恢复越慢</li>
<li>完美弹刀（Deflect）对敌人架势条的伤害远大于普通攻击</li>
<li>你的架势条同样会被打满，但<strong>完美弹刀永远不会让你架势崩断</strong></li>
</ul>
<blockquote>
<p>简单来说：别想着慢慢磨血，上去弹他。</p>
</blockquote>
<h2 id="战斗三大铁律" class="heading-with-anchor">战斗三大铁律<a href="#战斗三大铁律" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="1-弹刀-闪避" class="heading-with-anchor">1. 弹刀 > 闪避<a href="#1-弹刀-闪避" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>只狼的闪避 i-frame 极短，很多攻击根本躲不开。但弹刀的判定窗口相当宽松（约 6 帧 / 0.2 秒）。</p>
<ul>
<li><strong>看到敌人出手 → 听节奏 → 按 block</strong></li>
<li>不要连点 block，会缩短弹刀判定窗口</li>
<li>被打中了不要慌，立刻重新摆好架势继续弹</li>
</ul>
<h3 id="2-进攻是最好的防守" class="heading-with-anchor">2. 进攻是最好的防守<a href="#2-进攻是最好的防守" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>只狼鼓励<strong>持续施压</strong>：</p>
<ul>
<li>大多数敌人在你攻击时无法主动出招（被你的攻击硬直打断）</li>
<li>连续攻击迫使敌人做出固定反应（弹刀、闪避、或特殊招式），可以预判</li>
<li>打到敌人弹你的刀 → 立刻转为弹刀 → 反弹后继续进攻</li>
</ul>
<p>这就是所谓的「攻击节奏」：<strong>砍砍砍 → 弹 → 砍砍砍 → 弹</strong></p>
<h3 id="3-看懂危急攻击danger" class="heading-with-anchor">3. 看懂危急攻击（Danger）<a href="#3-看懂危急攻击danger" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>敌人出手前会出现「危」字，代表三种攻击：</p>
<p>| 类型 | 应对 | 判断方法 |
|------|------|----------|
| <strong>突刺</strong> | 踩刀（Mikiri Counter） | 武器从正面刺来 |
| <strong>横扫</strong> | 跳起踩头 | 武器从侧面扫来 |
| <strong>抓取</strong> | 闪避 / 后退 | 敌人张开双手 |</p>
<blockquote>
<p>踩刀是游戏中最重要的技能之一，对突刺类攻击造成巨量架势伤害。</p>
</blockquote>
<h2 id="必学技能推荐" class="heading-with-anchor">必学技能推荐<a href="#必学技能推荐" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="前期优先解锁" class="heading-with-anchor">前期优先解锁<a href="#前期优先解锁" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>踩刀（Mikiri Counter）</strong>：对抗突刺的神技，几乎每个 Boss 都有突刺招式</li>
<li><strong>空中弹刀</strong>：在跳跃中也能弹刀，应对横扫+后续攻击非常实用</li>
<li><strong>识破（Shinobi Eyes）</strong>：增强踩刀的判定窗口</li>
</ul>
<h3 id="忍义手推荐优先级" class="heading-with-anchor">忍义手推荐优先级<a href="#忍义手推荐优先级" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>| 优先级 | 义手 | 用途 |
|--------|------|------|
| ★★★ | 爆竹 | 打断敌人动作，对兽类敌人特效 |
| ★★★ | 手里剑 | 打断跳跃/远距离敌人，追击用 |
| ★★ | 火焰喷射器 | 对肉体敌人持续烧伤 |
| ★★ | 斧头 | 破盾，对持盾敌人特效 |
| ★ | 雾鸦 | 紧急回避，被打中时瞬移 |</p>
<h2 id="boss-通用攻略思路" class="heading-with-anchor">Boss 通用攻略思路<a href="#boss-通用攻略思路" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="阶段一观察" class="heading-with-anchor">阶段一：观察<a href="#阶段一观察" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>第一次遇到 Boss <strong>不要急着打</strong>，先专注闪避/弹刀，观察出招模式</li>
<li>注意哪些招式后面有长间隙（可以回血/输出）</li>
<li>记住「危」字攻击的类型</li>
</ul>
<h3 id="阶段二施压" class="heading-with-anchor">阶段二：施压<a href="#阶段二施压" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>进入攻击节奏：砍 → 弹 → 砍 → 弹</li>
<li>当敌人跳开/拉开距离时，跟上去继续压制</li>
<li>架势条快满时更加激进，不给恢复时间</li>
</ul>
<h3 id="阶段三处决" class="heading-with-anchor">阶段三：处决<a href="#阶段三处决" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>架势条打满后立刻按攻击键进行「忍杀」</li>
<li>多阶段 Boss 需要多次忍杀，注意血量和架势条的变化</li>
</ul>
<h2 id="实用小技巧" class="heading-with-anchor">实用小技巧<a href="#实用小技巧" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<ol>
<li><strong>练习找半兵卫</strong>：破庙附近的不死半兵卫是你的专属训练木桩，免费练习所有招式</li>
<li><strong>忍杀先手</strong>：能暗杀的敌人一定先暗杀，少打一场是一场</li>
<li><strong>回生不要乱用</strong>：死亡后可以在合适的时机回生，但有 CD，别浪费</li>
<li><strong>探索每个角落</strong>：佛珠（升级血量/架势）和葫芦种子（升级回血瓶）藏在各种隐蔽位置</li>
<li><strong>糖很重要</strong>：攻击糖/防御糖/隐身糖在 Boss 战中效果显著</li>
<li><strong>钱要及时花</strong>：死了会掉一半钱和经验，攒够了就花掉</li>
</ol>
<h2 id="推荐攻略顺序" class="heading-with-anchor">推荐攻略顺序<a href="#推荐攻略顺序" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<ol>
<li><strong>苇名城城邑</strong> → 学习基础战斗</li>
<li><strong>平田宅邸</strong> → 获取忍义手</li>
<li><strong>苇名城</strong> → 主线推进</li>
<li><strong>仙峰寺</strong> → 获取不死斩</li>
<li><strong>坠落之谷</strong> → 获取拳法</li>
<li><strong>源之宫</strong> → 后期区域</li>
</ol>
<hr>
<p>只狼是一款「死了才会变强」的游戏。每一个 Boss 都是你的老师，每一次死亡都是学费。坚持下去，当你终于能无伤弹掉弦一郎的三连斩时，那种成就感是其他游戏给不了的。</p>]]></content:encoded>
      <category>游戏</category>
      <category>只狼</category>
      <category>攻略</category>
    </item>
    <item>
      <title><![CDATA[CS2 新手进阶指南 — 从白银到全球精英的实用技巧]]></title>
      <link>http://localhost:3000/posts/cs2-guide</link>
      <guid isPermaLink="true">http://localhost:3000/posts/cs2-guide</guid>
      <pubDate>Sat, 27 Jun 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[CS2 的核心是枪法、地图理解和经济管理。本文涵盖压枪技巧、身法走位、地图报点和经济策略，帮你快速提升段位。]]></description>
      <content:encoded><![CDATA[<h2 id="cs2-的核心三件事决定胜负" class="heading-with-anchor">CS2 的核心：三件事决定胜负<a href="#cs2-的核心三件事决定胜负" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<ol>
<li><strong>枪法</strong> — 准星在哪、怎么开枪</li>
<li><strong>地图理解</strong> — 该去哪、敌人在哪</li>
<li><strong>经济管理</strong> — 什么时候买、买什么</li>
</ol>
<p>三项缺一不可，但对新手来说，<strong>枪法提升最快、回报最大</strong>。</p>
<h2 id="枪法基础准星放置" class="heading-with-anchor">枪法基础：准星放置<a href="#枪法基础准星放置" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="准星永远在头线" class="heading-with-anchor">准星永远在头线<a href="#准星永远在头线" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>这是 CS 最重要的习惯，没有之一：</p>
<ul>
<li><strong>走路时准星保持在敌人头部高度</strong></li>
<li>不要瞄地、不要瞄墙角上方</li>
<li>利用地图上的箱子、墙线作为头线参考</li>
</ul>
<blockquote>
<p>练好准星放置，你的击杀效率直接翻倍。因为当敌人出现时，你只需要按一下鼠标，而不是先拉枪再开枪。</p>
</blockquote>
<h3 id="急停射击counter-strafe" class="heading-with-anchor">急停射击（Counter-Strafe）<a href="#急停射击counter-strafe" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>CS2 中移动时射击精度极差。正确的开枪方式：</p>
<ol>
<li>向左走（A 键）→ 想停下的瞬间按一下 D 键 → 开枪</li>
<li>向右走（D 键）→ 想停下的瞬间按一下 A 键 → 开枪</li>
</ol>
<p>这叫<strong>急停</strong>，能让你瞬间恢复精准度。</p>
<p>练习方法：开一局离线，对着墙走走停停，观察弹孔是否集中。</p>
<h2 id="压枪控制spray-control" class="heading-with-anchor">压枪控制（Spray Control）<a href="#压枪控制spray-control" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="为什么要压枪" class="heading-with-anchor">为什么要压枪？<a href="#为什么要压枪" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>CS2 的枪械后坐力是<strong>固定弹道模式</strong>。AK-47 前 7 发子弹的弹道每次都是同一个形状——先往上，再往左，再往右。</p>
<h3 id="基础压枪前-7-发" class="heading-with-anchor">基础压枪：前 7 发<a href="#基础压枪前-7-发" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>AK-47 和 M4 是最常用的两把枪：</p>
<ul>
<li><strong>前 7 发</strong>：鼠标匀速向下拉</li>
<li><strong>第 8-15 发</strong>：向下拉的同时稍微向左修正</li>
<li><strong>第 16 发以后</strong>：向右修正</li>
</ul>
<blockquote>
<p>新手建议先练前 7 发。大多数对枪在 7 发以内就能分出胜负。</p>
</blockquote>
<h3 id="练习方法" class="heading-with-anchor">练习方法<a href="#练习方法" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ol>
<li>创意工坊订阅 <strong>"Recoil Master"</strong> 地图</li>
<li>先不开枪，看弹道轨迹</li>
<li>对着墙打一梭子，记住弹道形状</li>
<li>然后试着压枪，让弹孔集中在一点</li>
</ol>
<h2 id="身法与走位" class="heading-with-anchor">身法与走位<a href="#身法与走位" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="不要跑着打" class="heading-with-anchor">不要跑着打<a href="#不要跑着打" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>看到敌人 → 急停 → 开枪</li>
<li>打完一轮 → 移动换位 → 急停 → 再打</li>
<li>绝对不要边跑边扫射（除了 P90 冲锋枪）</li>
</ul>
<h3 id="peek探头" class="heading-with-anchor">Peek（探头）<a href="#peek探头" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>Jiggle Peek</strong>：快速左右探头，获取信息不被打中</li>
<li><strong>Wide Peek</strong>：大幅拉出，利用 Peeker's Advantage 先手击杀</li>
<li><strong>Shoulder Peek</strong>：只露出肩膀骗敌人开枪，等他换弹时再拉出来</li>
</ul>
<h3 id="走位原则" class="heading-with-anchor">走位原则<a href="#走位原则" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>贴墙走（减少暴露面积）</li>
<li>不要走地图中间（四面受敌）</li>
<li>利用掩体逐段推进</li>
<li>换位后等 2-3 秒再探头（敌人可能还在瞄老位置）</li>
</ul>
<h2 id="经济管理economy" class="heading-with-anchor">经济管理（Economy）<a href="#经济管理economy" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>CS2 的经济系统决定了你每局能买什么装备：</p>
<h3 id="买枪时机" class="heading-with-anchor">买枪时机<a href="#买枪时机" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>| 情况 | 策略 |
|------|------|
| 队伍经济好（$4500+） | 全买（步枪+甲+道具） |
| 经济一般（$2500-4000） | 半买（冲锋枪/手枪+甲） |
| 连败积累 | 存钱（ECO 局，只买手枪） |
| 赢了手枪局 | 第二局全买，碾压经济差 |</p>
<h3 id="手枪局pistol-round" class="heading-with-anchor">手枪局（Pistol Round）<a href="#手枪局pistol-round" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>手枪局非常重要，赢了能建立经济优势</li>
<li>CT 方：买甲 + 默认手枪 / 或 USP</li>
<li>T 方：买甲 + Glock（或升级 P250）</li>
</ul>
<h3 id="关键原则" class="heading-with-anchor">关键原则<a href="#关键原则" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>和队友同步买/存</strong>：一个人全买一个人存钱等于浪费</li>
<li><strong>输了不要急着全买</strong>：存一局，下局再 full buy</li>
<li><strong>赢了要乘胜追击</strong>：连续赢的时候保持 full buy</li>
</ul>
<h2 id="地图入门推荐" class="heading-with-anchor">地图入门推荐<a href="#地图入门推荐" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>新手建议先精通 2-3 张图：</p>
<h3 id="dust-2最经典" class="heading-with-anchor">Dust 2（最经典）<a href="#dust-2最经典" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>结构简单，直来直去</li>
<li>中路控制是关键</li>
<li>A 大和 B 洞是主要进攻路线</li>
</ul>
<h3 id="mirage最平衡" class="heading-with-anchor">Mirage（最平衡）<a href="#mirage最平衡" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>中路控制极其重要</li>
<li>A 点窗口是狙击手天堂</li>
<li>B 点公寓是 T 方突破口</li>
</ul>
<h3 id="inferno最考验配合" class="heading-with-anchor">Inferno（最考验配合）<a href="#inferno最考验配合" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>香蕉道是兵家必争之地</li>
<li>A 点需要多角度同步进攻</li>
<li>CT 方道具压制非常强</li>
</ul>
<h2 id="实用设置建议" class="heading-with-anchor">实用设置建议<a href="#实用设置建议" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="准星设置" class="heading-with-anchor">准星设置<a href="#准星设置" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>不要用默认准星，太分散</li>
<li>推荐：小准星、静态、绿色/青色</li>
<li>可以在 settings 里微调，或导入职业选手准星代码</li>
</ul>
<h3 id="灵敏度" class="heading-with-anchor">灵敏度<a href="#灵敏度" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>eDPI（DPI × 游戏灵敏度）建议 400-800</li>
<li>能 180° 转身但又不会太飘</li>
<li>手臂流玩家倾向低灵敏度，手腕流倾向高灵敏度</li>
</ul>
<h3 id="音频设置" class="heading-with-anchor">音频设置<a href="#音频设置" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>戴耳机，调大音量</li>
<li>脚步声是信息的关键来源</li>
<li>学会听声音判断敌人方位和距离</li>
</ul>
<h2 id="快速提升路线" class="heading-with-anchor">快速提升路线<a href="#快速提升路线" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<ol>
<li><strong>第 1 周</strong>：练习急停 + 准星放置（Aim Botz 地图）</li>
<li><strong>第 2 周</strong>：学习 AK/M4 前 7 发压枪</li>
<li><strong>第 3 周</strong>：精通一张地图的报点和基本战术</li>
<li><strong>第 4 周</strong>：开始打竞技模式，实战检验</li>
<li><strong>持续</strong>：每天 10 分钟 Aim Botz 热手，看自己的 demo 复盘</li>
</ol>
<hr>
<p>CS2 是一个需要持续练习的游戏。不要因为连输几局就气馁——每个全球精英都是从白银打上去的。坚持练枪、学习地图、和队友配合，段位自然会提升。</p>]]></content:encoded>
      <category>游戏</category>
      <category>CS2</category>
      <category>攻略</category>
    </item>
    <item>
      <title><![CDATA[Next.js 博客搭建指南]]></title>
      <link>http://localhost:3000/posts/nextjs-guide</link>
      <guid isPermaLink="true">http://localhost:3000/posts/nextjs-guide</guid>
      <pubDate>Sat, 20 Jun 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[从零开始用 Next.js App Router 搭建一个静态博客，含 TypeScript 和 Tailwind CSS。]]></description>
      <content:encoded><![CDATA[<h2 id="为什么选-nextjs" class="heading-with-anchor">为什么选 Next.js<a href="#为什么选-nextjs" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>Next.js 是目前 React 生态中最主流的全栈框架。选择它搭建博客的理由：</p>
<ul>
<li><strong>App Router</strong>：基于文件系统的路由，零配置即用</li>
<li><strong>静态生成 (SSG)</strong>：<code>generateStaticParams</code> 让文章页在构建时预渲染，访问速度极快</li>
<li><strong>内置图片优化</strong>：<code>next/image</code> 自动懒加载、响应式裁剪、WebP 转换</li>
<li><strong>API Routes</strong>：表单提交、订阅等功能不需要额外后端</li>
<li><strong>SEO 友好</strong>：<code>generateMetadata</code> 动态生成每篇文章的 meta 标签</li>
<li><strong>生态成熟</strong>：Vercel 一键部署，社区插件丰富</li>
</ul>
<hr>
<h2 id="初始化项目" class="heading-with-anchor">初始化项目<a href="#初始化项目" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">bash</span><div class="code-block-meta"><span class="code-block-language">bash</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="bash" data-theme="one-dark-pro"><code data-language="bash" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#61AFEF">npx</span><span style="color:#98C379"> create-next-app@latest</span><span style="color:#98C379"> my-blog</span><span style="color:#56B6C2"> \</span></span>
<span data-line=""><span style="color:#D19A66">  --typescript</span><span style="color:#56B6C2"> \</span></span>
<span data-line=""><span style="color:#D19A66">  --tailwind</span><span style="color:#56B6C2"> \</span></span>
<span data-line=""><span style="color:#D19A66">  --app</span><span style="color:#56B6C2"> \</span></span>
<span data-line=""><span style="color:#D19A66">  --src-dir</span></span></code></pre></figure>
<p>创建完成后安装博客所需的依赖：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">bash</span><div class="code-block-meta"><span class="code-block-language">bash</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="bash" data-theme="one-dark-pro"><code data-language="bash" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#61AFEF">npm</span><span style="color:#98C379"> install</span><span style="color:#98C379"> gray-matter</span><span style="color:#98C379"> remark</span><span style="color:#98C379"> remark-rehype</span><span style="color:#98C379"> rehype-stringify</span><span style="color:#98C379"> rehype-pretty-code</span><span style="color:#98C379"> shiki</span></span></code></pre></figure>
<p>| 包名 | 作用 |
|---|---|
| <code>gray-matter</code> | 解析 Markdown 文件头部的 YAML frontmatter（标题、日期、标签等） |
| <code>remark</code> | Markdown 处理引擎 |
| <code>remark-rehype</code> | 将 Markdown AST 转为 HTML AST |
| <code>rehype-stringify</code> | 将 HTML AST 序列化为字符串 |
| <code>rehype-pretty-code</code> | 基于 Shiki 的代码语法高亮 |
| <code>shiki</code> | 代码高亮引擎，支持上百种语言和主题 |</p>
<hr>
<h2 id="项目结构" class="heading-with-anchor">项目结构<a href="#项目结构" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>一个典型的博客项目长这样：</p>
<pre><code>my-blog/
├── content/
│   └── posts/                # Markdown 文章
│       ├── hello-world.md
│       └── nextjs-guide.md
├── src/
│   ├── app/
│   │   ├── layout.tsx        # 全局布局（Header + Footer）
│   │   ├── page.tsx          # 首页
│   │   ├── globals.css       # 全局样式
│   │   ├── posts/
│   │   │   └── [slug]/
│   │   │       └── page.tsx  # 文章详情页
│   │   ├── tags/
│   │   │   ├── page.tsx      # 标签总览
│   │   │   └── [tag]/
│   │   │       └── page.tsx  # 按标签筛选
│   │   ├── about/
│   │   │   └── page.tsx      # 关于页
│   │   ├── api/
│   │   │   ├── subscribe/
│   │   │   │   └── route.ts  # 订阅接口
│   │   │   └── og/
│   │   │       └── route.tsx # OG 图片生成
│   │   ├── feed.xml/
│   │   │   └── route.ts      # RSS 订阅源
│   │   ├── sitemap.ts        # 站点地图
│   │   └── robots.ts         # 爬虫规则
│   ├── components/           # React 组件
│   └── lib/
│       ├── posts.ts          # 文章读取与解析
│       └── i18n.tsx          # 国际化
├── public/                   # 静态资源
└── package.json
</code></pre>
<hr>
<h2 id="markdown-文章格式" class="heading-with-anchor">Markdown 文章格式<a href="#markdown-文章格式" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>每篇文章是一个带 frontmatter 的 Markdown 文件：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">markdown</span><div class="code-block-meta"><span class="code-block-language">markdown</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="markdown" data-theme="one-dark-pro"><code data-language="markdown" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#ABB2BF">---</span></span>
<span data-line=""><span style="color:#ABB2BF">title: "我的第一篇博客"</span></span>
<span data-line=""><span style="color:#ABB2BF">date: "2026-06-20"</span></span>
<span data-line=""><span style="color:#ABB2BF">summary: "这是一篇关于 Next.js 的入门文章。"</span></span>
<span data-line=""><span style="color:#ABB2BF">tags: ["技术", "Next.js"]</span></span>
<span data-line=""><span style="color:#ABB2BF">pinned: false</span></span>
<span data-line=""><span style="color:#ABB2BF">draft: false</span></span>
<span data-line=""><span style="color:#E06C75">---</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#E06C75">## 正文标题</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#ABB2BF">这里是文章内容...</span></span></code></pre></figure>
<p>frontmatter 字段说明：</p>
<p>| 字段 | 类型 | 说明 |
|---|---|---|
| <code>title</code> | string | 文章标题 |
| <code>date</code> | string | 发布日期（YYYY-MM-DD） |
| <code>summary</code> | string | 摘要，用于列表页和 SEO |
| <code>tags</code> | string[] | 标签数组 |
| <code>pinned</code> | boolean | 是否置顶 |
| <code>draft</code> | boolean | 是否草稿（不显示） |
| <code>publishAt</code> | string | 定时发布（ISO 日期） |</p>
<hr>
<h2 id="核心实现文章读取与解析" class="heading-with-anchor">核心实现：文章读取与解析<a href="#核心实现文章读取与解析" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p><code>src/lib/posts.ts</code> 是整个博客的数据层，负责读取 Markdown、解析 frontmatter、转换 HTML。</p>
<h3 id="读取所有文章" class="heading-with-anchor">读取所有文章<a href="#读取所有文章" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">typescript</span><div class="code-block-meta"><span class="code-block-language">typescript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="typescript" data-theme="one-dark-pro"><code data-language="typescript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">import</span><span style="color:#E06C75"> fs</span><span style="color:#C678DD"> from</span><span style="color:#98C379"> "fs"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""><span style="color:#C678DD">import</span><span style="color:#E06C75"> path</span><span style="color:#C678DD"> from</span><span style="color:#98C379"> "path"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""><span style="color:#C678DD">import</span><span style="color:#E06C75"> matter</span><span style="color:#C678DD"> from</span><span style="color:#98C379"> "gray-matter"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">const</span><span style="color:#E5C07B"> postsDirectory</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> path</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">join</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">process</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">cwd</span><span style="color:#ABB2BF">(), </span><span style="color:#98C379">"content"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"posts"</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">export</span><span style="color:#C678DD"> function</span><span style="color:#61AFEF"> getAllPosts</span><span style="color:#ABB2BF">() {</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> filenames</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> fs</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">readdirSync</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">postsDirectory</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">  return</span><span style="color:#E06C75"> filenames</span></span>
<span data-line=""><span style="color:#ABB2BF">    .</span><span style="color:#61AFEF">filter</span><span style="color:#ABB2BF">((</span><span style="color:#E06C75;font-style:italic">f</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#E5C07B"> f</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">endsWith</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">".md"</span><span style="color:#ABB2BF">))</span></span>
<span data-line=""><span style="color:#ABB2BF">    .</span><span style="color:#61AFEF">map</span><span style="color:#ABB2BF">((</span><span style="color:#E06C75;font-style:italic">filename</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> {</span></span>
<span data-line=""><span style="color:#C678DD">      const</span><span style="color:#E5C07B"> slug</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> filename</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">replace</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">/</span><span style="color:#56B6C2">\.</span><span style="color:#E06C75">md</span><span style="color:#C678DD">$</span><span style="color:#E06C75">/</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""><span style="color:#C678DD">      const</span><span style="color:#E5C07B"> fileContent</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> fs</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">readFileSync</span><span style="color:#ABB2BF">(</span></span>
<span data-line=""><span style="color:#E5C07B">        path</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">join</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">postsDirectory</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">filename</span><span style="color:#ABB2BF">), </span><span style="color:#98C379">"utf-8"</span></span>
<span data-line=""><span style="color:#ABB2BF">      );</span></span>
<span data-line=""><span style="color:#C678DD">      const</span><span style="color:#ABB2BF"> { </span><span style="color:#E5C07B">data</span><span style="color:#ABB2BF">, </span><span style="color:#E5C07B">content</span><span style="color:#ABB2BF"> } </span><span style="color:#56B6C2">=</span><span style="color:#61AFEF"> matter</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">fileContent</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">      return</span><span style="color:#ABB2BF"> {</span></span>
<span data-line=""><span style="color:#E06C75">        slug</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">        title</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">data</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">title</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">        date</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">data</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">date</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">        summary</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">data</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">summary</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">        tags</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">data</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">tags</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#7F848E;font-style:italic">        // 计算阅读时间...</span></span>
<span data-line=""><span style="color:#ABB2BF">      };</span></span>
<span data-line=""><span style="color:#ABB2BF">    })</span></span>
<span data-line=""><span style="color:#ABB2BF">    .</span><span style="color:#61AFEF">sort</span><span style="color:#ABB2BF">((</span><span style="color:#E06C75;font-style:italic">a</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">b</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span></span>
<span data-line=""><span style="color:#C678DD">      new</span><span style="color:#61AFEF"> Date</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">b</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">date</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">getTime</span><span style="color:#ABB2BF">() </span><span style="color:#56B6C2">-</span><span style="color:#C678DD"> new</span><span style="color:#61AFEF"> Date</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">a</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">date</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">getTime</span><span style="color:#ABB2BF">()</span></span>
<span data-line=""><span style="color:#ABB2BF">    );</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span></code></pre></figure>
<h3 id="markdown-转-html" class="heading-with-anchor">Markdown 转 HTML<a href="#markdown-转-html" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>使用 remark/rehype 流水线处理 Markdown，同时集成代码高亮：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">typescript</span><div class="code-block-meta"><span class="code-block-language">typescript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="typescript" data-theme="one-dark-pro"><code data-language="typescript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> { </span><span style="color:#E06C75">remark</span><span style="color:#ABB2BF"> } </span><span style="color:#C678DD">from</span><span style="color:#98C379"> "remark"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""><span style="color:#C678DD">import</span><span style="color:#E06C75"> remarkRehype</span><span style="color:#C678DD"> from</span><span style="color:#98C379"> "remark-rehype"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""><span style="color:#C678DD">import</span><span style="color:#E06C75"> rehypePrettyCode</span><span style="color:#C678DD"> from</span><span style="color:#98C379"> "rehype-pretty-code"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""><span style="color:#C678DD">import</span><span style="color:#E06C75"> rehypeStringify</span><span style="color:#C678DD"> from</span><span style="color:#98C379"> "rehype-stringify"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">const</span><span style="color:#E5C07B"> processed</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#61AFEF"> remark</span><span style="color:#ABB2BF">()</span></span>
<span data-line=""><span style="color:#ABB2BF">  .</span><span style="color:#61AFEF">use</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">remarkRehype</span><span style="color:#ABB2BF">)</span></span>
<span data-line=""><span style="color:#ABB2BF">  .</span><span style="color:#61AFEF">use</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">rehypePrettyCode</span><span style="color:#ABB2BF">, {</span></span>
<span data-line=""><span style="color:#E06C75">    theme</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"one-dark-pro"</span><span style="color:#ABB2BF">,  </span><span style="color:#7F848E;font-style:italic">// Shiki 代码主题</span></span>
<span data-line=""><span style="color:#E06C75">    keepBackground</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">true</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#ABB2BF">  })</span></span>
<span data-line=""><span style="color:#ABB2BF">  .</span><span style="color:#61AFEF">use</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">rehypeStringify</span><span style="color:#ABB2BF">)</span></span>
<span data-line=""><span style="color:#ABB2BF">  .</span><span style="color:#61AFEF">process</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">markdownContent</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">const</span><span style="color:#E5C07B"> html</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> processed</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">toString</span><span style="color:#ABB2BF">();</span></span></code></pre></figure>
<p>处理流程：<code>Markdown</code> → <code>remark AST</code> → <code>rehype AST</code>（含代码高亮） → <code>HTML 字符串</code></p>
<hr>
<h2 id="路由与页面" class="heading-with-anchor">路由与页面<a href="#路由与页面" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="首页" class="heading-with-anchor">首页<a href="#首页" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p><code>src/app/page.tsx</code> 直接调用 <code>getAllPosts()</code> 获取文章列表：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">tsx</span><div class="code-block-meta"><span class="code-block-language">tsx</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="tsx" data-theme="one-dark-pro"><code data-language="tsx" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">export</span><span style="color:#C678DD"> default</span><span style="color:#C678DD"> function</span><span style="color:#61AFEF"> HomePage</span><span style="color:#ABB2BF">() {</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> posts</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> getAllPosts</span><span style="color:#ABB2BF">();</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> tags</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> getAllTags</span><span style="color:#ABB2BF">();</span></span>
<span data-line=""><span style="color:#C678DD">  return</span><span style="color:#ABB2BF"> &#x3C;</span><span style="color:#E5C07B">HomeContent</span><span style="color:#D19A66;font-style:italic"> posts</span><span style="color:#56B6C2">=</span><span style="color:#C678DD">{</span><span style="color:#E06C75">posts</span><span style="color:#C678DD">}</span><span style="color:#D19A66;font-style:italic"> tags</span><span style="color:#56B6C2">=</span><span style="color:#C678DD">{</span><span style="color:#E06C75">tags</span><span style="color:#C678DD">}</span><span style="color:#ABB2BF"> />;</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span></code></pre></figure>
<h3 id="文章详情页" class="heading-with-anchor">文章详情页<a href="#文章详情页" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p><code>src/app/posts/[slug]/page.tsx</code> 使用动态路由：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">tsx</span><div class="code-block-meta"><span class="code-block-language">tsx</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="tsx" data-theme="one-dark-pro"><code data-language="tsx" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#7F848E;font-style:italic">// 告诉 Next.js 需要预渲染哪些页面</span></span>
<span data-line=""><span style="color:#C678DD">export</span><span style="color:#C678DD"> function</span><span style="color:#61AFEF"> generateStaticParams</span><span style="color:#ABB2BF">() {</span></span>
<span data-line=""><span style="color:#C678DD">  return</span><span style="color:#61AFEF"> getAllPosts</span><span style="color:#ABB2BF">().</span><span style="color:#61AFEF">map</span><span style="color:#ABB2BF">((</span><span style="color:#E06C75;font-style:italic">post</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> ({ </span><span style="color:#E06C75">slug</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">slug</span><span style="color:#ABB2BF"> }));</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#7F848E;font-style:italic">// 动态生成每篇文章的 meta 标签</span></span>
<span data-line=""><span style="color:#C678DD">export</span><span style="color:#C678DD"> async</span><span style="color:#C678DD"> function</span><span style="color:#61AFEF"> generateMetadata</span><span style="color:#ABB2BF">({ </span><span style="color:#E06C75;font-style:italic">params</span><span style="color:#ABB2BF"> }) {</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> post</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#61AFEF"> getPostBySlug</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">params</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">slug</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""><span style="color:#C678DD">  return</span><span style="color:#ABB2BF"> {</span></span>
<span data-line=""><span style="color:#E06C75">    title</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">title</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">    description</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">summary</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">    openGraph</span><span style="color:#ABB2BF">: {</span></span>
<span data-line=""><span style="color:#E06C75">      title</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">title</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">      description</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">summary</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">      type</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"article"</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#ABB2BF">    },</span></span>
<span data-line=""><span style="color:#ABB2BF">  };</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">export</span><span style="color:#C678DD"> default</span><span style="color:#C678DD"> async</span><span style="color:#C678DD"> function</span><span style="color:#61AFEF"> PostPage</span><span style="color:#ABB2BF">({ </span><span style="color:#E06C75;font-style:italic">params</span><span style="color:#ABB2BF"> }) {</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> post</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#61AFEF"> getPostBySlug</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">params</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">slug</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!</span><span style="color:#E06C75">post</span><span style="color:#ABB2BF">) </span><span style="color:#61AFEF">notFound</span><span style="color:#ABB2BF">();</span></span>
<span data-line=""><span style="color:#C678DD">  return</span><span style="color:#ABB2BF"> &#x3C;</span><span style="color:#E5C07B">PostContent</span><span style="color:#D19A66;font-style:italic"> post</span><span style="color:#56B6C2">=</span><span style="color:#C678DD">{</span><span style="color:#E06C75">post</span><span style="color:#C678DD">}</span><span style="color:#ABB2BF"> />;</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span></code></pre></figure>
<p><code>generateStaticParams</code> 让 Next.js 在构建时为每篇文章生成静态 HTML，访问时零延迟。</p>
<hr>
<h2 id="样式方案tailwind-css-自定义-css" class="heading-with-anchor">样式方案：Tailwind CSS + 自定义 CSS<a href="#样式方案tailwind-css-自定义-css" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>项目使用 Tailwind CSS 4 做原子化样式，同时用 <code>globals.css</code> 编写复杂组件样式。</p>
<h3 id="tailwind-配置" class="heading-with-anchor">Tailwind 配置<a href="#tailwind-配置" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p><code>postcss.config.mjs</code> 中启用 Tailwind：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">javascript</span><div class="code-block-meta"><span class="code-block-language">javascript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="javascript" data-theme="one-dark-pro"><code data-language="javascript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">export</span><span style="color:#C678DD"> default</span><span style="color:#ABB2BF"> {</span></span>
<span data-line=""><span style="color:#E06C75">  plugins</span><span style="color:#ABB2BF">: {</span></span>
<span data-line=""><span style="color:#98C379">    "@tailwindcss/postcss"</span><span style="color:#ABB2BF">: {},</span></span>
<span data-line=""><span style="color:#ABB2BF">  },</span></span>
<span data-line=""><span style="color:#ABB2BF">};</span></span></code></pre></figure>
<p>在 <code>globals.css</code> 顶部引入：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">css</span><div class="code-block-meta"><span class="code-block-language">css</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="css" data-theme="one-dark-pro"><code data-language="css" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">@import</span><span style="color:#98C379"> "tailwindcss"</span><span style="color:#ABB2BF">;</span></span></code></pre></figure>
<h3 id="暗色模式" class="heading-with-anchor">暗色模式<a href="#暗色模式" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>Tailwind 内置 <code>dark:</code> 前缀支持暗色模式。结合自定义主题切换：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">tsx</span><div class="code-block-meta"><span class="code-block-language">tsx</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="tsx" data-theme="one-dark-pro"><code data-language="tsx" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#7F848E;font-style:italic">// ThemeToggle 组件：system → light → dark 三态切换</span></span>
<span data-line=""><span style="color:#E5C07B">document</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">documentElement</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">setAttribute</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"data-theme"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"dark"</span><span style="color:#ABB2BF">);</span></span></code></pre></figure>
<p>CSS 中同时处理系统偏好和手动切换：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">css</span><div class="code-block-meta"><span class="code-block-language">css</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="css" data-theme="one-dark-pro"><code data-language="css" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">@media</span><span style="color:#ABB2BF"> (prefers-color-scheme: dark) {</span></span>
<span data-line=""><span style="color:#56B6C2">  :root:not</span><span style="color:#C678DD">([</span><span style="color:#D19A66">data-theme</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"light"</span><span style="color:#C678DD">]) </span><span style="color:#D19A66">.my-class</span><span style="color:#ABB2BF"> { </span><span style="color:#7F848E;font-style:italic">/* 暗色样式 */</span><span style="color:#ABB2BF"> }</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span>
<span data-line=""><span style="color:#C678DD">[</span><span style="color:#D19A66">data-theme</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"dark"</span><span style="color:#C678DD">] </span><span style="color:#D19A66">.my-class</span><span style="color:#ABB2BF"> { </span><span style="color:#7F848E;font-style:italic">/* 暗色样式 */</span><span style="color:#ABB2BF"> }</span></span></code></pre></figure>
<hr>
<h2 id="代码高亮" class="heading-with-anchor">代码高亮<a href="#代码高亮" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>使用 <code>rehype-pretty-code</code> + <code>Shiki</code> 实现语法高亮，支持：</p>
<ul>
<li>上百种编程语言</li>
<li>多种主题（本项目使用 <code>one-dark-pro</code>）</li>
<li>diff 高亮（<code>+</code>/<code>-</code> 标记新增/删除行）</li>
<li>行号显示</li>
<li>语言标签自动显示</li>
</ul>
<p>代码块的 HTML 结构：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">html</span><div class="code-block-meta"><span class="code-block-language">html</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="html" data-theme="one-dark-pro"><code data-language="html" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#ABB2BF">&#x3C;</span><span style="color:#E06C75">pre</span><span style="color:#D19A66"> data-language</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"typescript"</span><span style="color:#ABB2BF">></span></span>
<span data-line=""><span style="color:#ABB2BF">  &#x3C;</span><span style="color:#E06C75">code</span><span style="color:#ABB2BF">>...&#x3C;/</span><span style="color:#E06C75">code</span><span style="color:#ABB2BF">></span></span>
<span data-line=""><span style="color:#ABB2BF">&#x3C;/</span><span style="color:#E06C75">pre</span><span style="color:#ABB2BF">></span></span></code></pre></figure>
<p>通过 CSS 伪元素自动显示语言标签：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">css</span><div class="code-block-meta"><span class="code-block-language">css</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="css" data-theme="one-dark-pro"><code data-language="css" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#D19A66">.prose</span><span style="color:#E06C75"> pre</span><span style="color:#C678DD">[</span><span style="color:#D19A66">data-language</span><span style="color:#C678DD">]</span><span style="color:#56B6C2">::before</span><span style="color:#ABB2BF"> {</span></span>
<span data-line=""><span style="color:#ABB2BF">  content: </span><span style="color:#56B6C2">attr</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75;font-style:italic">data-language</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""><span style="color:#7F848E;font-style:italic">  /* 定位和样式... */</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span></code></pre></figure>
<hr>
<h2 id="seo-优化" class="heading-with-anchor">SEO 优化<a href="#seo-优化" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="动态-metadata" class="heading-with-anchor">动态 Metadata<a href="#动态-metadata" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>每篇文章通过 <code>generateMetadata</code> 生成独立的 meta 标签：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">typescript</span><div class="code-block-meta"><span class="code-block-language">typescript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="typescript" data-theme="one-dark-pro"><code data-language="typescript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">export</span><span style="color:#C678DD"> async</span><span style="color:#C678DD"> function</span><span style="color:#61AFEF"> generateMetadata</span><span style="color:#ABB2BF">({ </span><span style="color:#E06C75;font-style:italic">params</span><span style="color:#ABB2BF"> }) {</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> post</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#61AFEF"> getPostBySlug</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">params</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">slug</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""><span style="color:#C678DD">  return</span><span style="color:#ABB2BF"> {</span></span>
<span data-line=""><span style="color:#E06C75">    title</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">title</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">    description</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">summary</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">    openGraph</span><span style="color:#ABB2BF">: { </span><span style="color:#7F848E;font-style:italic">/* OG 标签 */</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#E06C75">    twitter</span><span style="color:#ABB2BF">: { </span><span style="color:#7F848E;font-style:italic">/* Twitter Card */</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#ABB2BF">  };</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span></code></pre></figure>
<h3 id="og-图片动态生成" class="heading-with-anchor">OG 图片动态生成<a href="#og-图片动态生成" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>使用 Next.js 内置的 <code>ImageResponse</code> API 为每篇文章生成社交预览图：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">typescript</span><div class="code-block-meta"><span class="code-block-language">typescript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="typescript" data-theme="one-dark-pro"><code data-language="typescript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#7F848E;font-style:italic">// src/app/api/og/route.tsx</span></span>
<span data-line=""><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> { </span><span style="color:#E06C75">ImageResponse</span><span style="color:#ABB2BF"> } </span><span style="color:#C678DD">from</span><span style="color:#98C379"> "next/og"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">export</span><span style="color:#C678DD"> async</span><span style="color:#C678DD"> function</span><span style="color:#61AFEF"> GET</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75;font-style:italic">request</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">Request</span><span style="color:#ABB2BF">) {</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> slug</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> new</span><span style="color:#61AFEF"> URL</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">request</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">url</span><span style="color:#ABB2BF">).</span><span style="color:#E5C07B">searchParams</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">get</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"slug"</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> post</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#61AFEF"> getPostBySlug</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">slug</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">  return</span><span style="color:#C678DD"> new</span><span style="color:#61AFEF"> ImageResponse</span><span style="color:#ABB2BF">(</span></span>
<span data-line=""><span style="color:#ABB2BF">    (</span></span>
<span data-line=""><span style="color:#56B6C2">      &#x3C;</span><span style="color:#E06C75">div</span><span style="color:#E06C75"> style</span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF">{{ </span><span style="color:#7F848E;font-style:italic">/* 布局和样式 */</span><span style="color:#ABB2BF"> }}</span><span style="color:#56B6C2">></span></span>
<span data-line=""><span style="color:#ABB2BF">        &#x3C;</span><span style="color:#E5C07B">div</span><span style="color:#ABB2BF">>{post.</span><span style="color:#E06C75">title</span><span style="color:#ABB2BF">}</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#E06C75">div</span><span style="color:#56B6C2">></span></span>
<span data-line=""><span style="color:#ABB2BF">        &#x3C;</span><span style="color:#E5C07B">div</span><span style="color:#ABB2BF">>{post.</span><span style="color:#E06C75">summary</span><span style="color:#ABB2BF">}</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#E06C75">div</span><span style="color:#56B6C2">></span></span>
<span data-line=""><span style="color:#56B6C2">      &#x3C;/</span><span style="color:#E06C75">div</span><span style="color:#56B6C2">></span></span>
<span data-line=""><span style="color:#ABB2BF">    ),</span></span>
<span data-line=""><span style="color:#ABB2BF">    { </span><span style="color:#E06C75">width</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">1200</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">height</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">630</span><span style="color:#ABB2BF"> }</span></span>
<span data-line=""><span style="color:#ABB2BF">  );</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span></code></pre></figure>
<p>在 <code>generateMetadata</code> 中引用：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">typescript</span><div class="code-block-meta"><span class="code-block-language">typescript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="typescript" data-theme="one-dark-pro"><code data-language="typescript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#E06C75">openGraph</span><span style="color:#ABB2BF">: {</span></span>
<span data-line=""><span style="color:#E06C75">  images</span><span style="color:#ABB2BF">: [{ </span><span style="color:#E06C75">url</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">`/api/og?slug=</span><span style="color:#C678DD">${</span><span style="color:#E06C75">slug</span><span style="color:#C678DD">}</span><span style="color:#98C379">`</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">width</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">1200</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">height</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">630</span><span style="color:#ABB2BF"> }],</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span></code></pre></figure>
<h3 id="json-ld-结构化数据" class="heading-with-anchor">JSON-LD 结构化数据<a href="#json-ld-结构化数据" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>帮助搜索引擎理解文章内容：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">typescript</span><div class="code-block-meta"><span class="code-block-language">typescript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="typescript" data-theme="one-dark-pro"><code data-language="typescript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">const</span><span style="color:#E5C07B"> jsonLd</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> {</span></span>
<span data-line=""><span style="color:#98C379">  "@context"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"https://schema.org"</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#98C379">  "@type"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"Article"</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">  headline</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">title</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">  datePublished</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">date</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#E06C75">  author</span><span style="color:#ABB2BF">: { </span><span style="color:#98C379">"@type"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"Person"</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">name</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"LunaPath"</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#E06C75">  wordCount</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">post</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">wordCount</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#ABB2BF">};</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#7F848E;font-style:italic">// 在页面中注入</span></span>
<span data-line=""><span style="color:#56B6C2">&#x3C;</span><span style="color:#E06C75">script</span><span style="color:#E06C75"> type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"application/ld+json"</span></span>
<span data-line=""><span style="color:#E06C75">  dangerouslySetInnerHTML</span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF">{{ </span><span style="color:#E06C75">__html</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">JSON</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">stringify</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">jsonLd</span><span style="color:#ABB2BF">) }} </span><span style="color:#56B6C2">/></span></span></code></pre></figure>
<h3 id="rss-sitemap-robots" class="heading-with-anchor">RSS / Sitemap / Robots<a href="#rss-sitemap-robots" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>RSS</strong>：<code>src/app/feed.xml/route.ts</code> 生成 RSS 2.0 订阅源</li>
<li><strong>Sitemap</strong>：<code>src/app/sitemap.ts</code> 动态生成站点地图</li>
<li><strong>Robots</strong>：<code>src/app/robots.ts</code> 配置爬虫规则</li>
</ul>
<hr>
<h2 id="搜索功能" class="heading-with-anchor">搜索功能<a href="#搜索功能" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>使用 <code>Fuse.js</code> 实现客户端模糊搜索：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">typescript</span><div class="code-block-meta"><span class="code-block-language">typescript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="typescript" data-theme="one-dark-pro"><code data-language="typescript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">import</span><span style="color:#E06C75"> Fuse</span><span style="color:#C678DD"> from</span><span style="color:#98C379"> "fuse.js"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">const</span><span style="color:#E5C07B"> fuse</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> new</span><span style="color:#61AFEF"> Fuse</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">posts</span><span style="color:#ABB2BF">, {</span></span>
<span data-line=""><span style="color:#E06C75">  keys</span><span style="color:#ABB2BF">: [</span></span>
<span data-line=""><span style="color:#ABB2BF">    { </span><span style="color:#E06C75">name</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"title"</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">weight</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">3</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#ABB2BF">    { </span><span style="color:#E06C75">name</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"summary"</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">weight</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">2</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#ABB2BF">    { </span><span style="color:#E06C75">name</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"tags"</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">weight</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">1.5</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#ABB2BF">    { </span><span style="color:#E06C75">name</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"content"</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">weight</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">1</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#ABB2BF">  ],</span></span>
<span data-line=""><span style="color:#E06C75">  threshold</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">0.4</span><span style="color:#ABB2BF">,</span></span>
<span data-line=""><span style="color:#ABB2BF">});</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">const</span><span style="color:#E5C07B"> results</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> fuse</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">search</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">keyword</span><span style="color:#ABB2BF">);</span></span></code></pre></figure>
<p>搜索索引通过 API Route <code>/api/search-index</code> 提供，前端在打开搜索框时异步加载。</p>
<hr>
<h2 id="评论系统" class="heading-with-anchor">评论系统<a href="#评论系统" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>使用 <a href="https://giscus.app/">Giscus</a> 基于 GitHub Discussions 的评论。</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">bash</span><div class="code-block-meta"><span class="code-block-language">bash</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="bash" data-theme="one-dark-pro"><code data-language="bash" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#61AFEF">npm</span><span style="color:#98C379"> install</span><span style="color:#98C379"> @giscus/react</span></span></code></pre></figure>
<p>在 <code>.env.local</code> 中配置：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">bash</span><div class="code-block-meta"><span class="code-block-language">bash</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="bash" data-theme="one-dark-pro"><code data-language="bash" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#E06C75">NEXT_PUBLIC_GISCUS_REPO_ID</span><span style="color:#56B6C2">=</span><span style="color:#98C379">...</span></span>
<span data-line=""><span style="color:#E06C75">NEXT_PUBLIC_GISCUS_CATEGORY_ID</span><span style="color:#56B6C2">=</span><span style="color:#98C379">...</span></span></code></pre></figure>
<p>组件会自动读取环境变量并跟随站点主题 / 语言：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">tsx</span><div class="code-block-meta"><span class="code-block-language">tsx</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="tsx" data-theme="one-dark-pro"><code data-language="tsx" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">import</span><span style="color:#E06C75"> Giscus</span><span style="color:#C678DD"> from</span><span style="color:#98C379"> "@giscus/react"</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#ABB2BF">&#x3C;</span><span style="color:#E5C07B">Giscus</span></span>
<span data-line=""><span style="color:#D19A66;font-style:italic">  repo</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"your-username/your-repo"</span></span>
<span data-line=""><span style="color:#D19A66;font-style:italic">  repoId</span><span style="color:#56B6C2">=</span><span style="color:#C678DD">{</span><span style="color:#E5C07B">process</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">env</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">NEXT_PUBLIC_GISCUS_REPO_ID</span><span style="color:#56B6C2"> ??</span><span style="color:#98C379"> ""</span><span style="color:#C678DD">}</span></span>
<span data-line=""><span style="color:#D19A66;font-style:italic">  category</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"Announcements"</span></span>
<span data-line=""><span style="color:#D19A66;font-style:italic">  categoryId</span><span style="color:#56B6C2">=</span><span style="color:#C678DD">{</span><span style="color:#E5C07B">process</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">env</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">NEXT_PUBLIC_GISCUS_CATEGORY_ID</span><span style="color:#56B6C2"> ??</span><span style="color:#98C379"> ""</span><span style="color:#C678DD">}</span></span>
<span data-line=""><span style="color:#D19A66;font-style:italic">  mapping</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"pathname"</span></span>
<span data-line=""><span style="color:#D19A66;font-style:italic">  loading</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"lazy"</span></span>
<span data-line=""><span style="color:#ABB2BF">/></span></span></code></pre></figure>
<hr>
<h2 id="国际化-i18n" class="heading-with-anchor">国际化 (i18n)<a href="#国际化-i18n" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>通过 React Context 实现中英文切换：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">typescript</span><div class="code-block-meta"><span class="code-block-language">typescript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="typescript" data-theme="one-dark-pro"><code data-language="typescript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">const</span><span style="color:#E5C07B"> translations</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> {</span></span>
<span data-line=""><span style="color:#E06C75">  zh</span><span style="color:#ABB2BF">: { </span><span style="color:#98C379">"nav.home"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"首页"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"nav.about"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"关于"</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#E06C75">  en</span><span style="color:#ABB2BF">: { </span><span style="color:#98C379">"nav.home"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"Home"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"nav.about"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"About"</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#ABB2BF">};</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">function</span><span style="color:#61AFEF"> useI18n</span><span style="color:#ABB2BF">() {</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#ABB2BF"> { </span><span style="color:#E5C07B">locale</span><span style="color:#ABB2BF"> } </span><span style="color:#56B6C2">=</span><span style="color:#61AFEF"> useContext</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">I18nContext</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#61AFEF"> t</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75;font-style:italic">key</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">string</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#E06C75"> translations</span><span style="color:#ABB2BF">[</span><span style="color:#E06C75">locale</span><span style="color:#ABB2BF">][</span><span style="color:#E06C75">key</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">??</span><span style="color:#E06C75"> key</span><span style="color:#ABB2BF">;</span></span>
<span data-line=""><span style="color:#C678DD">  return</span><span style="color:#ABB2BF"> { </span><span style="color:#E06C75">locale</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">t</span><span style="color:#ABB2BF"> };</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span></code></pre></figure>
<p>组件中使用：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">tsx</span><div class="code-block-meta"><span class="code-block-language">tsx</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="tsx" data-theme="one-dark-pro"><code data-language="tsx" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#C678DD">const</span><span style="color:#ABB2BF"> { </span><span style="color:#E5C07B">t</span><span style="color:#ABB2BF"> } </span><span style="color:#56B6C2">=</span><span style="color:#61AFEF"> useI18n</span><span style="color:#ABB2BF">();</span></span>
<span data-line=""><span style="color:#C678DD">return</span><span style="color:#ABB2BF"> &#x3C;</span><span style="color:#E06C75">h1</span><span style="color:#ABB2BF">></span><span style="color:#C678DD">{</span><span style="color:#61AFEF">t</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"home.greeting"</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">}</span><span style="color:#ABB2BF">&#x3C;/</span><span style="color:#E06C75">h1</span><span style="color:#ABB2BF">>;</span></span></code></pre></figure>
<p>语言偏好存储在 <code>localStorage</code>，服务端渲染时默认中文避免闪烁。</p>
<hr>
<h2 id="交互功能" class="heading-with-anchor">交互功能<a href="#交互功能" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="订阅表单" class="heading-with-anchor">订阅表单<a href="#订阅表单" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>前端表单 POST 到 <code>/api/subscribe</code>，后端 Route Handler 负责校验邮箱并调用 Resend Audience API：</p>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">typescript</span><div class="code-block-meta"><span class="code-block-language">typescript</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="typescript" data-theme="one-dark-pro"><code data-language="typescript" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#7F848E;font-style:italic">// src/app/api/subscribe/route.ts</span></span>
<span data-line=""><span style="color:#C678DD">export</span><span style="color:#C678DD"> async</span><span style="color:#C678DD"> function</span><span style="color:#61AFEF"> POST</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75;font-style:italic">request</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">Request</span><span style="color:#ABB2BF">) {</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> payload</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#E5C07B"> request</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">json</span><span style="color:#ABB2BF">();</span></span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> validation</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> validateSubscribePayload</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">payload</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!</span><span style="color:#E5C07B">validation</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">ok</span><span style="color:#ABB2BF">) {</span></span>
<span data-line=""><span style="color:#C678DD">    return</span><span style="color:#E5C07B"> Response</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">json</span><span style="color:#ABB2BF">(</span></span>
<span data-line=""><span style="color:#ABB2BF">      { </span><span style="color:#E06C75">ok</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">false</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">error</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">validation</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">error</span><span style="color:#ABB2BF"> },</span></span>
<span data-line=""><span style="color:#ABB2BF">      { </span><span style="color:#E06C75">status</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">validation</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">status</span><span style="color:#ABB2BF"> }</span></span>
<span data-line=""><span style="color:#ABB2BF">    );</span></span>
<span data-line=""><span style="color:#ABB2BF">  }</span></span>
<span data-line=""> </span>
<span data-line=""><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> result</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#61AFEF"> addSubscriber</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">validation</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">data</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">email</span><span style="color:#ABB2BF">);</span></span>
<span data-line=""><span style="color:#C678DD">  return</span><span style="color:#E5C07B"> Response</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">json</span><span style="color:#ABB2BF">({ </span><span style="color:#E06C75">ok</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">true</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">code</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">result</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">code</span><span style="color:#ABB2BF"> });</span></span>
<span data-line=""><span style="color:#ABB2BF">}</span></span></code></pre></figure>
<h3 id="联系表单" class="heading-with-anchor">联系表单<a href="#联系表单" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>联系表单 POST 到 <code>/api/contact</code>，服务端校验姓名、邮箱和留言长度后，通过 Resend 把内容发送到站长邮箱。这样适合部署到 Vercel/serverless，不依赖运行时写入本地 JSON 文件。</p>
<hr>
<h2 id="部署" class="heading-with-anchor">部署<a href="#部署" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="vercel推荐" class="heading-with-anchor">Vercel（推荐）<a href="#vercel推荐" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<figure data-rehype-pretty-code-figure="" class="code-block"><div class="code-block-header"><span class="code-block-title">bash</span><div class="code-block-meta"><span class="code-block-language">bash</span><div class="code-block-actions"></div></div></div><pre style="background-color:#282c34;color:#abb2bf" tabindex="0" data-language="bash" data-theme="one-dark-pro"><code data-language="bash" data-theme="one-dark-pro" style="display: grid;"><span data-line=""><span style="color:#61AFEF">npm</span><span style="color:#98C379"> run</span><span style="color:#98C379"> build</span><span style="color:#7F848E;font-style:italic">    # 本地验证构建</span></span>
<span data-line=""><span style="color:#61AFEF">npm</span><span style="color:#98C379"> run</span><span style="color:#98C379"> start</span><span style="color:#7F848E;font-style:italic">    # 本地预览</span></span></code></pre></figure>
<p>推送到 GitHub 后，在 Vercel 导入项目即可自动部署。每次 push 触发重新构建。</p>
<h3 id="其他平台" class="heading-with-anchor">其他平台<a href="#其他平台" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p><code>npm run build</code> 生成 <code>.next/</code> 静态文件，可部署到任何支持 Node.js 或静态托管的平台（Netlify、Cloudflare Pages 等）。</p>
<hr>
<h2 id="总结" class="heading-with-anchor">总结<a href="#总结" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>用 Next.js 搭建博客的核心流程：</p>
<ol>
<li><code>create-next-app</code> 初始化项目</li>
<li>安装 Markdown 处理依赖（gray-matter + remark + rehype）</li>
<li>编写 <code>lib/posts.ts</code> 数据层</li>
<li>用 App Router 创建页面路由</li>
<li>添加样式（Tailwind + 自定义 CSS）</li>
<li>补充 SEO（metadata、OG、JSON-LD、RSS、sitemap）</li>
<li>添加交互功能（搜索、订阅、评论）</li>
<li>部署到 Vercel</li>
</ol>
<p>完整代码参考：本博客的所有源码。</p>]]></content:encoded>
      <category>技术</category>
      <category>Next.js</category>
    </item>
    <item>
      <title><![CDATA[PUBG 吃鸡实战指南 — 从落地成盒到大吉大利]]></title>
      <link>http://localhost:3000/posts/pubg-guide</link>
      <guid isPermaLink="true">http://localhost:3000/posts/pubg-guide</guid>
      <pubDate>Wed, 10 Jun 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[PUBG 的核心是生存而非击杀。本文涵盖跳伞策略、枪械选择、身法走位、决赛圈打法，帮你稳定进前十。]]></description>
      <content:encoded><![CDATA[<h2 id="核心理念活到最后才是赢家" class="heading-with-anchor">核心理念：活到最后才是赢家<a href="#核心理念活到最后才是赢家" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>PUBG 不是射击游戏，是<strong>生存游戏</strong>。100 个人里只有 1 个能吃鸡，但进前 10 已经算赢了。</p>
<ul>
<li>击杀数 ≠ 排名，杀 10 个但第 20 名毫无意义</li>
<li>前期避战、后期发力是稳定上分的核心策略</li>
<li>信息 > 枪法：知道敌人在哪比能打中更重要</li>
</ul>
<h2 id="跳伞策略" class="heading-with-anchor">跳伞策略<a href="#跳伞策略" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="热点-vs-冷点" class="heading-with-anchor">热点 vs 冷点<a href="#热点-vs-冷点" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>| 策略 | 落点 | 风险 | 收益 |
|------|------|------|------|
| 刚枪流 | 军事基地、Pecado、School | 高 | 快速成型 |
| 打野流 | 路边小房群、偏远村庄 | 低 | 稳定发育 |
| 折中流 | 中型城镇边缘 | 中 | 平衡 |</p>
<h3 id="新手推荐" class="heading-with-anchor">新手推荐<a href="#新手推荐" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>不要跳热点</strong>：落地成盒学不到任何东西</li>
<li><strong>跳航线两侧 1-2 格的中型点</strong>：人少、物资够</li>
<li><strong>提前开伞飘远处</strong>：落地时周围没人 = 安全发育</li>
</ul>
<h3 id="跳伞技巧" class="heading-with-anchor">跳伞技巧<a href="#跳伞技巧" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>标记落点后，视角朝下俯冲，速度 234km/h</li>
<li>距离目标约 100-150m 时水平飞过去</li>
<li>开伞后按住 Ctrl 可以滑翔更远</li>
</ul>
<h2 id="枪械选择" class="heading-with-anchor">枪械选择<a href="#枪械选择" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="推荐新手搭配" class="heading-with-anchor">推荐新手搭配<a href="#推荐新手搭配" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p><strong>方案一：全能型</strong></p>
<ul>
<li>主武器：M416（突击步枪，稳定性最好）</li>
<li>副武器：Mini14 / SLR（精准步枪，中远距离）</li>
</ul>
<p><strong>方案二：近战刚枪</strong></p>
<ul>
<li>主武器：Beryl M762（高伤害，需要练压枪）</li>
<li>副武器：UMP45（冲锋枪，近战稳定）</li>
</ul>
<p><strong>方案三：远距离</strong></p>
<ul>
<li>主武器：Kar98k / M24（栓狙，一枪爆头）</li>
<li>副武器：M416（中近距离补枪）</li>
</ul>
<h3 id="枪械优先级" class="heading-with-anchor">枪械优先级<a href="#枪械优先级" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>突击步枪</strong>：M416 > SCAR-L > Beryl M762 > AKM</li>
<li><strong>精准步枪</strong>：Mini14 > SLR > SKS</li>
<li><strong>栓动狙击</strong>：AWM > M24 > Kar98k</li>
<li><strong>冲锋枪</strong>：UMP45 > Vector > UZI</li>
</ul>
<h3 id="配件很重要" class="heading-with-anchor">配件很重要<a href="#配件很重要" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>握把</strong>：垂直握把（减后坐）> 半截式握把 > 拇指握把</li>
<li><strong>枪口</strong>：消音器（隐蔽）> 补偿器（稳定）> 消焰器</li>
<li><strong>弹夹</strong>：扩容快速弹夹 > 快速弹夹 > 扩容弹夹</li>
</ul>
<h2 id="身法与走位" class="heading-with-anchor">身法与走位<a href="#身法与走位" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="对枪原则" class="heading-with-anchor">对枪原则<a href="#对枪原则" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>不要站桩输出</strong>：打几枪就换位置</li>
<li><strong>利用第三人称视角</strong>：TPP 模式下躲在掩体后观察</li>
<li><strong>探头射击</strong>：QE 探头打，打完立刻缩回来</li>
<li><strong>蹲起交替</strong>：对枪时按 C 蹲起，让敌人难以瞄准</li>
</ul>
<h3 id="跑毒走位" class="heading-with-anchor">跑毒走位<a href="#跑毒走位" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>贴毒边跑</strong>：从毒圈外侧切入，背后安全</li>
<li><strong>不要直线跑</strong>：蛇皮走位（Z 字形）减少被打中的概率</li>
<li><strong>有掩体就贴</strong>：树 > 石头 > 房子 > 空地</li>
<li><strong>载具是双刃剑</strong>：速度快但暴露位置，决赛圈前丢车</li>
</ul>
<h2 id="决赛圈打法" class="heading-with-anchor">决赛圈打法<a href="#决赛圈打法" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="进圈时机" class="heading-with-anchor">进圈时机<a href="#进圈时机" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>第 1-3 圈</strong>：不用急，慢慢搜物资</li>
<li><strong>第 4 圈</strong>：开始转移，找好位置</li>
<li><strong>第 5-6 圈</strong>：必须进圈，迟了就被毒死</li>
</ul>
<h3 id="位置选择" class="heading-with-anchor">位置选择<a href="#位置选择" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>高打低</strong>：高地永远优于低地</li>
<li><strong>圈中心</strong>：安全但容易四面受敌</li>
<li><strong>圈边</strong>：只需防一面，但要不断转移</li>
<li><strong>房子里</strong>：安全但容易被攻楼</li>
</ul>
<h3 id="决赛圈技巧" class="heading-with-anchor">决赛圈技巧<a href="#决赛圈技巧" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ol>
<li><strong>不要先开枪</strong>：暴露位置 = 被集火</li>
<li><strong>等别人打起来再出手</strong>：鹬蚌相争渔翁得利</li>
<li><strong>烟雾弹是神器</strong>：进圈、救人、转移都要用</li>
<li><strong>手雷逼位</strong>：往敌人掩体后扔雷，逼他出来</li>
</ol>
<h2 id="实用设置" class="heading-with-anchor">实用设置<a href="#实用设置" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<ul>
<li><strong>灵敏度</strong>：DPI 800，游戏内 30-40（根据个人习惯调整）</li>
<li><strong>自动拾取</strong>：关闭，手动拾取更精准</li>
<li><strong>自动奔跑</strong>：开启，解放左手</li>
<li><strong>声音</strong>：戴耳机，调大脚步声，听声辨位</li>
</ul>
<hr>
<p>吃鸡是一个概率游戏。即使你做到 100% 正确，也可能被一个蹲厕所的人阴死。但长期来看，好的策略一定会让你的平均排名稳步提升。大吉大利，今晚吃鸡！</p>]]></content:encoded>
      <category>游戏</category>
      <category>PUBG</category>
      <category>攻略</category>
    </item>
    <item>
      <title><![CDATA[GTA5 线上模式赚钱指南 — 从零到亿万富翁]]></title>
      <link>http://localhost:3000/posts/gta5-guide</link>
      <guid isPermaLink="true">http://localhost:3000/posts/gta5-guide</guid>
      <pubDate>Fri, 05 Jun 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[GTA5 线上模式的核心是资产运营。本文涵盖新手赚钱路线、各产业收益对比、佩里科岛抢劫攻略和实用技巧。]]></description>
      <content:encoded><![CDATA[<h2 id="核心理念资产-被动收入" class="heading-with-anchor">核心理念：资产 = 被动收入<a href="#核心理念资产-被动收入" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>GTA5 线上模式的本质是一个<strong>商业模拟器</strong>。你不是在抢劫，你是在经营一家犯罪集团。</p>
<ul>
<li>前期靠手动任务赚钱</li>
<li>中期靠购买产业产生被动收入</li>
<li>后期靠多个产业同时运转，钱自动进账</li>
</ul>
<h2 id="新手赚钱路线推荐顺序" class="heading-with-anchor">新手赚钱路线（推荐顺序）<a href="#新手赚钱路线推荐顺序" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="第一阶段攒第一桶金0-22m" class="heading-with-anchor">第一阶段：攒第一桶金（$0 → $2.2M）<a href="#第一阶段攒第一桶金0-22m" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ol>
<li><strong>完成新手教程</strong>：跟着教程走，熟悉基本操作</li>
<li><strong>做联系人任务</strong>：Gerald、Simeon、Martin 的任务稳定收入</li>
<li><strong>做每日目标</strong>：每天 3 个小任务，完成有额外奖励</li>
<li><strong>参与活动/竞速</strong>：双倍奖励周活动收入翻倍</li>
</ol>
<blockquote>
<p>目标：攒够 $2,200,000 买潜艇</p>
</blockquote>
<h3 id="第二阶段佩里科岛抢劫22m-10m" class="heading-with-anchor">第二阶段：佩里科岛抢劫（$2.2M → $10M+）<a href="#第二阶段佩里科岛抢劫22m-10m" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>这是<strong>新手最赚钱的方式</strong>，没有之一：</p>
<ul>
<li>购买 <strong>Kosatka 潜艇</strong>（$2.2M）</li>
<li>解锁佩里科岛抢劫（Cayo Perico Heist）</li>
<li>单人即可完成，不需要队友</li>
<li>每次净赚 $1.2M - $1.8M</li>
<li>冷却时间：现实时间 48 分钟（普通）/ 144 分钟（困难）</li>
</ul>
<blockquote>
<p>这是整个 GTA 线上性价比最高的赚钱方式。买潜艇 → 刷佩里科 → 买产业 → 被动收入</p>
</blockquote>
<h3 id="第三阶段建立产业帝国10m" class="heading-with-anchor">第三阶段：建立产业帝国（$10M+）<a href="#第三阶段建立产业帝国10m" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>有了本金后，逐步购买以下产业：</p>
<p>| 产业 | 价格 | 收益 | 优先级 |
|------|------|------|--------|
| 摩托车作坊（可卡因） | ~$2M | 被动收入，满仓 $420K | ★★★ |
| 办公室+CEO仓库 | ~$3M | 大宗货物交易 | ★★★ |
| 地堡 | ~$2.5M | 武器贩卖，满仓 $1.05M | ★★★ |
| 夜总会 | ~$1.5M | 自动整合其他产业收入 | ★★ |
| 设施 | ~$2.5M | 解锁末日抢劫 | ★★ |
| 游戏厅 | ~$2M | 解锁钻石赌场抢劫 | ★ |</p>
<h2 id="佩里科岛抢劫攻略" class="heading-with-anchor">佩里科岛抢劫攻略<a href="#佩里科岛抢劫攻略" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="准备阶段" class="heading-with-anchor">准备阶段<a href="#准备阶段" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ol>
<li><strong>侦察</strong>：飞到岛上，标记主目标（通常在地下室）</li>
<li><strong>武器</strong>：推荐「神射手」装（精准步枪+消音器）</li>
<li><strong>载具</strong>：推荐「长鳍」潜艇突入（最隐蔽）</li>
<li><strong>设备</strong>：一定要做「等离子切割器」和「指纹克隆」</li>
</ol>
<h3 id="入侵路线最推荐隐蔽流" class="heading-with-anchor">入侵路线（最推荐：隐蔽流）<a href="#入侵路线最推荐隐蔽流" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ol>
<li>从潜艇出发，用长鳍靠近岛屿</li>
<li>游泳到排水管道入口（水下，不会被发现）</li>
<li>进入 compound 后，沿左侧围墙走</li>
<li>用消音器逐个击杀守卫</li>
<li>进入地下室，拿到主目标</li>
<li>从正门离开，跳海游泳逃离</li>
</ol>
<blockquote>
<p>整个过程可以不被发现完成，难度不高但需要记住路线</p>
</blockquote>
<h3 id="收益最大化" class="heading-with-anchor">收益最大化<a href="#收益最大化" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>困难模式</strong>：在普通冷却结束后 48 小时内再次开启，目标价值 +10%</li>
<li><strong>挑金条</strong>：副目标选金条（每格 $330K），比现金和画值钱</li>
<li><strong>满背包</strong>：先搜副目标再拿主目标，背包满了收益更高</li>
</ul>
<h2 id="战斗与生存技巧" class="heading-with-anchor">战斗与生存技巧<a href="#战斗与生存技巧" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="对枪技巧" class="heading-with-anchor">对枪技巧<a href="#对枪技巧" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>自动瞄准</strong>：主机版默认开启，PC 版关闭</li>
<li><strong>掩体射击</strong>：按 Q/RB 进入掩体，探头射击</li>
<li><strong>吃零食</strong>：对枪时打开物品栏吃零食回血（不用动画时间）</li>
<li><strong>防弹衣</strong>：任务前在武器店买满防弹衣</li>
</ul>
<h3 id="载具技巧" class="heading-with-anchor">载具技巧<a href="#载具技巧" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>Kuruma（装甲版）</strong>：新手神车，防弹、速度快</li>
<li><strong>Oppressor Mk II</strong>：后期神器，飞行摩托，但贵（$6M+）</li>
<li><strong>Buzzard 直升机</strong>：CEO 可免费召唤，赶路神器</li>
</ul>
<h3 id="避坑指南" class="heading-with-anchor">避坑指南<a href="#避坑指南" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>不要在公开战局卖货</strong>：会被外挂/大佬炸掉</li>
<li><strong>单人战局方法</strong>：网络设置 → 测试 NAT 类型 → 回到游戏（PC 任务管理器暂停网络 10 秒）</li>
<li><strong>不要乱花钱</strong>：先买赚钱工具，再买玩具</li>
<li><strong>外挂很多</strong>：遇到外挂直接换战局，不要浪费时间</li>
</ul>
<h2 id="被动收入运营" class="heading-with-anchor">被动收入运营<a href="#被动收入运营" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="日常循环" class="heading-with-anchor">日常循环<a href="#日常循环" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ol>
<li>登录 → 补货各产业（购买原料）</li>
<li>做佩里科岛抢劫（趁产业生产的时间）</li>
<li>抢劫完 → 检查产业是否满仓</li>
<li>满仓了 → 出货（最好在单人战局）</li>
<li>重复</li>
</ol>
<h3 id="收益时间表" class="heading-with-anchor">收益时间表<a href="#收益时间表" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>| 产业 | 生产时间 | 满仓收益 |
|------|----------|----------|
| 可卡因 | ~5 小时 | $420K |
| 地堡 | ~11 小时 | $1.05M |
| 夜总会 | ~20 小时 | $1.69M（满仓） |
| CEO 仓库 | 手动收集 | $2.2M（111 箱） |</p>
<hr>
<p>GTA5 线上是一个长期游戏。不要急于求成，也不要被老玩家的资产吓到。按照路线一步步来，用不了几周你也能拥有自己的犯罪帝国。</p>]]></content:encoded>
      <category>游戏</category>
      <category>GTA5</category>
      <category>攻略</category>
    </item>
    <item>
      <title><![CDATA[PLC 学习路线规划 — 从零基础到独立编程]]></title>
      <link>http://localhost:3000/posts/plc-learning-roadmap</link>
      <guid isPermaLink="true">http://localhost:3000/posts/plc-learning-roadmap</guid>
      <pubDate>Mon, 01 Jun 2026 00:00:00 GMT</pubDate>
      <description><![CDATA[PLC 是工业自动化的基石。本文提供完整学习路线 + 6 个实战项目详解（含 I/O 表和梯形图逻辑），助你从入门到独立编程。]]></description>
      <content:encoded><![CDATA[<h2 id="什么是-plc" class="heading-with-anchor">什么是 PLC<a href="#什么是-plc" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>PLC（Programmable Logic Controller，可编程逻辑控制器）是工业自动化的核心设备。简单来说，它就是一个<strong>专门为工厂设计的专用电脑</strong>。</p>
<ul>
<li>输入端接收传感器信号（按钮、温度、压力）</li>
<li>程序处理逻辑判断</li>
<li>输出端控制执行器（电机、阀门、指示灯）</li>
</ul>
<blockquote>
<p>PLC 的特点：稳定、抗干扰、24/7 运行、编程相对简单</p>
</blockquote>
<h2 id="学习路线总览" class="heading-with-anchor">学习路线总览<a href="#学习路线总览" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<pre><code>第一阶段：电气基础（2-4 周）
    ↓
第二阶段：PLC 基础编程（4-6 周）
    ↓
第三阶段：进阶功能（4-6 周）
    ↓
第四阶段：通信与 HMI（4 周）
    ↓
第五阶段：项目实战（4-8 周）
</code></pre>
<h2 id="第一阶段电气基础2-4-周" class="heading-with-anchor">第一阶段：电气基础（2-4 周）<a href="#第一阶段电气基础2-4-周" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>在碰 PLC 之前，你需要先懂基本电气知识：</p>
<h3 id="必学内容" class="heading-with-anchor">必学内容<a href="#必学内容" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>电路基础</strong>：电压、电流、电阻、欧姆定律</li>
<li><strong>直流/交流电</strong>：DC 24V（PLC 常用）vs AC 220V（动力电）</li>
<li><strong>继电器原理</strong>：线圈通电 → 触点闭合 → 控制回路</li>
<li><strong>传感器类型</strong>：
<ul>
<li>开关量：按钮、限位开关、光电开关</li>
<li>模拟量：温度传感器、压力变送器（4-20mA / 0-10V）</li>
</ul>
</li>
<li><strong>电气图纸阅读</strong>：能看懂原理图和接线图</li>
</ul>
<h3 id="推荐资源" class="heading-with-anchor">推荐资源<a href="#推荐资源" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>B 站搜索「电工基础」「电气入门」</li>
<li>买一本《电气控制与 PLC 应用技术》</li>
<li>如果有条件，去实验室摸一摸真实的继电器控制柜</li>
</ul>
<h2 id="第二阶段plc-基础编程4-6-周" class="heading-with-anchor">第二阶段：PLC 基础编程（4-6 周）<a href="#第二阶段plc-基础编程4-6-周" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="选择一个品牌入门" class="heading-with-anchor">选择一个品牌入门<a href="#选择一个品牌入门" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>| 品牌 | 市场份额 | 软件 | 推荐度 |
|------|----------|------|--------|
| <strong>西门子</strong> | 欧洲/中国主流 | TIA Portal | ★★★ 最推荐 |
| 三菱 | 日系主流 | GX Works | ★★ |
| 欧姆龙 | 日系 | CX-Programmer | ★★ |
| AB (罗克韦尔) | 美系主流 | Studio 5000 | ★ |</p>
<blockquote>
<p><strong>建议从西门子 S7-1200 开始</strong>：国内用得最多，资料最全，TIA Portal 功能强大</p>
</blockquote>
<h3 id="必学编程语言" class="heading-with-anchor">必学编程语言<a href="#必学编程语言" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p><strong>1. 梯形图（LAD）— 最重要</strong></p>
<p>梯形图是 PLC 最常用的编程语言，长得像电路图：</p>
<pre><code>|--[ ]--[/]--( )--|
  I0.0  I0.1   Q0.0

含义：当 I0.0 接通 且 I0.1 未接通时，Q0.0 输出
</code></pre>
<p>基本元素：</p>
<ul>
<li>常开触点 <code>[ ]</code>：对应输入信号</li>
<li>常闭触点 <code>[/ ]</code>：对应输入信号取反</li>
<li>线圈 <code>( )</code>：对应输出</li>
<li>定时器 <code>TON</code>：延时接通</li>
<li>计数器 <code>CTU</code>：计数</li>
</ul>
<p><strong>2. 功能块图（FBD）— 推荐学</strong></p>
<p>用逻辑框图表示，适合复杂逻辑：</p>
<pre><code>AND 门：两个输入都为 1 时输出 1
OR 门：任一输入为 1 时输出 1
NOT 门：输入取反
</code></pre>
<h2 id="第三阶段进阶功能4-6-周" class="heading-with-anchor">第三阶段：进阶功能（4-6 周）<a href="#第三阶段进阶功能4-6-周" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="定时器和计数器" class="heading-with-anchor">定时器和计数器<a href="#定时器和计数器" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>TON（接通延时）</strong>：信号接通后等 N 秒再动作</li>
<li><strong>TOF（断开延时）</strong>：信号断开后等 N 秒再复位</li>
<li><strong>CTU（加计数）</strong>：计到设定值触发</li>
<li><strong>CTD（减计数）</strong>：从设定值往下减</li>
</ul>
<h3 id="数据处理" class="heading-with-anchor">数据处理<a href="#数据处理" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>数据类型</strong>：BOOL、INT、DINT、REAL</li>
<li><strong>比较指令</strong>：大于、小于、等于</li>
<li><strong>数学运算</strong>：加减乘除、移位</li>
<li><strong>数据转换</strong>：INT ↔ REAL、BCD ↔ INT</li>
</ul>
<h3 id="模拟量处理" class="heading-with-anchor">模拟量处理<a href="#模拟量处理" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>输入</strong>：4-20mA 信号 → PLC 内部数值（0-27648）</li>
<li><strong>标定</strong>：把原始数值转换为实际物理量（如 0-100°C）</li>
<li><strong>PID 控制</strong>：温度、压力、流量的闭环控制</li>
</ul>
<blockquote>
<p>PID 是工业控制最重要的算法，一定要学</p>
</blockquote>
<h3 id="结构化编程" class="heading-with-anchor">结构化编程<a href="#结构化编程" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>FC（功能）</strong>：无状态的子程序</li>
<li><strong>FB（功能块）</strong>：有状态的子程序（带背景数据块）</li>
<li><strong>DB（数据块）</strong>：存储全局变量</li>
</ul>
<h2 id="第四阶段通信与-hmi4-周" class="heading-with-anchor">第四阶段：通信与 HMI（4 周）<a href="#第四阶段通信与-hmi4-周" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="通信协议" class="heading-with-anchor">通信协议<a href="#通信协议" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>| 协议 | 用途 | 特点 |
|------|------|------|
| <strong>Modbus RTU</strong> | PLC ↔ 变频器/仪表 | 串口，最常用 |
| <strong>Profinet</strong> | 西门子 PLC ↔ PLC | 以太网，高速 |
| <strong>OPC UA</strong> | PLC ↔ 上位机/SCADA | 标准化，跨平台 |
| <strong>MQTT</strong> | PLC ↔ 云平台 | IoT 场景 |</p>
<blockquote>
<p>先学 Modbus RTU，这是工业现场最常用的协议</p>
</blockquote>
<h3 id="hmi触摸屏" class="heading-with-anchor">HMI（触摸屏）<a href="#hmi触摸屏" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>西门子 KTP 系列</strong>：配合 TIA Portal 组态</li>
<li><strong>威纶通</strong>：性价比高，国内用得多</li>
<li>学会设计：主画面、参数设置、报警显示、趋势曲线</li>
</ul>
<hr>
<h2 id="第五阶段项目实战6-个完整例题" class="heading-with-anchor">第五阶段：项目实战（6 个完整例题）<a href="#第五阶段项目实战6-个完整例题" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<p>以下每个项目都包含 <strong>I/O 分配表</strong>、<strong>梯形图逻辑</strong>和<strong>调试要点</strong>，可以直接在 S7-PLCSIM 仿真或真实硬件上实现。</p>
<hr>
<h3 id="项目一启保停电路入门级" class="heading-with-anchor">项目一：启保停电路（入门级）<a href="#项目一启保停电路入门级" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>这是 PLC 最基础的程序，所有后续项目都建立在这个基础上。</p>
<h4 id="io-分配" class="heading-with-anchor">I/O 分配<a href="#io-分配" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<p>| 地址 | 信号 | 说明 |
|------|------|------|
| I0.0 | SB1 | 启动按钮（常开） |
| I0.1 | SB2 | 停止按钮（常闭） |
| Q0.0 | KM1 | 电机接触器 |</p>
<h4 id="梯形图逻辑" class="heading-with-anchor">梯形图逻辑<a href="#梯形图逻辑" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>Network 1：启保停电路
|--[ ]----+--[/]----( )--|
  I0.0    |  I0.1   Q0.0
  (启动)  |  (停止)  (电机)
          |
|--[ ]----+
  Q0.0
  (自锁)
</code></pre>
<h4 id="工作原理" class="heading-with-anchor">工作原理<a href="#工作原理" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<ol>
<li>按下启动按钮 I0.0 → Q0.0 得电 → 电机运转</li>
<li>Q0.0 的常开触点闭合 → 形成自锁 → 松开按钮后电机继续转</li>
<li>按下停止按钮 I0.1 → 回路断开 → Q0.0 失电 → 电机停转</li>
</ol>
<h4 id="调试要点" class="heading-with-anchor">调试要点<a href="#调试要点" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<ul>
<li>停止按钮在外部接线时接<strong>常闭</strong>（NC），这样断线时自动停机（安全）</li>
<li>程序里用常闭触点 <code>[/ ]</code> 是因为外部已经取反了</li>
<li>先在仿真里跑通，再接真实硬件</li>
</ul>
<hr>
<h3 id="项目二星三角启动工业经典" class="heading-with-anchor">项目二：星三角启动（工业经典）<a href="#项目二星三角启动工业经典" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>大功率电机（>3kW）不能直接启动，需要星三角降压启动。</p>
<h4 id="io-分配-2" class="heading-with-anchor">I/O 分配<a href="#io-分配-2" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<p>| 地址 | 信号 | 说明 |
|------|------|------|
| I0.0 | SB1 | 启动按钮 |
| I0.1 | SB2 | 停止按钮 |
| Q0.0 | KM1 | 主接触器 |
| Q0.1 | KM2 | 星形接触器 |
| Q0.2 | KM3 | 三角形接触器 |</p>
<h4 id="时序要求" class="heading-with-anchor">时序要求<a href="#时序要求" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>启动：
  按下启动 → KM1+KM2 吸合（星形运行）
  → 延时 6 秒 → KM2 断开、KM3 吸合（切换到三角形）
  → 正常运行

停止：
  按下停止 → 全部断开
</code></pre>
<h4 id="梯形图逻辑-2" class="heading-with-anchor">梯形图逻辑<a href="#梯形图逻辑-2" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>Network 1：主接触器（启保停）
|--[ ]----+--[/]----( )--|
  I0.0    |  I0.1   Q0.0
          |
|--[ ]----+
  Q0.0

Network 2：星形接触器（启动后立即吸合，延时后断开）
|--[ ]--[/]----------( )--|
  Q0.0  T1.Q         Q0.1
 (主接触器) (定时器到) (星形)

Network 3：三角形接触器（延时后吸合）
|--[ ]--[ ]----------( )--|
  Q0.0  T1.Q         Q0.2
 (主接触器)(定时器到)(三角形)

Network 4：启动定时器
|--[ ]--------------(TON)--
  Q0.0               T1
 (主接触器)       PT:=6s
</code></pre>
<h4 id="调试要点-2" class="heading-with-anchor">调试要点<a href="#调试要点-2" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<ul>
<li>KM2（星形）和 KM3（三角形）<strong>绝对不能同时吸合</strong>，会短路！</li>
<li>程序里做了互锁：Q0.1 和 Q0.2 互相用对方的常闭触点串联</li>
<li>延时时间根据电机功率调整，一般 5-10 秒</li>
</ul>
<hr>
<h3 id="项目三交通灯控制顺序控制入门" class="heading-with-anchor">项目三：交通灯控制（顺序控制入门）<a href="#项目三交通灯控制顺序控制入门" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>经典的顺序控制项目，练习定时器串联和状态切换。</p>
<h4 id="io-分配-3" class="heading-with-anchor">I/O 分配<a href="#io-分配-3" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<p>| 地址 | 信号 | 说明 |
|------|------|------|
| I0.0 | SW1 | 启动开关 |
| Q0.0 | HL1 | 南北红灯 |
| Q0.1 | HL2 | 南北绿灯 |
| Q0.2 | HL3 | 南北黄灯 |
| Q0.3 | HL4 | 东西红灯 |
| Q0.4 | HL5 | 东西绿灯 |
| Q0.5 | HL6 | 东西黄灯 |</p>
<h4 id="时序设计" class="heading-with-anchor">时序设计<a href="#时序设计" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>状态 1（25s）：南北绿灯亮，东西红灯亮
状态 2（3s） ：南北黄灯亮，东西红灯亮
状态 3（25s）：东西绿灯亮，南北红灯亮
状态 4（3s） ：东西黄灯亮，南北红灯亮
→ 循环回到状态 1
</code></pre>
<h4 id="梯形图逻辑简化版" class="heading-with-anchor">梯形图逻辑（简化版）<a href="#梯形图逻辑简化版" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>Network 1：状态计数器（每完成一个状态，计数+1）
|--[ ]--[CTU]--
  I0.0   C1
         PV:=4

Network 2：状态 1 — 南北绿 + 东西红（C1=1）
|--[ ]--[ ]----( )--|    |--[ ]--[ ]----( )--|
  I0.0  C1=1   Q0.1|    |  I0.0  C1=1   Q0.3|
  (开关)(状态1)(绿灯)|    |  (开关)(状态1)(红灯)|

Network 3：状态 2 — 南北黄 + 东西红（C1=2）
|--[ ]--[ ]----( )--|    |--[ ]--[ ]----( )--|
  I0.0  C1=2   Q0.2|    |  I0.0  C1=2   Q0.3|

Network 4：状态 3 — 东西绿 + 南北红（C1=3）
|--[ ]--[ ]----( )--|    |--[ ]--[ ]----( )--|
  I0.0  C1=3   Q0.4|    |  I0.0  C1=3   Q0.0|

Network 5：状态 4 — 东西黄 + 南北红（C1=4）
|--[ ]--[ ]----( )--|    |--[ ]--[ ]----( )--|
  I0.0  C1=4   Q0.5|    |  I0.0  C1=4   Q0.0|

Network 6：定时器（每个状态持续指定时间后切换）
|--[TON]--
  T1
  PT:=25s (状态1和3)
  / PT:=3s (状态2和4)
</code></pre>
<h4 id="调试要点-3" class="heading-with-anchor">调试要点<a href="#调试要点-3" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<ul>
<li>用**步进顺序控制（SFC）**思路：每个状态是一个"步"</li>
<li>实际工程中会用状态字（MW）来管理当前步骤</li>
<li>黄灯闪烁可以用 1Hz 的时钟脉冲实现</li>
</ul>
<hr>
<h3 id="项目四自动送料传送带传感器应用" class="heading-with-anchor">项目四：自动送料传送带（传感器应用）<a href="#项目四自动送料传送带传感器应用" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>模拟工厂产线上的自动送料系统，练习传感器和顺序控制。</p>
<h4 id="io-分配-4" class="heading-with-anchor">I/O 分配<a href="#io-分配-4" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<p>| 地址 | 信号 | 说明 |
|------|------|------|
| I0.0 | SB1 | 启动按钮 |
| I0.1 | SB2 | 停止按钮 |
| I0.2 | SQ1 | 入料口光电传感器 |
| I0.3 | SQ2 | 出料口光电传感器 |
| I0.4 | FR | 电机热继电器（常闭） |
| Q0.0 | M1 | 传送带电机 |
| Q0.1 | YV1 | 入料气缸电磁阀 |
| Q0.2 | HL1 | 运行指示灯 |
| Q0.3 | HL2 | 故障报警灯 |</p>
<h4 id="工作流程" class="heading-with-anchor">工作流程<a href="#工作流程" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>启动 → 传送带运转 → 入料口检测到物料 → 气缸推出推料
→ 物料到达出料口 → 传送带暂停 2 秒（等待取料）
→ 继续运转 → 循环

异常：
- 热继电器动作 → 停机 + 报警灯
- 物料在传送带超过 30 秒未到达 → 报警
</code></pre>
<h4 id="梯形图逻辑-3" class="heading-with-anchor">梯形图逻辑<a href="#梯形图逻辑-3" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>Network 1：传送带启保停（带热继电器保护）
|--[ ]----+--[/]--[/]----( )--|
  I0.0    |  I0.1  I0.4   Q0.0
  (启动)  |  (停止)(热保)  (电机)
          |
|--[ ]----+
  Q0.0
  (自锁)

Network 2：入料气缸（入料口检测到物料后推出，2秒后缩回）
|--[ ]--[TON]---------( )--|
  I0.2   T1            Q0.1
 (传感器) PT:=2s       (气缸)

Network 3：出料口暂停（检测到物料后暂停 2 秒）
|--[ ]--[ ]--[/]-------(R)--
  Q0.0  I0.3 T2         Q0.0
 (运行)(出料)(定时器)   (复位电机)

|--[ ]----------------[TON]--
  I0.3                 T2
 (出料传感器)          PT:=2s

Network 4：运行指示灯
|--[ ]----------------( )--
  Q0.0                 Q0.2
 (电机运行)           (运行灯)

Network 5：故障报警（热继电器动作时报警）
|--[/]----------------( )--
  I0.4                 Q0.3
 (热继电器)           (报警灯)
</code></pre>
<h4 id="调试要点-4" class="heading-with-anchor">调试要点<a href="#调试要点-4" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<ul>
<li>热继电器（I0.4）外部接常闭，所以程序里用常闭触点——正常时为 1，过载时为 0</li>
<li>气缸电磁阀一般需要加<strong>节流阀</strong>调节速度</li>
<li>出料口暂停可以用定时器或直接用传感器信号控制</li>
</ul>
<hr>
<h3 id="项目五恒压供水系统pid-控制" class="heading-with-anchor">项目五：恒压供水系统（PID 控制）<a href="#项目五恒压供水系统pid-控制" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>工业中最常见的 PID 应用场景，练习模拟量和闭环控制。</p>
<h4 id="io-分配-5" class="heading-with-anchor">I/O 分配<a href="#io-分配-5" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<p>| 地址 | 信号 | 类型 | 说明 |
|------|------|------|------|
| I0.0 | SB1 | 开关量 | 启动按钮 |
| I0.1 | SB2 | 开关量 | 停止按钮 |
| IW64 | PT1 | 模拟量 | 压力传感器（4-20mA） |
| Q0.0 | KM1 | 开关量 | 变频器运行信号 |
| QW80 | AO1 | 模拟量 | 变频器频率给定（4-20mA） |</p>
<h4 id="控制原理" class="heading-with-anchor">控制原理<a href="#控制原理" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>设定压力（如 0.4MPa）
    ↓
PID 控制器 ← 实际压力（压力传感器反馈）
    ↓
输出频率 → 变频器 → 水泵电机
    ↓
管网压力变化 → 压力传感器 → 反馈回 PID
</code></pre>
<h4 id="模拟量标定" class="heading-with-anchor">模拟量标定<a href="#模拟量标定" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>压力传感器量程：0-1.0 MPa
输出信号：4-20mA
PLC 内部值：0-27648

标定公式：
实际压力 = (PLC原始值 - 0) × 1.0 / 27648

变频器频率给定：
PLC输出值 = 目标频率 × 27648 / 50Hz
</code></pre>
<h4 id="梯形图逻辑scl-语言更适合-pid" class="heading-with-anchor">梯形图逻辑（SCL 语言更适合 PID）<a href="#梯形图逻辑scl-语言更适合-pid" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>// 模拟量标定
#Pressure_RAW := IW64;  // 读取原始值
#Pressure_REAL := INT_TO_REAL(#Pressure_RAW) / 27648.0 * 1.0;
// 结果：0.0 ~ 1.0 MPa

// PID 控制器（使用 TIA Portal 内置 PID_Compact）
"PID_Compact_1"(
    Setpoint := 0.4,           // 设定压力 0.4MPa
    Input := #Pressure_REAL,   // 实际压力
    Output => #Output_REAL     // 输出 0.0 ~ 1.0
);

// 输出标定 → 变频器
#Freq_output := REAL_TO_INT(#Output_REAL * 27648.0);
QW80 := #Freq_output;
</code></pre>
<h4 id="pid-调参口诀" class="heading-with-anchor">PID 调参口诀<a href="#pid-调参口诀" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>先比例（P）：从小到大，直到系统有响应但不振荡
再积分（I）：消除稳态误差，从小到大
后微分（D）：减少超调，一般设为积分时间的 1/4

经验值（供水系统）：
P = 2.0 ~ 5.0
I = 5s ~ 15s
D = 1s ~ 3s
</code></pre>
<h4 id="调试要点-5" class="heading-with-anchor">调试要点<a href="#调试要点-5" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<ul>
<li>先用手动模式验证模拟量读取是否正确</li>
<li>PID 参数需要现场整定，不同管道系统参数不同</li>
<li>加上下限幅：输出不能超过变频器最大频率</li>
</ul>
<hr>
<h3 id="项目六多工位旋转钻床综合项目" class="heading-with-anchor">项目六：多工位旋转钻床（综合项目）<a href="#项目六多工位旋转钻床综合项目" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<p>综合项目：顺序控制 + 定时器 + 计数器 + 传感器 + 报警。</p>
<h4 id="io-分配-6" class="heading-with-anchor">I/O 分配<a href="#io-分配-6" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<p>| 地址 | 信号 | 说明 |
|------|------|------|
| I0.0 | SB1 | 启动按钮 |
| I0.1 | SB2 | 停止按钮 |
| I0.2 | SQ1 | 工位 1 到位传感器 |
| I0.3 | SQ2 | 工位 2 到位传感器 |
| I0.4 | SQ3 | 工位 3 到位传感器 |
| I0.5 | SQ4 | 钻头下限位 |
| I0.6 | SQ5 | 钻头上限位 |
| I0.7 | FR | 热继电器 |
| Q0.0 | M1 | 转盘电机 |
| Q0.1 | YV1 | 钻头下降电磁阀 |
| Q0.2 | YV2 | 钻头上升电磁阀 |
| Q0.3 | M2 | 钻头旋转电机 |
| Q0.4 | HL1 | 运行灯 |
| Q0.5 | HL2 | 故障灯 |
| Q0.6 | HL3 | 计数完成灯 |</p>
<h4 id="工作流程-2" class="heading-with-anchor">工作流程<a href="#工作流程-2" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>启动 → 转盘旋转 → 工位 1 到位 → 停止旋转
→ 钻头下降 + 旋转 → 到达下限位 → 钻头上升 → 到达上限位
→ 转盘继续旋转 → 工位 2 到位 → 重复钻孔
→ 工位 3 到位 → 重复钻孔
→ 计数 +1 → 判断是否完成指定数量
→ 完成 → 停机 + 完成灯亮
→ 未完成 → 继续循环
</code></pre>
<h4 id="梯形图逻辑核心部分" class="heading-with-anchor">梯形图逻辑（核心部分）<a href="#梯形图逻辑核心部分" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<pre><code>Network 1：系统启保停
|--[ ]----+--[/]--[/]----( )--|
  I0.0    |  I0.1  I0.7   M0.0
  (启动)  |  (停止)(热保)  (系统运行)
          |
|--[ ]----+
  M0.0

Network 2：转盘旋转（系统运行 + 钻头在上限位 + 未到位时旋转）
|--[ ]--[/]--[ ]----( )--|
  M0.0 I0.2  I0.6   Q0.0
 (运行)(未到位)(上限位)(转盘)

Network 3：工位到位 → 停止转盘，启动钻孔
|--[ ]--[ ]--[/]----(S)--
  M0.0 I0.2  I0.5    M0.1
 (运行)(到位)(下限位)(钻孔中)

Network 4：钻孔中 → 钻头下降 + 旋转
|--[ ]----------------( )--|
  M0.1                  Q0.1
 (钻孔中)              (下降阀)

|--[ ]----------------( )--|
  M0.1                  Q0.3
 (钻孔中)              (钻头电机)

Network 5：到达下限位 → 钻头上升
|--[ ]--[ ]----(R)----(S)--
  M0.1 I0.5    M0.1    M0.2
 (钻孔)(下限位)(停止钻孔)(上升中)

Network 6：上升中 → 上升阀
|--[ ]----------------( )--|
  M0.2                  Q0.2
 (上升中)              (上升阀)

Network 7：到达上限位 → 完成一次钻孔，计数
|--[ ]--[ ]----(R)----(CU)--
  M0.2 I0.6    M0.2    C1
 (上升)(上限位)(停止上升)(计数)
                      PV:=100

Network 8：完成计数 → 停机 + 完成灯
|--[ ]----------------( )--|
  C1.Q                  Q0.6
 (计数到)              (完成灯)

Network 9：运行指示灯
|--[ ]--[ ]--[/]-------( )--|
  M0.0  Q0.0 C1.Q      Q0.4
 (系统)(转盘)(未完成)  (运行灯)

Network 10：故障报警
|--[/]-----------------( )--|
  I0.7                   Q0.5
 (热继电器)             (故障灯)
</code></pre>
<h4 id="调试要点-6" class="heading-with-anchor">调试要点<a href="#调试要点-6" class="heading-anchor" aria-label="Link to this section">#</a></h4>
<ul>
<li><strong>先分步调试</strong>：单独测试转盘旋转、单独测试钻孔动作</li>
<li><strong>安全互锁</strong>：钻头下降时转盘不能旋转，转盘旋转时钻头不能下降</li>
<li><strong>到位传感器</strong>：使用接近开关或光电开关，安装位置要精确</li>
<li><strong>计数器复位</strong>：完成后需要手动或自动复位计数器才能重新开始</li>
</ul>
<hr>
<h2 id="学以致用" class="heading-with-anchor">学以致用<a href="#学以致用" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="仿真练习" class="heading-with-anchor">仿真练习<a href="#仿真练习" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>S7-PLCSIM</strong>：西门子官方仿真，不用买硬件就能跑程序</li>
<li><strong>S7-PLCSIM Advanced</strong>：支持更多高级功能</li>
</ul>
<h3 id="真实硬件" class="heading-with-anchor">真实硬件<a href="#真实硬件" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>淘宝买 <strong>S7-1200 CPU 1214C</strong> + 电源 + 导轨，几百块就能搭实验台</li>
<li>配合按钮盒、指示灯、小型电机，可以跑通大部分项目</li>
</ul>
<h3 id="进阶方向" class="heading-with-anchor">进阶方向<a href="#进阶方向" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li><strong>接私活</strong>：猪八戒、一品威客，接小项目练手</li>
<li><strong>考证书</strong>：电工证、西门子认证工程师</li>
<li><strong>学 SCADA</strong>：WinCC、组态王，做上位机监控系统</li>
</ul>
<h2 id="学习资源推荐" class="heading-with-anchor">学习资源推荐<a href="#学习资源推荐" class="heading-anchor" aria-label="Link to this section">#</a></h2>
<h3 id="视频" class="heading-with-anchor">视频<a href="#视频" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>B 站：技成培训、工控帮、PLC 技术应用</li>
<li>YouTube：RealPars（英文，动画讲解很清晰）</li>
</ul>
<h3 id="书籍" class="heading-with-anchor">书籍<a href="#书籍" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>《西门子 S7-1200 PLC 编程及应用》</li>
<li>《PLC 控制程序精编 108 例》</li>
<li>《工业自动化通信技术》</li>
</ul>
<h3 id="社区" class="heading-with-anchor">社区<a href="#社区" class="heading-anchor" aria-label="Link to this section">#</a></h3>
<ul>
<li>工控网（gkong.com）</li>
<li>西门子技术论坛</li>
<li>知乎「PLC」话题</li>
</ul>
<hr>
<p>PLC 学习是一个「理论 + 实践」缺一不可的过程。光看书不动手永远学不会，建议尽早接触真实硬件或仿真软件。从最简单的启保停电路开始，一步步走向复杂的项目。工业自动化的需求一直在增长，掌握 PLC 技能是一条非常靠谱的职业路线。</p>]]></content:encoded>
      <category>技术</category>
      <category>PLC</category>
      <category>学习路线</category>
    </item>
  </channel>
</rss>