<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>克喵爱吃卤面</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://blog.kemiaosw.top/</id>
  <link href="https://blog.kemiaosw.top/" rel="alternate"/>
  <link href="https://blog.kemiaosw.top/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, 克喵爱吃卤面</rights>
  <subtitle>每一段旅行，都有终点。| www.kemiaosw.top</subtitle>
  <title>喵洛阁</title>
  <updated>2026-04-30T05:53:47.322Z</updated>
  <entry>
    <author>
      <name>克喵爱吃卤面</name>
    </author>
    <category term="技术教程" scheme="https://blog.kemiaosw.top/categories/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
    <category term="Hexo" scheme="https://blog.kemiaosw.top/tags/Hexo/"/>
    <category term="Stellar" scheme="https://blog.kemiaosw.top/tags/Stellar/"/>
    <category term="Toast" scheme="https://blog.kemiaosw.top/tags/Toast/"/>
    <category term="Notification" scheme="https://blog.kemiaosw.top/tags/Notification/"/>
    <category term="通知" scheme="https://blog.kemiaosw.top/tags/%E9%80%9A%E7%9F%A5/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>为博客添加了 Toast Notification 通知悬浮窗组件，可以在页面上显示优雅的通知消息。本文将详细介绍实现过程。</p><h2 id="效果预览"><a href="#效果预览" class="headerlink" title="效果预览"></a>效果预览</h2><ul><li><strong>多种类型</strong>：成功、错误、警告、信息</li><li><strong>自动消失</strong>：默认 5 秒后自动关闭</li><li><strong>进度条显示</strong>：直观显示剩余时间</li><li><strong>动画效果</strong>：平滑的滑入滑出动画</li><li><strong>明暗模式</strong>：自动适配深色&#x2F;浅色主题</li><li><strong>PJAX 兼容</strong>：页面切换时自动关闭</li></ul><h2 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h2><h3 id="1-创建样式文件"><a href="#1-创建样式文件" class="headerlink" title="1. 创建样式文件"></a>1. 创建样式文件</h3><p>创建样式文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">source/css/toast-notification.styl</span><br></pre></td></tr></table></figure><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Toast Notification 通知悬浮窗样式</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 通知容器</span></span><br><span class="line"><span class="selector-id">#toast-container</span></span><br><span class="line">  <span class="attribute">position</span>: fixed</span><br><span class="line">  <span class="attribute">top</span>: <span class="number">20px</span></span><br><span class="line">  <span class="attribute">right</span>: <span class="number">20px</span></span><br><span class="line">  <span class="attribute">z-index</span>: <span class="number">9999</span></span><br><span class="line">  <span class="attribute">display</span>: flex</span><br><span class="line">  <span class="attribute">flex-direction</span>: column</span><br><span class="line">  <span class="attribute">gap</span>: <span class="number">12px</span></span><br><span class="line">  <span class="attribute">pointer-events</span>: none</span><br><span class="line"></span><br><span class="line"><span class="comment">// 通知项</span></span><br><span class="line"><span class="selector-class">.toast-item</span></span><br><span class="line">  <span class="attribute">display</span>: flex</span><br><span class="line">  <span class="attribute">align-items</span>: center</span><br><span class="line">  <span class="attribute">gap</span>: <span class="number">12px</span></span><br><span class="line">  <span class="attribute">padding</span>: <span class="number">14px</span> <span class="number">18px</span></span><br><span class="line">  <span class="attribute">min-width</span>: <span class="number">280px</span></span><br><span class="line">  <span class="attribute">max-width</span>: <span class="number">400px</span></span><br><span class="line">  <span class="attribute">background</span>: <span class="built_in">var</span>(--card)</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="variable">$border</span>-card</span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="variable">$boxshadow</span>-card-float</span><br><span class="line">  <span class="attribute">pointer-events</span>: auto</span><br><span class="line">  <span class="attribute">transform</span>: <span class="built_in">translateX</span>(<span class="number">120%</span>)</span><br><span class="line">  <span class="attribute">opacity</span>: <span class="number">0</span></span><br><span class="line">  <span class="attribute">transition</span>: all <span class="number">0.3s</span> <span class="built_in">cubic-bezier</span>(<span class="number">0.68</span>, -<span class="number">0.55</span>, <span class="number">0.265</span>, <span class="number">1.55</span>)</span><br><span class="line">  <span class="attribute">border-left</span>: <span class="number">4px</span> solid transparent</span><br><span class="line">  </span><br><span class="line">  &amp;<span class="selector-class">.show</span></span><br><span class="line">    <span class="attribute">transform</span>: <span class="built_in">translateX</span>(<span class="number">0</span>)</span><br><span class="line">    <span class="attribute">opacity</span>: <span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 类型样式</span></span><br><span class="line"><span class="selector-class">.toast-item</span></span><br><span class="line">  &amp;<span class="selector-class">.toast-success</span></span><br><span class="line">    <span class="attribute">border-left-color</span>: <span class="number">#10b981</span></span><br><span class="line">    <span class="selector-class">.toast-icon</span></span><br><span class="line">      <span class="attribute">background</span>: <span class="built_in">rgba</span>(<span class="number">16</span>, <span class="number">185</span>, <span class="number">129</span>, <span class="number">0.1</span>)</span><br><span class="line">      <span class="attribute">color</span>: <span class="number">#10b981</span></span><br><span class="line">  </span><br><span class="line">  &amp;<span class="selector-class">.toast-error</span></span><br><span class="line">    <span class="attribute">border-left-color</span>: <span class="number">#ef4444</span></span><br><span class="line">    <span class="selector-class">.toast-icon</span></span><br><span class="line">      <span class="attribute">background</span>: <span class="built_in">rgba</span>(<span class="number">239</span>, <span class="number">68</span>, <span class="number">68</span>, <span class="number">0.1</span>)</span><br><span class="line">      <span class="attribute">color</span>: <span class="number">#ef4444</span></span><br><span class="line">  </span><br><span class="line">  &amp;<span class="selector-class">.toast-warning</span></span><br><span class="line">    <span class="attribute">border-left-color</span>: <span class="number">#f59e0b</span></span><br><span class="line">    <span class="selector-class">.toast-icon</span></span><br><span class="line">      <span class="attribute">background</span>: <span class="built_in">rgba</span>(<span class="number">245</span>, <span class="number">158</span>, <span class="number">11</span>, <span class="number">0.1</span>)</span><br><span class="line">      <span class="attribute">color</span>: <span class="number">#f59e0b</span></span><br><span class="line">  </span><br><span class="line">  &amp;<span class="selector-class">.toast-info</span></span><br><span class="line">    <span class="attribute">border-left-color</span>: <span class="number">#3b82f6</span></span><br><span class="line">    <span class="selector-class">.toast-icon</span></span><br><span class="line">      <span class="attribute">background</span>: <span class="built_in">rgba</span>(<span class="number">59</span>, <span class="number">130</span>, <span class="number">246</span>, <span class="number">0.1</span>)</span><br><span class="line">      <span class="attribute">color</span>: <span class="number">#3b82f6</span></span><br></pre></td></tr></table></figure><h3 id="2-创建交互脚本"><a href="#2-创建交互脚本" class="headerlink" title="2. 创建交互脚本"></a>2. 创建交互脚本</h3><p>创建脚本文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">source/js/toast-notification.js</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">  <span class="string">&quot;use strict&quot;</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="variable constant_">CONFIG</span> = &#123;</span><br><span class="line">    <span class="attr">duration</span>: <span class="number">5000</span>,</span><br><span class="line">    <span class="attr">maxCount</span>: <span class="number">5</span>,</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="variable constant_">ICONS</span> = &#123;</span><br><span class="line">    <span class="attr">success</span>: <span class="string">&#x27;&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z&quot;/&gt;&lt;/svg&gt;&#x27;</span>,</span><br><span class="line">    <span class="attr">error</span>: <span class="string">&#x27;&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z&quot;/&gt;&lt;/svg&gt;&#x27;</span>,</span><br><span class="line">    <span class="attr">warning</span>: <span class="string">&#x27;&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z&quot;/&gt;&lt;/svg&gt;&#x27;</span>,</span><br><span class="line">    <span class="attr">info</span>: <span class="string">&#x27;&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z&quot;/&gt;&lt;/svg&gt;&#x27;</span>,</span><br><span class="line">    <span class="attr">close</span>: <span class="string">&#x27;&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z&quot;/&gt;&lt;/svg&gt;&#x27;</span>,</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> toastContainer = <span class="literal">null</span>;</span><br><span class="line">  <span class="keyword">const</span> activeToasts = <span class="keyword">new</span> <span class="title class_">Map</span>();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">getContainer</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!toastContainer) &#123;</span><br><span class="line">      toastContainer = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&quot;div&quot;</span>);</span><br><span class="line">      toastContainer.<span class="property">id</span> = <span class="string">&quot;toast-container&quot;</span>;</span><br><span class="line">      <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(toastContainer);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> toastContainer;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">show</span>(<span class="params">options</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> config = &#123;</span><br><span class="line">      <span class="attr">type</span>: <span class="string">&quot;info&quot;</span>,</span><br><span class="line">      <span class="attr">title</span>: <span class="string">&quot;&quot;</span>,</span><br><span class="line">      <span class="attr">message</span>: <span class="string">&quot;&quot;</span>,</span><br><span class="line">      <span class="attr">duration</span>: <span class="variable constant_">CONFIG</span>.<span class="property">duration</span>,</span><br><span class="line">      ...options,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 创建通知元素...</span></span><br><span class="line">    <span class="comment">// 详细代码见完整文件</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 快捷方法</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">success</span>(<span class="params">message, title, options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">show</span>(&#123; <span class="attr">type</span>: <span class="string">&quot;success&quot;</span>, message, title, ...options &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">error</span>(<span class="params">message, title, options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">show</span>(&#123; <span class="attr">type</span>: <span class="string">&quot;error&quot;</span>, message, title, ...options &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">warning</span>(<span class="params">message, title, options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">show</span>(&#123; <span class="attr">type</span>: <span class="string">&quot;warning&quot;</span>, message, title, ...options &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">info</span>(<span class="params">message, title, options = &#123;&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">show</span>(&#123; <span class="attr">type</span>: <span class="string">&quot;info&quot;</span>, message, title, ...options &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 暴露全局 API</span></span><br><span class="line">  <span class="variable language_">window</span>.<span class="property">Toast</span> = &#123;</span><br><span class="line">    show,</span><br><span class="line">    success,</span><br><span class="line">    error,</span><br><span class="line">    warning,</span><br><span class="line">    info,</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure><h3 id="3-全局加载资源"><a href="#3-全局加载资源" class="headerlink" title="3. 全局加载资源"></a>3. 全局加载资源</h3><p>在 <code>_config.stellar.yml</code> 中添加：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">inject:</span></span><br><span class="line">  <span class="attr">head:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">&#x27;&lt;link rel=&quot;stylesheet&quot; href=&quot;/css/toast-notification.css&quot; type=&quot;text/css&quot;&gt;&#x27;</span></span><br><span class="line">  <span class="attr">script:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">&#x27;&lt;script defer src=&quot;/js/toast-notification.js&quot;&gt;&lt;/script&gt;&#x27;</span></span><br></pre></td></tr></table></figure><h2 id="在线演示"><a href="#在线演示" class="headerlink" title="在线演示"></a>在线演示</h2><p>点击下面的按钮查看通知效果：</p><h3 id="基础类型"><a href="#基础类型" class="headerlink" title="基础类型"></a>基础类型</h3><div class="toast-demo" style="margin: 20px 0; padding: 20px; background: var(--block); border-radius: 12px; text-align: center;">  <button onclick="Toast.success('操作成功！', '成功')" style="margin: 8px; padding: 10px 20px; background: #10b981; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">成功通知</button>  <button onclick="Toast.error('操作失败，请重试。', '错误')" style="margin: 8px; padding: 10px 20px; background: #ef4444; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">错误通知</button>  <button onclick="Toast.warning('请注意，此操作不可撤销。', '警告')" style="margin: 8px; padding: 10px 20px; background: #f59e0b; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">警告通知</button>  <button onclick="Toast.info('这是一条提示信息。', '信息')" style="margin: 8px; padding: 10px 20px; background: #3b82f6; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">信息通知</button>  <button onclick="Toast.closeAll()" style="margin: 8px; padding: 10px 20px; background: var(--text-p3); color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">关闭所有</button></div><h3 id="自定义位置"><a href="#自定义位置" class="headerlink" title="自定义位置"></a>自定义位置</h3><div class="toast-demo" style="margin: 20px 0; padding: 20px; background: var(--block); border-radius: 12px; text-align: center;">  <button onclick="Toast.info('左上角通知', '位置演示', {position: 'top-left'})" style="margin: 8px; padding: 10px 20px; background: #8b5cf6; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">左上角</button>  <button onclick="Toast.info('右上角通知', '位置演示', {position: 'top-right'})" style="margin: 8px; padding: 10px 20px; background: #8b5cf6; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">右上角</button>  <button onclick="Toast.info('左下角通知', '位置演示', {position: 'bottom-left'})" style="margin: 8px; padding: 10px 20px; background: #8b5cf6; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">左下角</button>  <button onclick="Toast.info('右下角通知', '位置演示', {position: 'bottom-right'})" style="margin: 8px; padding: 10px 20px; background: #8b5cf6; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">右下角</button></div><h3 id="自定义按钮"><a href="#自定义按钮" class="headerlink" title="自定义按钮"></a>自定义按钮</h3><div class="toast-demo" style="margin: 20px 0; padding: 20px; background: var(--block); border-radius: 12px; text-align: center;">  <button onclick="Toast.show({type: 'info', title: '发现新版本', message: '是否立即更新到最新版本？', button: {text: '立即更新', onclick: function() { Toast.success('开始更新...', '更新'); }}})" style="margin: 8px; padding: 10px 20px; background: #06b6d4; color: white; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;">带按钮的通知</button></div><h2 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h2><h3 id="基础用法"><a href="#基础用法" class="headerlink" title="基础用法"></a>基础用法</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 显示成功通知</span></span><br><span class="line"><span class="title class_">Toast</span>.<span class="title function_">success</span>(<span class="string">&#x27;操作成功！&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 显示错误通知</span></span><br><span class="line"><span class="title class_">Toast</span>.<span class="title function_">error</span>(<span class="string">&#x27;操作失败，请重试。&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 显示警告通知</span></span><br><span class="line"><span class="title class_">Toast</span>.<span class="title function_">warning</span>(<span class="string">&#x27;请注意，此操作不可撤销。&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 显示信息通知</span></span><br><span class="line"><span class="title class_">Toast</span>.<span class="title function_">info</span>(<span class="string">&#x27;这是一条提示信息。&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="带标题的通知"><a href="#带标题的通知" class="headerlink" title="带标题的通知"></a>带标题的通知</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Toast</span>.<span class="title function_">success</span>(<span class="string">&#x27;文章发布成功！&#x27;</span>, <span class="string">&#x27;发布成功&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">duration</span>: <span class="number">3000</span>  <span class="comment">// 3秒后自动关闭</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="完整配置"><a href="#完整配置" class="headerlink" title="完整配置"></a>完整配置</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Toast</span>.<span class="title function_">show</span>(&#123;</span><br><span class="line">  <span class="attr">type</span>: <span class="string">&#x27;success&#x27;</span>,      <span class="comment">// 类型：success, error, warning, info</span></span><br><span class="line">  <span class="attr">title</span>: <span class="string">&#x27;标题&#x27;</span>,        <span class="comment">// 标题（可选）</span></span><br><span class="line">  <span class="attr">message</span>: <span class="string">&#x27;消息内容&#x27;</span>,   <span class="comment">// 消息内容</span></span><br><span class="line">  <span class="attr">duration</span>: <span class="number">5000</span>        <span class="comment">// 显示时长（毫秒），0 表示不自动关闭</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="关闭所有通知"><a href="#关闭所有通知" class="headerlink" title="关闭所有通知"></a>关闭所有通知</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Toast</span>.<span class="title function_">closeAll</span>();</span><br></pre></td></tr></table></figure><h3 id="自定义位置-1"><a href="#自定义位置-1" class="headerlink" title="自定义位置"></a>自定义位置</h3><p>支持四个位置显示：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 左上角</span></span><br><span class="line"><span class="title class_">Toast</span>.<span class="title function_">info</span>(<span class="string">&#x27;左上角通知&#x27;</span>, <span class="string">&#x27;提示&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">position</span>: <span class="string">&#x27;top-left&#x27;</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 右上角（默认）</span></span><br><span class="line"><span class="title class_">Toast</span>.<span class="title function_">info</span>(<span class="string">&#x27;右上角通知&#x27;</span>, <span class="string">&#x27;提示&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">position</span>: <span class="string">&#x27;top-right&#x27;</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 左下角</span></span><br><span class="line"><span class="title class_">Toast</span>.<span class="title function_">info</span>(<span class="string">&#x27;左下角通知&#x27;</span>, <span class="string">&#x27;提示&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">position</span>: <span class="string">&#x27;bottom-left&#x27;</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 右下角</span></span><br><span class="line"><span class="title class_">Toast</span>.<span class="title function_">info</span>(<span class="string">&#x27;右下角通知&#x27;</span>, <span class="string">&#x27;提示&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">position</span>: <span class="string">&#x27;bottom-right&#x27;</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="自定义按钮-1"><a href="#自定义按钮-1" class="headerlink" title="自定义按钮"></a>自定义按钮</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Toast</span>.<span class="title function_">show</span>(&#123;</span><br><span class="line">  <span class="attr">type</span>: <span class="string">&#x27;info&#x27;</span>,</span><br><span class="line">  <span class="attr">title</span>: <span class="string">&#x27;发现新版本&#x27;</span>,</span><br><span class="line">  <span class="attr">message</span>: <span class="string">&#x27;是否立即更新？&#x27;</span>,</span><br><span class="line">  <span class="attr">button</span>: &#123;</span><br><span class="line">    <span class="attr">text</span>: <span class="string">&#x27;立即更新&#x27;</span>,</span><br><span class="line">    <span class="attr">icon</span>: <span class="string">&#x27;&lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M12 4v12m0 0l-4-4m4 4l4-4M4 12h16&quot;/&gt;&lt;/svg&gt;&#x27;</span>,</span><br><span class="line">    <span class="attr">onclick</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;用户点击了更新按钮&#x27;</span>);</span><br><span class="line">      <span class="comment">// 执行更新操作</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="关闭回调"><a href="#关闭回调" class="headerlink" title="关闭回调"></a>关闭回调</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> toast = <span class="title class_">Toast</span>.<span class="title function_">success</span>(<span class="string">&#x27;操作成功！&#x27;</span>, <span class="string">&#x27;成功&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">duration</span>: <span class="number">3000</span></span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 监听关闭事件</span></span><br><span class="line">toast.<span class="property">onClose</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;通知已关闭&#x27;</span>);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 手动关闭</span></span><br><span class="line">toast.<span class="title function_">close</span>();</span><br></pre></td></tr></table></figure><h3 id="鼠标悬停暂停"><a href="#鼠标悬停暂停" class="headerlink" title="鼠标悬停暂停"></a>鼠标悬停暂停</h3><p>当鼠标悬停在通知上时，自动关闭计时器会暂停，移开后继续计时：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Toast</span>.<span class="title function_">info</span>(<span class="string">&#x27;这条通知会在鼠标悬停时暂停计时&#x27;</span>, <span class="string">&#x27;提示&#x27;</span>, &#123;</span><br><span class="line">  <span class="attr">duration</span>: <span class="number">10000</span>  <span class="comment">// 10秒</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="适配特性"><a href="#适配特性" class="headerlink" title="适配特性"></a>适配特性</h2><ul><li><strong>明暗模式</strong>：自动适配深色&#x2F;浅色主题</li><li><strong>多端响应</strong>：桌面端右上角显示，移动端全宽顶部显示</li><li><strong>PJAX 兼容</strong>：页面切换时自动关闭所有通知</li><li><strong>最大数量限制</strong>：最多同时显示 5 条通知</li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过自定义 Toast Notification 组件，我们为 Hexo Stellar 主题添加了优雅的通知功能。这个实现不依赖第三方库，轻量且易于定制。</p>]]>
    </content>
    <id>https://blog.kemiaosw.top/posts/794688f8</id>
    <link href="https://blog.kemiaosw.top/posts/794688f8"/>
    <published>2026-04-29T07:00:00.000Z</published>
    <summary>为 Hexo Stellar 主题添加轻量级通知悬浮窗组件，支持成功、错误、警告、信息等多种类型。</summary>
    <title>Hexo Stellar 添加 Toast Notification 通知悬浮窗</title>
    <updated>2026-04-30T05:53:47.322Z</updated>
  </entry>
  <entry>
    <author>
      <name>克喵爱吃卤面</name>
    </author>
    <category term="技术教程" scheme="https://blog.kemiaosw.top/categories/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
    <category term="Hexo" scheme="https://blog.kemiaosw.top/tags/Hexo/"/>
    <category term="Stellar" scheme="https://blog.kemiaosw.top/tags/Stellar/"/>
    <category term="轮播" scheme="https://blog.kemiaosw.top/tags/%E8%BD%AE%E6%92%AD/"/>
    <category term="Swiper" scheme="https://blog.kemiaosw.top/tags/Swiper/"/>
    <content>
      <![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>最近为博客添加了 Swiper Bar 轮播组件，可以在首页顶部展示置顶文章或最新文章。本文将详细介绍实现过程。</p><h2 id="效果预览"><a href="#效果预览" class="headerlink" title="效果预览"></a>效果预览</h2><ul><li><strong>自动轮播</strong>：5 秒自动切换</li><li><strong>置顶文章</strong>：支持设置置顶文章优先展示</li><li><strong>触摸滑动</strong>：移动端支持手势滑动</li><li><strong>明暗模式</strong>：自动适配深色&#x2F;浅色主题</li><li><strong>PJAX 兼容</strong>：导航后自动重新初始化</li></ul><h2 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h2><h3 id="1-创建样式文件"><a href="#1-创建样式文件" class="headerlink" title="1. 创建样式文件"></a>1. 创建样式文件</h3><p>创建样式文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">source/css/swiper-bar.styl</span><br></pre></td></tr></table></figure><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Swiper Bar 轮播组件样式 - 适配 Stellar 主题</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 轮播容器</span></span><br><span class="line"><span class="selector-class">.swiper-bar-container</span></span><br><span class="line">  <span class="attribute">width</span>: <span class="number">100%</span></span><br><span class="line">  <span class="attribute">margin</span>: <span class="number">1rem</span> <span class="number">0</span></span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="variable">$border</span>-card-l</span><br><span class="line">  <span class="attribute">overflow</span>: hidden</span><br><span class="line">  <span class="attribute">background</span>: <span class="built_in">var</span>(--card)</span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="variable">$boxshadow</span>-card</span><br><span class="line">  <span class="built_in">hoverable-card</span>()</span><br><span class="line">  <span class="attribute">z-index</span>: <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Swiper 主体</span></span><br><span class="line"><span class="selector-class">.blog-slider</span></span><br><span class="line">  <span class="attribute">width</span>: <span class="number">100%</span></span><br><span class="line">  <span class="attribute">position</span>: relative</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="variable">$border</span>-card</span><br><span class="line">  <span class="attribute">overflow</span>: hidden</span><br><span class="line"></span><br><span class="line"><span class="comment">// 轮播项</span></span><br><span class="line"><span class="selector-class">.blog-slider__item</span></span><br><span class="line">  <span class="attribute">display</span>: flex</span><br><span class="line">  <span class="attribute">align-items</span>: center</span><br><span class="line">  <span class="attribute">padding</span>: <span class="number">20px</span></span><br><span class="line">  <span class="attribute">gap</span>: <span class="number">20px</span></span><br><span class="line">  <span class="attribute">background</span>: <span class="built_in">var</span>(--block)</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">@media</span> screen <span class="keyword">and</span> (<span class="attribute">max-width</span>: <span class="number">768px</span>)</span><br><span class="line">    flex-direction: column</span><br><span class="line">    padding: <span class="number">16px</span></span><br><span class="line">    gap: <span class="number">16px</span></span><br><span class="line"></span><br><span class="line">// 图片区域</span><br><span class="line">.blog-slider__img</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">280px</span></span><br><span class="line">  <span class="attribute">height</span>: <span class="number">180px</span></span><br><span class="line">  flex-shrink: <span class="number">0</span></span><br><span class="line">  border-radius: $border-card-s</span><br><span class="line">  overflow: hidden</span><br><span class="line">  position: relative</span><br><span class="line">  </span><br><span class="line">  img</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">100%</span></span><br><span class="line">    <span class="attribute">height</span>: <span class="number">100%</span></span><br><span class="line">    object-fit: cover</span><br><span class="line">    transition: transform <span class="number">0.3s</span> ease</span><br><span class="line">  </span><br><span class="line">  &amp;:<span class="attribute">hover</span> img</span><br><span class="line">    transform: scale(<span class="number">1.05</span>)</span><br><span class="line">  </span><br><span class="line">  @media screen <span class="keyword">and</span> (<span class="attribute">max-width</span>: <span class="number">768px</span>)</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">100%</span></span><br><span class="line">    <span class="attribute">height</span>: <span class="number">200px</span></span><br><span class="line">  </span><br><span class="line">  @media screen <span class="keyword">and</span> (<span class="attribute">max-width</span>: <span class="number">480px</span>)</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">160px</span></span><br></pre></td></tr></table></figure><h3 id="2-创建交互脚本"><a href="#2-创建交互脚本" class="headerlink" title="2. 创建交互脚本"></a>2. 创建交互脚本</h3><p>创建脚本文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">source/js/swiper-bar.js</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br></pre></td><td class="code"><pre><span class="line">(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">  <span class="string">&quot;use strict&quot;</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="variable constant_">CONFIG</span> = &#123;</span><br><span class="line">    <span class="attr">selector</span>: <span class="string">&quot;.blog-slider&quot;</span>,</span><br><span class="line">    <span class="attr">autoplayDelay</span>: <span class="number">5000</span>,</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> swiperInstance = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">initSwiper</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> container = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="variable constant_">CONFIG</span>.<span class="property">selector</span>);</span><br><span class="line">    <span class="keyword">if</span> (!container) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (swiperInstance) &#123;</span><br><span class="line">      swiperInstance.<span class="title function_">destroy</span>();</span><br><span class="line">      swiperInstance = <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> slides = container.<span class="title function_">querySelectorAll</span>(<span class="string">&quot;.blog-slider__item&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (slides.<span class="property">length</span> === <span class="number">0</span>) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> currentIndex = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">let</span> autoplayTimer = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">showSlide</span>(<span class="params">index</span>) &#123;</span><br><span class="line">      slides.<span class="title function_">forEach</span>(<span class="function">(<span class="params">slide, i</span>) =&gt;</span> &#123;</span><br><span class="line">        slide.<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">&quot;swiper-slide-active&quot;</span>);</span><br><span class="line">        slide.<span class="property">style</span>.<span class="property">display</span> = <span class="string">&quot;none&quot;</span>;</span><br><span class="line">        <span class="keyword">if</span> (i === index) &#123;</span><br><span class="line">          slide.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&quot;swiper-slide-active&quot;</span>);</span><br><span class="line">          slide.<span class="property">style</span>.<span class="property">display</span> = <span class="string">&quot;flex&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;);</span><br><span class="line">      <span class="title function_">updatePagination</span>(index);</span><br><span class="line">      currentIndex = index;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">updatePagination</span>(<span class="params">activeIndex</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> bullets = container.<span class="title function_">querySelectorAll</span>(<span class="string">&quot;.swiper-pagination-bullet&quot;</span>);</span><br><span class="line">      bullets.<span class="title function_">forEach</span>(<span class="function">(<span class="params">bullet, i</span>) =&gt;</span> &#123;</span><br><span class="line">        bullet.<span class="property">classList</span>.<span class="title function_">toggle</span>(<span class="string">&quot;swiper-pagination-bullet-active&quot;</span>, i === activeIndex);</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">nextSlide</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> next = (currentIndex + <span class="number">1</span>) % slides.<span class="property">length</span>;</span><br><span class="line">      <span class="title function_">showSlide</span>(next);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">prevSlide</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> prev = (currentIndex - <span class="number">1</span> + slides.<span class="property">length</span>) % slides.<span class="property">length</span>;</span><br><span class="line">      <span class="title function_">showSlide</span>(prev);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">startAutoplay</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="title function_">stopAutoplay</span>();</span><br><span class="line">      autoplayTimer = <span class="built_in">setInterval</span>(nextSlide, <span class="variable constant_">CONFIG</span>.<span class="property">autoplayDelay</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">stopAutoplay</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (autoplayTimer) &#123;</span><br><span class="line">        <span class="built_in">clearInterval</span>(autoplayTimer);</span><br><span class="line">        autoplayTimer = <span class="literal">null</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 绑定事件</span></span><br><span class="line">    <span class="keyword">const</span> prevBtn = container.<span class="title function_">querySelector</span>(<span class="string">&quot;.blog-slider__button--prev&quot;</span>);</span><br><span class="line">    <span class="keyword">const</span> nextBtn = container.<span class="title function_">querySelector</span>(<span class="string">&quot;.blog-slider__button--next&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (prevBtn) &#123;</span><br><span class="line">      prevBtn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">prevSlide</span>();</span><br><span class="line">        <span class="title function_">startAutoplay</span>();</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (nextBtn) &#123;</span><br><span class="line">      nextBtn.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">nextSlide</span>();</span><br><span class="line">        <span class="title function_">startAutoplay</span>();</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 分页器点击事件</span></span><br><span class="line">    <span class="keyword">const</span> bullets = container.<span class="title function_">querySelectorAll</span>(<span class="string">&quot;.swiper-pagination-bullet&quot;</span>);</span><br><span class="line">    bullets.<span class="title function_">forEach</span>(<span class="function">(<span class="params">bullet, i</span>) =&gt;</span> &#123;</span><br><span class="line">      bullet.<span class="title function_">addEventListener</span>(<span class="string">&quot;click&quot;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">showSlide</span>(i);</span><br><span class="line">        <span class="title function_">startAutoplay</span>();</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 鼠标悬停时暂停</span></span><br><span class="line">    container.<span class="title function_">addEventListener</span>(<span class="string">&quot;mouseenter&quot;</span>, stopAutoplay);</span><br><span class="line">    container.<span class="title function_">addEventListener</span>(<span class="string">&quot;mouseleave&quot;</span>, startAutoplay);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 触摸滑动支持</span></span><br><span class="line">    <span class="keyword">let</span> touchStartX = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">let</span> touchEndX = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    container.<span class="title function_">addEventListener</span>(<span class="string">&quot;touchstart&quot;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">      touchStartX = e.<span class="property">changedTouches</span>[<span class="number">0</span>].<span class="property">screenX</span>;</span><br><span class="line">      <span class="title function_">stopAutoplay</span>();</span><br><span class="line">    &#125;, &#123; <span class="attr">passive</span>: <span class="literal">true</span> &#125;);</span><br><span class="line"></span><br><span class="line">    container.<span class="title function_">addEventListener</span>(<span class="string">&quot;touchend&quot;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">      touchEndX = e.<span class="property">changedTouches</span>[<span class="number">0</span>].<span class="property">screenX</span>;</span><br><span class="line">      <span class="title function_">handleSwipe</span>();</span><br><span class="line">      <span class="title function_">startAutoplay</span>();</span><br><span class="line">    &#125;, &#123; <span class="attr">passive</span>: <span class="literal">true</span> &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">handleSwipe</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> diff = touchStartX - touchEndX;</span><br><span class="line">      <span class="keyword">if</span> (<span class="title class_">Math</span>.<span class="title function_">abs</span>(diff) &gt; <span class="number">50</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (diff &gt; <span class="number">0</span>) &#123;</span><br><span class="line">          <span class="title function_">nextSlide</span>();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          <span class="title function_">prevSlide</span>();</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">showSlide</span>(<span class="number">0</span>);</span><br><span class="line">    <span class="title function_">startAutoplay</span>();</span><br><span class="line"></span><br><span class="line">    swiperInstance = &#123;</span><br><span class="line">      <span class="attr">destroy</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="title function_">stopAutoplay</span>();</span><br><span class="line">        container.<span class="title function_">removeEventListener</span>(<span class="string">&quot;mouseenter&quot;</span>, stopAutoplay);</span><br><span class="line">        container.<span class="title function_">removeEventListener</span>(<span class="string">&quot;mouseleave&quot;</span>, startAutoplay);</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">handlePjaxComplete</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="built_in">setTimeout</span>(initSwiper, <span class="number">100</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">init</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">initSwiper</span>();</span><br><span class="line">    <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&quot;pjax:complete&quot;</span>, handlePjaxComplete);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (<span class="variable language_">document</span>.<span class="property">readyState</span> === <span class="string">&quot;loading&quot;</span>) &#123;</span><br><span class="line">    <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&quot;DOMContentLoaded&quot;</span>, init);</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="title function_">init</span>();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure><h3 id="3-创建-EJS-模板"><a href="#3-创建-EJS-模板" class="headerlink" title="3. 创建 EJS 模板"></a>3. 创建 EJS 模板</h3><p>创建模板文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">themes/stellar/layout/_partial/main/post_list/swiper_bar.ejs</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br></pre></td><td class="code"><pre><span class="line">&lt;%</span><br><span class="line">// 获取置顶文章</span><br><span class="line">let swiperPosts = [];</span><br><span class="line">site.posts.forEach(function(post) &#123;</span><br><span class="line">  if (post.swiper_index !== undefined) &#123;</span><br><span class="line">    swiperPosts.push(post);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">// 按 swiper_index 排序</span><br><span class="line">swiperPosts.sort(function(a, b) &#123;</span><br><span class="line">  return (b.swiper_index || 0) - (a.swiper_index || 0);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">// 最多显示 5 篇</span><br><span class="line">swiperPosts = swiperPosts.slice(0, 5);</span><br><span class="line"></span><br><span class="line">// 如果没有置顶文章，显示最新的 3 篇</span><br><span class="line">if (swiperPosts.length === 0) &#123;</span><br><span class="line">  site.posts.sort(&#x27;date&#x27;, -1).limit(3).forEach(function(post) &#123;</span><br><span class="line">    swiperPosts.push(post);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">if (swiperPosts.length === 0) return &#x27;&#x27;;</span><br><span class="line">%&gt;</span><br><span class="line"></span><br><span class="line">&lt;div class=&quot;swiper-bar-container&quot;&gt;</span><br><span class="line">  &lt;div class=&quot;blog-slider&quot;&gt;</span><br><span class="line">    &lt;% swiperPosts.forEach(function(post, index) &#123; %&gt;</span><br><span class="line">    &lt;div class=&quot;blog-slider__item&quot; style=&quot;&lt;%= index === 0 ? &#x27;&#x27; : &#x27;display: none;&#x27; %&gt;&quot;&gt;</span><br><span class="line">      &lt;div class=&quot;blog-slider__img&quot;&gt;</span><br><span class="line">        &lt;% </span><br><span class="line">        let coverUrl = &#x27;&#x27;;</span><br><span class="line">        if (post.swiper_cover) &#123;</span><br><span class="line">          coverUrl = post.swiper_cover;</span><br><span class="line">        &#125; else if (post.cover) &#123;</span><br><span class="line">          coverUrl = post.cover;</span><br><span class="line">        &#125; else if (post.poster &amp;&amp; post.poster.image) &#123;</span><br><span class="line">          coverUrl = post.poster.image;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">          coverUrl = &#x27;https://p.268682.xyz/pic?img=ua&#x27;;</span><br><span class="line">        &#125;</span><br><span class="line">        %&gt;</span><br><span class="line">        &lt;img src=&quot;&lt;%= coverUrl %&gt;&quot; alt=&quot;&lt;%= post.title %&gt;&quot;&gt;</span><br><span class="line">        </span><br><span class="line">        &lt;% if (post.swiper_index !== undefined) &#123; %&gt;</span><br><span class="line">        &lt;div class=&quot;blog-slider__pin&quot;&gt;</span><br><span class="line">          &lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M16 12V4H17V2H7V4H8V12L6 14V16H11.2V22H12.8V16H18V14L16 12Z&quot;/&gt;&lt;/svg&gt;</span><br><span class="line">          置顶</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">        &lt;% &#125; %&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">      </span><br><span class="line">      &lt;div class=&quot;blog-slider__content&quot;&gt;</span><br><span class="line">        &lt;h3 class=&quot;blog-slider__title&quot;&gt;</span><br><span class="line">          &lt;a href=&quot;&lt;%= url_for(post.path) %&gt;&quot;&gt;&lt;%= post.title %&gt;&lt;/a&gt;</span><br><span class="line">        &lt;/h3&gt;</span><br><span class="line">        </span><br><span class="line">        &lt;div class=&quot;blog-slider__desc&quot;&gt;</span><br><span class="line">          &lt;% if (post.swiper_desc) &#123; %&gt;</span><br><span class="line">            &lt;%= post.swiper_desc %&gt;</span><br><span class="line">          &lt;% &#125; else if (post.description) &#123; %&gt;</span><br><span class="line">            &lt;%= post.description %&gt;</span><br><span class="line">          &lt;% &#125; else if (post.excerpt) &#123; %&gt;</span><br><span class="line">            &lt;%= strip_html(post.excerpt).substring(0, 120) %&gt;...</span><br><span class="line">          &lt;% &#125; else &#123; %&gt;</span><br><span class="line">            &lt;%= strip_html(post.content).substring(0, 120) %&gt;...</span><br><span class="line">          &lt;% &#125; %&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">        </span><br><span class="line">        &lt;div class=&quot;blog-slider__meta&quot;&gt;</span><br><span class="line">          &lt;span class=&quot;meta-item&quot;&gt;</span><br><span class="line">            &lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M19 3H18V1H16V3H8V1H6V3H5C3.89 3 3 3.9 3 5V19C3 20.1 3.89 21 5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3ZM19 19H5V8H19V19Z&quot;/&gt;&lt;/svg&gt;</span><br><span class="line">            &lt;%= date(post.date, config.date_format) %&gt;</span><br><span class="line">          &lt;/span&gt;</span><br><span class="line">          </span><br><span class="line">          &lt;% if (post.categories &amp;&amp; post.categories.length &gt; 0) &#123; %&gt;</span><br><span class="line">          &lt;span class=&quot;meta-item&quot;&gt;</span><br><span class="line">            &lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M12 2L2 7L12 12L22 7L12 2Z&quot;/&gt;&lt;/svg&gt;</span><br><span class="line">            &lt;% post.categories.forEach(function(cat, i) &#123; %&gt;</span><br><span class="line">              &lt;%= i &gt; 0 ? &#x27; / &#x27; : &#x27;&#x27; %&gt;&lt;%= cat.name %&gt;</span><br><span class="line">            &lt;% &#125;); %&gt;</span><br><span class="line">          &lt;/span&gt;</span><br><span class="line">          &lt;% &#125; %&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">    &lt;% &#125;); %&gt;</span><br><span class="line">    </span><br><span class="line">    &lt;button class=&quot;blog-slider__button blog-slider__button--prev&quot;&gt;</span><br><span class="line">      &lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M15.41 7.41L14 6L8 12L14 18L15.41 16.59L10.83 12L15.41 7.41Z&quot;/&gt;&lt;/svg&gt;</span><br><span class="line">    &lt;/button&gt;</span><br><span class="line">    &lt;button class=&quot;blog-slider__button blog-slider__button--next&quot;&gt;</span><br><span class="line">      &lt;svg viewBox=&quot;0 0 24 24&quot;&gt;&lt;path d=&quot;M8.59 16.59L10 18L16 12L10 6L8.59 7.41L13.17 12L8.59 16.59Z&quot;/&gt;&lt;/svg&gt;</span><br><span class="line">    &lt;/button&gt;</span><br><span class="line">    </span><br><span class="line">    &lt;div class=&quot;blog-slider__pagination&quot;&gt;</span><br><span class="line">      &lt;% swiperPosts.forEach(function(post, index) &#123; %&gt;</span><br><span class="line">        &lt;div class=&quot;swiper-pagination-bullet &lt;%= index === 0 ? &#x27;swiper-pagination-bullet-active&#x27; : &#x27;&#x27; %&gt;&quot;&gt;&lt;/div&gt;</span><br><span class="line">      &lt;% &#125;); %&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure><h3 id="4-修改首页布局"><a href="#4-修改首页布局" class="headerlink" title="4. 修改首页布局"></a>4. 修改首页布局</h3><p>编辑 <code>themes/stellar/layout/index.ejs</code>，在文章列表前添加：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">&lt;%- partial(&#x27;_partial/main/navbar/nav_tabs_blog&#x27;) %&gt;</span><br><span class="line">&lt;%- partial(&#x27;_partial/main/post_list/swiper_bar&#x27;) %&gt;</span><br><span class="line">&lt;%- layout_post_list(function(post)&#123;</span><br><span class="line">  return partial(&#x27;_partial/main/post_list/post_card&#x27;, &#123;post: post&#125;)</span><br><span class="line">&#125;) %&gt;</span><br></pre></td></tr></table></figure><h3 id="5-全局加载资源"><a href="#5-全局加载资源" class="headerlink" title="5. 全局加载资源"></a>5. 全局加载资源</h3><p>在 <code>_config.stellar.yml</code> 中添加：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">inject:</span></span><br><span class="line">  <span class="attr">head:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">&#x27;&lt;link rel=&quot;stylesheet&quot; href=&quot;/css/swiper-bar.css&quot; type=&quot;text/css&quot;&gt;&#x27;</span></span><br><span class="line">  <span class="attr">script:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">&#x27;&lt;script defer src=&quot;/js/swiper-bar.js&quot;&gt;&lt;/script&gt;&#x27;</span></span><br></pre></td></tr></table></figure><h2 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h2><h3 id="置顶文章"><a href="#置顶文章" class="headerlink" title="置顶文章"></a>置顶文章</h3><p>在文章的 Front-matter 中添加：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">swiper_index:</span> <span class="number">10</span>      <span class="comment"># 数字越大越靠前</span></span><br><span class="line"><span class="attr">swiper_cover:</span> <span class="string">/images/cover.jpg</span>  <span class="comment"># 轮播封面图</span></span><br><span class="line"><span class="attr">swiper_desc:</span> <span class="string">文章简介描述</span>       <span class="comment"># 轮播描述</span></span><br></pre></td></tr></table></figure><h3 id="自动-fallback"><a href="#自动-fallback" class="headerlink" title="自动 fallback"></a>自动 fallback</h3><p>如果没有设置置顶文章，会自动显示最新的 3 篇文章。</p><h2 id="适配特性"><a href="#适配特性" class="headerlink" title="适配特性"></a>适配特性</h2><ul><li><strong>明暗模式</strong>：自动适配深色&#x2F;浅色主题</li><li><strong>多端响应</strong>：桌面端左右布局，移动端上下布局</li><li><strong>PJAX 兼容</strong>：导航后自动重新初始化</li><li><strong>默认封面</strong>：无封面文章使用默认图片</li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过自定义 Swiper Bar 组件，我们为 Hexo Stellar 主题添加了文章轮播功能。这个实现不依赖第三方库，轻量且易于定制。</p>]]>
    </content>
    <id>https://blog.kemiaosw.top/posts/6973b1b8</id>
    <link href="https://blog.kemiaosw.top/posts/6973b1b8"/>
    <published>2026-04-29T06:30:00.000Z</published>
    <summary>为 Hexo Stellar 主题添加文章轮播组件，支持置顶文章展示、自动轮播、触摸滑动等功能。</summary>
    <title>Hexo Stellar 添加 Swiper Bar 轮播组件</title>
    <updated>2026-04-30T05:53:47.322Z</updated>
  </entry>
  <entry>
    <author>
      <name>克喵爱吃卤面</name>
    </author>
    <category term="技术教程" scheme="https://blog.kemiaosw.top/categories/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
    <category term="Hexo" scheme="https://blog.kemiaosw.top/tags/Hexo/"/>
    <category term="Stellar" scheme="https://blog.kemiaosw.top/tags/Stellar/"/>
    <category term="TgTalk" scheme="https://blog.kemiaosw.top/tags/TgTalk/"/>
    <category term="说说" scheme="https://blog.kemiaosw.top/tags/%E8%AF%B4%E8%AF%B4/"/>
    <content>
      <![CDATA[<h1 id="Hexo-Stellar-添加-TgTalk-说说页面"><a href="#Hexo-Stellar-添加-TgTalk-说说页面" class="headerlink" title="Hexo Stellar 添加 TgTalk 说说页面"></a>Hexo Stellar 添加 TgTalk 说说页面</h1><h2 id="效果预览"><a href="#效果预览" class="headerlink" title="效果预览"></a>效果预览</h2><p>创建一个类似「即刻」的说说页面，展示来自 TgTalk 的消息：</p><ul><li>📱 <strong>实时展示</strong>：从 TgTalk API 获取最新消息</li><li>🎨 <strong>精美样式</strong>：卡片式设计，支持悬停效果</li><li>🖼️ <strong>图片展示</strong>：支持图片网格和全屏查看</li><li>⏱️ <strong>时间显示</strong>：智能时间格式化（刚刚、X 分钟前）</li><li>📊 <strong>浏览量</strong>：显示每条说说的浏览次数</li><li>💾 <strong>本地缓存</strong>：30 分钟缓存，提升加载速度</li></ul><h2 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h2><h3 id="1-创建-JavaScript-文件"><a href="#1-创建-JavaScript-文件" class="headerlink" title="1. 创建 JavaScript 文件"></a>1. 创建 JavaScript 文件</h3><p>在 <code>source/js/</code> 目录下创建 <code>talks.js</code> 文件：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * TgTalk 说说页面展示脚本</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">(<span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> <span class="variable constant_">CONFIG</span> = &#123;</span><br><span class="line">    <span class="attr">API_URL</span>: <span class="string">&#x27;https://tgtalk.kemeow.top/api/echo/page&#x27;</span>,</span><br><span class="line">    <span class="attr">CACHE_KEY</span>: <span class="string">&#x27;tgTalkCache&#x27;</span>,</span><br><span class="line">    <span class="attr">CACHE_TIME_KEY</span>: <span class="string">&#x27;tgTalkCacheTime&#x27;</span>,</span><br><span class="line">    <span class="attr">CACHE_DURATION</span>: <span class="number">30</span> * <span class="number">60</span> * <span class="number">1000</span>,</span><br><span class="line">    <span class="attr">AVATAR</span>: <span class="string">&#x27;https://ui-avatars.com/api/?name=TgTalk&amp;background=random&#x27;</span>,</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 格式化时间</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">formatTime</span>(<span class="params">timestamp</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> date = <span class="keyword">new</span> <span class="title class_">Date</span>(timestamp);</span><br><span class="line">    <span class="keyword">const</span> now = <span class="keyword">new</span> <span class="title class_">Date</span>();</span><br><span class="line">    <span class="keyword">const</span> diff = now - date;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">const</span> minute = <span class="number">60</span> * <span class="number">1000</span>;</span><br><span class="line">    <span class="keyword">const</span> hour = <span class="number">60</span> * minute;</span><br><span class="line">    <span class="keyword">const</span> day = <span class="number">24</span> * hour;</span><br><span class="line">    <span class="keyword">const</span> month = <span class="number">30</span> * day;</span><br><span class="line">    <span class="keyword">const</span> year = <span class="number">12</span> * month;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (diff &lt; minute) <span class="keyword">return</span> <span class="string">&#x27;刚刚&#x27;</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (diff &lt; hour) <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(diff / minute) + <span class="string">&#x27;分钟前&#x27;</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (diff &lt; day) <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(diff / hour) + <span class="string">&#x27;小时前&#x27;</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (diff &lt; month) <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(diff / day) + <span class="string">&#x27;天前&#x27;</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (diff &lt; year) <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(diff / month) + <span class="string">&#x27;个月前&#x27;</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(diff / year) + <span class="string">&#x27;年前&#x27;</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 渲染说说列表</span></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">renderTalks</span>(<span class="params">talks</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> talkContainer = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;#talk&#x27;</span>);</span><br><span class="line">    <span class="keyword">if</span> (!talkContainer) <span class="keyword">return</span>;</span><br><span class="line">    </span><br><span class="line">    talkContainer.<span class="property">innerHTML</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (!talks || talks.<span class="property">length</span> === <span class="number">0</span>) &#123;</span><br><span class="line">      talkContainer.<span class="property">innerHTML</span> = <span class="string">&#x27;&lt;div class=&quot;talk-empty&quot;&gt;暂无说说&lt;/div&gt;&#x27;</span>;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    talks.<span class="title function_">forEach</span>(<span class="function"><span class="params">talk</span> =&gt;</span> &#123;</span><br><span class="line">      talkContainer.<span class="property">innerHTML</span> += <span class="title function_">renderTalkItem</span>(talk);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 加载数据</span></span><br><span class="line">  <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">loadTalks</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="variable constant_">CONFIG</span>.<span class="property">API_URL</span>);</span><br><span class="line">      <span class="keyword">const</span> data = <span class="keyword">await</span> response.<span class="title function_">json</span>();</span><br><span class="line">      <span class="title function_">renderTalks</span>(data.<span class="property">ChannelMessageData</span> || []);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">error</span>(<span class="string">&#x27;加载说说失败:&#x27;</span>, error);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">loadTalks</span>();</span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure><h3 id="2-创建说说页面"><a href="#2-创建说说页面" class="headerlink" title="2. 创建说说页面"></a>2. 创建说说页面</h3><p>在 <code>source/moment/</code> 目录下编辑 <code>index.md</code>：</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">menu<span class="emphasis">_id: more</span></span><br><span class="line"><span class="emphasis">title: 即刻</span></span><br><span class="line"><span class="emphasis">layout: page</span></span><br><span class="line"><span class="emphasis">comments: false</span></span><br><span class="line"><span class="emphasis">---</span></span><br><span class="line"><span class="emphasis"></span></span><br><span class="line"><span class="emphasis"><span class="language-xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;talk&quot;</span> <span class="attr">class</span>=<span class="string">&quot;talk-container&quot;</span>&gt;</span></span><span class="language-xml"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span></span><br><span class="line"><span class="emphasis"></span></span><br><span class="line"><span class="emphasis"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;/js/talks.js&quot;</span>&gt;</span></span><span class="language-xml"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span></span><br></pre></td></tr></table></figure><h3 id="3-添加-CSS-样式"><a href="#3-添加-CSS-样式" class="headerlink" title="3. 添加 CSS 样式"></a>3. 添加 CSS 样式</h3><p>在 <code>themes/stellar/source/css/_custom.styl</code> 中添加：</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 说说页面样式 */</span></span><br><span class="line"><span class="selector-id">#talk</span></span><br><span class="line">  <span class="attribute">max-width</span>: <span class="number">900px</span></span><br><span class="line">  <span class="attribute">margin</span>: <span class="number">0</span> auto</span><br><span class="line">  <span class="attribute">padding</span>: <span class="number">20px</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="selector-class">.talk-item</span></span><br><span class="line">  <span class="attribute">display</span>: flex</span><br><span class="line">  <span class="attribute">gap</span>: <span class="number">16px</span></span><br><span class="line">  <span class="attribute">margin-bottom</span>: <span class="number">24px</span></span><br><span class="line">  <span class="attribute">padding</span>: <span class="number">20px</span></span><br><span class="line">  <span class="attribute">background</span>: <span class="built_in">var</span>(--card)</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">12px</span></span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="number">0</span> <span class="number">2px</span> <span class="number">8px</span> <span class="built_in">rgba</span>(<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0.04</span>)</span><br><span class="line">  <span class="attribute">transition</span>: all <span class="number">0.3s</span> ease</span><br><span class="line">  </span><br><span class="line">  <span class="selector-pseudo">&amp;:hover</span></span><br><span class="line">    <span class="attribute">box-shadow</span>: <span class="number">0</span> <span class="number">4px</span> <span class="number">16px</span> <span class="built_in">rgba</span>(<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0.08</span>)</span><br><span class="line">    <span class="attribute">transform</span>: <span class="built_in">translateY</span>(-<span class="number">2px</span>)</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.talk-avatar</span></span><br><span class="line">  <span class="selector-tag">img</span></span><br><span class="line">    <span class="attribute">width</span>: <span class="number">48px</span></span><br><span class="line">    <span class="attribute">height</span>: <span class="number">48px</span></span><br><span class="line">    <span class="attribute">border-radius</span>: <span class="number">50%</span></span><br><span class="line"></span><br><span class="line"><span class="selector-class">.talk-header</span></span><br><span class="line">  <span class="attribute">display</span>: flex</span><br><span class="line">  <span class="attribute">justify-content</span>: space-between</span><br><span class="line">  <span class="attribute">margin-bottom</span>: <span class="number">12px</span></span><br><span class="line"></span><br><span class="line"><span class="selector-class">.talk-author</span></span><br><span class="line">  <span class="attribute">font-weight</span>: <span class="number">600</span></span><br><span class="line"></span><br><span class="line"><span class="selector-class">.talk-time</span></span><br><span class="line">  <span class="attribute">color</span>: <span class="built_in">var</span>(--text-p4)</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.talk-images</span></span><br><span class="line">  <span class="attribute">display</span>: grid</span><br><span class="line">  <span class="attribute">grid-template-columns</span>: <span class="built_in">repeat</span>(auto-fill, <span class="built_in">minmax</span>(<span class="number">120px</span>, <span class="number">1</span>fr))</span><br><span class="line">  <span class="attribute">gap</span>: <span class="number">8px</span></span><br></pre></td></tr></table></figure><h3 id="4-重新生成博客"><a href="#4-重新生成博客" class="headerlink" title="4. 重新生成博客"></a>4. 重新生成博客</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo generate</span><br><span class="line">hexo server</span><br></pre></td></tr></table></figure><h2 id="功能说明"><a href="#功能说明" class="headerlink" title="功能说明"></a>功能说明</h2><h3 id="API-配置"><a href="#API-配置" class="headerlink" title="API 配置"></a>API 配置</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">CONFIG</span> = &#123;</span><br><span class="line">  <span class="attr">API_URL</span>: <span class="string">&#x27;https://tgtalk.kemeow.top/api/echo/page&#x27;</span>, <span class="comment">// TgTalk API</span></span><br><span class="line">  <span class="attr">CACHE_DURATION</span>: <span class="number">30</span> * <span class="number">60</span> * <span class="number">1000</span>, <span class="comment">// 缓存 30 分钟</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h3><p>TgTalk API 返回的数据格式：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;nextBefore&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;Region&quot;</span><span class="punctuation">:</span> <span class="string">&quot;HK&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;version&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2.1.7&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;ChannelMessageData&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;3&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;text&quot;</span><span class="punctuation">:</span> <span class="string">&quot;换了个号。。。&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;image&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;time&quot;</span><span class="punctuation">:</span> <span class="number">1776846917000</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;views&quot;</span><span class="punctuation">:</span> <span class="string">&quot;1&quot;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h3 id="核心功能"><a href="#核心功能" class="headerlink" title="核心功能"></a>核心功能</h3><h4 id="1-时间格式化"><a href="#1-时间格式化" class="headerlink" title="1. 时间格式化"></a>1. 时间格式化</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">formatTime</span>(<span class="params">timestamp</span>) &#123;</span><br><span class="line">  <span class="comment">// 根据时间差返回友好格式</span></span><br><span class="line">  <span class="comment">// 刚刚、X 分钟前、X 小时前、X 天前...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="2-图片处理"><a href="#2-图片处理" class="headerlink" title="2. 图片处理"></a>2. 图片处理</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">processImages</span>(<span class="params">images</span>) &#123;</span><br><span class="line">  <span class="comment">// 生成图片网格</span></span><br><span class="line">  <span class="comment">// 支持全屏查看</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="3-本地缓存"><a href="#3-本地缓存" class="headerlink" title="3. 本地缓存"></a>3. 本地缓存</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">loadFromCache</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="comment">// 从 localStorage 加载缓存</span></span><br><span class="line">  <span class="comment">// 30 分钟有效期</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">saveToCache</span>(<span class="params">data</span>) &#123;</span><br><span class="line">  <span class="comment">// 保存数据到 localStorage</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="4-瀑布流布局"><a href="#4-瀑布流布局" class="headerlink" title="4. 瀑布流布局"></a>4. 瀑布流布局</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">waterfall</span>(<span class="params">container</span>) &#123;</span><br><span class="line">  <span class="comment">// 响应式布局</span></span><br><span class="line">  <span class="comment">// 移动端单列，桌面端双列</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="自定义配置"><a href="#自定义配置" class="headerlink" title="自定义配置"></a>自定义配置</h2><h3 id="修改-API-地址"><a href="#修改-API-地址" class="headerlink" title="修改 API 地址"></a>修改 API 地址</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">CONFIG</span> = &#123;</span><br><span class="line">  <span class="attr">API_URL</span>: <span class="string">&#x27;https://your-tgtalk-domain.com/api/echo/page&#x27;</span>,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="修改头像"><a href="#修改头像" class="headerlink" title="修改头像"></a>修改头像</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">CONFIG</span> = &#123;</span><br><span class="line">  <span class="attr">AVATAR</span>: <span class="string">&#x27;https://your-avatar-url.com/avatar.jpg&#x27;</span>,</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="修改缓存时间"><a href="#修改缓存时间" class="headerlink" title="修改缓存时间"></a>修改缓存时间</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="variable constant_">CONFIG</span> = &#123;</span><br><span class="line">  <span class="attr">CACHE_DURATION</span>: <span class="number">60</span> * <span class="number">60</span> * <span class="number">1000</span>, <span class="comment">// 1 小时</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="修改作者名称"><a href="#修改作者名称" class="headerlink" title="修改作者名称"></a>修改作者名称</h3><p>在 <code>renderTalkItem</code> 函数中修改：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;span <span class="keyword">class</span>=<span class="string">&quot;talk-author&quot;</span>&gt;你的昵称&lt;/span&gt;</span><br></pre></td></tr></table></figure><h2 id="样式定制"><a href="#样式定制" class="headerlink" title="样式定制"></a>样式定制</h2><h3 id="修改卡片样式"><a href="#修改卡片样式" class="headerlink" title="修改卡片样式"></a>修改卡片样式</h3><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.talk-item</span></span><br><span class="line">  <span class="attribute">background</span>: <span class="built_in">var</span>(--card)  // 背景色</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">12px</span>       // 圆角</span><br><span class="line">  <span class="attribute">padding</span>: <span class="number">20px</span>            // 内边距</span><br></pre></td></tr></table></figure><h3 id="修改图片网格"><a href="#修改图片网格" class="headerlink" title="修改图片网格"></a>修改图片网格</h3><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.talk-images</span></span><br><span class="line">  <span class="attribute">grid-template-columns</span>: <span class="built_in">repeat</span>(auto-fill, <span class="built_in">minmax</span>(<span class="number">150px</span>, <span class="number">1</span>fr))</span><br><span class="line">  <span class="comment">// 调整图片最小宽度</span></span><br></pre></td></tr></table></figure><h3 id="修改响应式断点"><a href="#修改响应式断点" class="headerlink" title="修改响应式断点"></a>修改响应式断点</h3><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">@media</span> screen <span class="keyword">and</span> (<span class="attribute">max-width</span>: <span class="number">768px</span>)</span><br><span class="line">  // 修改移动端样式</span><br></pre></td></tr></table></figure><h2 id="高级功能"><a href="#高级功能" class="headerlink" title="高级功能"></a>高级功能</h2><h3 id="1-图片全屏查看"><a href="#1-图片全屏查看" class="headerlink" title="1. 图片全屏查看"></a>1. 图片全屏查看</h3><p>点击图片时显示全屏预览：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">viewImage</span> = <span class="keyword">function</span>(<span class="params">img</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> overlay = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;div&#x27;</span>);</span><br><span class="line">  overlay.<span class="property">className</span> = <span class="string">&#x27;talk-image-overlay&#x27;</span>;</span><br><span class="line">  overlay.<span class="property">innerHTML</span> = <span class="string">`&lt;img src=&quot;<span class="subst">$&#123;img.src&#125;</span>&quot;&gt;`</span>;</span><br><span class="line">  overlay.<span class="property">onclick</span> = <span class="function">() =&gt;</span> overlay.<span class="title function_">remove</span>();</span><br><span class="line">  <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(overlay);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="2-链接自动识别"><a href="#2-链接自动识别" class="headerlink" title="2. 链接自动识别"></a>2. 链接自动识别</h3><p>自动将文本中的 URL 转换为可点击链接：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">processLinks</span>(<span class="params">text</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> linkRegex = <span class="regexp">/(https?:\/\/[^\s]+)/g</span>;</span><br><span class="line">  <span class="keyword">return</span> text.<span class="title function_">replace</span>(linkRegex, <span class="function">(<span class="params">url</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">`&lt;a href=&quot;<span class="subst">$&#123;url&#125;</span>&quot; target=&quot;_blank&quot;&gt;<span class="subst">$&#123;url&#125;</span>&lt;/a&gt;`</span>;</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-浏览量统计"><a href="#3-浏览量统计" class="headerlink" title="3. 浏览量统计"></a>3. 浏览量统计</h3><p>显示每条说说的浏览次数：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;div <span class="keyword">class</span>=<span class="string">&quot;talk-views&quot;</span>&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">svg</span>&gt;</span>...<span class="tag">&lt;/<span class="name">svg</span>&gt;</span></span></span><br><span class="line">  $&#123;talk.<span class="property">views</span> || <span class="number">0</span>&#125;</span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure><h2 id="效果展示"><a href="#效果展示" class="headerlink" title="效果展示"></a>效果展示</h2><h3 id="桌面端"><a href="#桌面端" class="headerlink" title="桌面端"></a>桌面端</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">┌─────────────────────────────────────┐</span><br><span class="line">│ 👤 TgTalk          刚刚            │</span><br><span class="line">│                                    │</span><br><span class="line">│ 换了个号。。。                      │</span><br><span class="line">│                                    │</span><br><span class="line">│ 👁️ 1                               │</span><br><span class="line">└─────────────────────────────────────┘</span><br></pre></td></tr></table></figure><h3 id="移动端"><a href="#移动端" class="headerlink" title="移动端"></a>移动端</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">┌───────────────────┐</span><br><span class="line">│ 👤 TgTalk  刚刚  │</span><br><span class="line">│                   │</span><br><span class="line">│ 换了个号。。。    │</span><br><span class="line">│                   │</span><br><span class="line">│ 👁️ 1             │</span><br><span class="line">└───────────────────┘</span><br></pre></td></tr></table></figure><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><strong>API 可用性</strong>：确保 TgTalk API 可访问</li><li><strong>CORS 问题</strong>：如果遇到跨域问题，需要配置 CORS</li><li><strong>缓存策略</strong>：根据实际需求调整缓存时间</li><li><strong>图片加载</strong>：使用 <code>loading=&quot;lazy&quot;</code> 延迟加载</li></ol><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://tgtalk.kemeow.top/">TgTalk 项目</a></li><li><a href="https://xaoxuu.com/wiki/stellar/">Stellar 主题文档</a></li><li><a href="https://hexo.io/zh-cn/">Hexo 官方文档</a></li></ul><hr><p><strong>作者</strong>: Kemeow0815<br><strong>发布日期</strong>: 2026-04-25<br><strong>本文链接</strong>: &#x2F;moment&#x2F;</p>]]>
    </content>
    <id>https://blog.kemiaosw.top/posts/2ad1033e</id>
    <link href="https://blog.kemiaosw.top/posts/2ad1033e"/>
    <published>2026-04-25T12:00:00.000Z</published>
    <summary>为 Hexo Stellar 主题添加基于 TgTalk 的说说页面，展示 Telegram 频道消息。</summary>
    <title>Hexo Stellar 添加 TgTalk 说说页面</title>
    <updated>2026-04-30T05:53:47.322Z</updated>
  </entry>
  <entry>
    <author>
      <name>克喵爱吃卤面</name>
    </author>
    <category term="技术教程" scheme="https://blog.kemiaosw.top/categories/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
    <category term="Hexo" scheme="https://blog.kemiaosw.top/tags/Hexo/"/>
    <category term="Stellar" scheme="https://blog.kemiaosw.top/tags/Stellar/"/>
    <category term="字数统计" scheme="https://blog.kemiaosw.top/tags/%E5%AD%97%E6%95%B0%E7%BB%9F%E8%AE%A1/"/>
    <content>
      <![CDATA[<h1 id="Hexo-Stellar-添加全站字数统计"><a href="#Hexo-Stellar-添加全站字数统计" class="headerlink" title="Hexo Stellar 添加全站字数统计"></a>Hexo Stellar 添加全站字数统计</h1><h2 id="效果预览"><a href="#效果预览" class="headerlink" title="效果预览"></a>效果预览</h2><p>在博客页面底部（Footer）显示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">共发表 X 篇 Blog · 总计 XXXXX 字</span><br></pre></td></tr></table></figure><p>实时统计全站所有文章的总字数。</p><h2 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h2><h3 id="1-创建全站字数统计辅助函数"><a href="#1-创建全站字数统计辅助函数" class="headerlink" title="1. 创建全站字数统计辅助函数"></a>1. 创建全站字数统计辅助函数</h3><p>在 <code>themes/stellar/scripts/helpers/</code> 目录下创建 <code>totalcount.js</code> 文件：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 计算全站文章总字数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@returns</span> &#123;<span class="type">number</span>&#125; 总字数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">hexo.<span class="property">extend</span>.<span class="property">helper</span>.<span class="title function_">register</span>(<span class="string">&#x27;totalcount&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> total = <span class="number">0</span>;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 获取所有文章</span></span><br><span class="line">  <span class="keyword">var</span> posts = <span class="variable language_">this</span>.<span class="property">site</span>.<span class="property">posts</span>;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 遍历所有文章</span></span><br><span class="line">  posts.<span class="title function_">forEach</span>(<span class="keyword">function</span>(<span class="params">post</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (post.<span class="property">content</span>) &#123;</span><br><span class="line">      <span class="comment">// 移除 HTML 标签</span></span><br><span class="line">      <span class="keyword">var</span> text = post.<span class="property">content</span>.<span class="title function_">replace</span>(<span class="regexp">/&lt;[^&gt;]+&gt;/g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">      </span><br><span class="line">      <span class="comment">// 计算中文字符数</span></span><br><span class="line">      <span class="keyword">var</span> chinese = (text.<span class="title function_">match</span>(<span class="regexp">/[\u4e00-\u9fa5]/g</span>) || []).<span class="property">length</span>;</span><br><span class="line">      </span><br><span class="line">      <span class="comment">// 计算英文单词数</span></span><br><span class="line">      <span class="keyword">var</span> english = (text.<span class="title function_">match</span>(<span class="regexp">/[a-zA-Z0-9_\u00C0-\u00FF]+/g</span>) || []).<span class="property">length</span>;</span><br><span class="line">      </span><br><span class="line">      total += chinese + english;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> total;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="2-修改-Footer-模板"><a href="#2-修改-Footer-模板" class="headerlink" title="2. 修改 Footer 模板"></a>2. 修改 Footer 模板</h3><p>编辑 <code>themes/stellar/layout/_partial/main/footer.ejs</code> 文件，在 <code>// footer</code> 部分添加：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// footer</span></span><br><span class="line">el += <span class="string">&#x27;&lt;div class=&quot;text&quot;&gt;&#x27;</span></span><br><span class="line"><span class="keyword">if</span> (content) &#123;</span><br><span class="line">  el += <span class="title function_">markdown</span>(content)</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 添加全站字数统计</span></span><br><span class="line">el += <span class="string">&#x27;&lt;div style=&quot;margin-top: 8px; text-align: center;&quot;&gt;&#x27;</span></span><br><span class="line">el += <span class="string">&#x27;&lt;span class=&quot;totalcount&quot;&gt;共发表 &#x27;</span> + site.<span class="property">posts</span>.<span class="property">length</span> + <span class="string">&#x27; 篇 Blog · &lt;/span&gt;&#x27;</span></span><br><span class="line">el += <span class="string">&#x27;&lt;span class=&quot;post-count&quot;&gt;总计 &#x27;</span> + <span class="title function_">totalcount</span>(site) + <span class="string">&#x27; 字&lt;/span&gt;&#x27;</span></span><br><span class="line">el += <span class="string">&#x27;&lt;/div&gt;&#x27;</span></span><br><span class="line">el += <span class="string">&#x27;&lt;/div&gt;&#x27;</span></span><br><span class="line"><span class="comment">// runtime script</span></span><br></pre></td></tr></table></figure><h3 id="3-添加-CSS-样式"><a href="#3-添加-CSS-样式" class="headerlink" title="3. 添加 CSS 样式"></a>3. 添加 CSS 样式</h3><p>在 <code>themes/stellar/source/css/_custom.styl</code> 文件末尾添加：</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 页面底部字数统计 */</span></span><br><span class="line"><span class="selector-class">.post-count</span></span><br><span class="line">  <span class="attribute">scrollbar-width</span>: none</span><br><span class="line">  <span class="attribute">color</span>: <span class="built_in">var</span>(--text-p2)</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.totalcount</span></span><br><span class="line">  <span class="attribute">color</span>: <span class="built_in">var</span>(--text-p2)</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.page-footer</span></span><br><span class="line">  <span class="attribute">text-align</span>: center</span><br><span class="line">  <span class="attribute">margin</span>: <span class="number">0</span> auto</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">100%</span></span><br></pre></td></tr></table></figure><h3 id="4-重新生成博客"><a href="#4-重新生成博客" class="headerlink" title="4. 重新生成博客"></a>4. 重新生成博客</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo generate</span><br><span class="line">hexo server</span><br></pre></td></tr></table></figure><h2 id="功能说明"><a href="#功能说明" class="headerlink" title="功能说明"></a>功能说明</h2><h3 id="字数统计"><a href="#字数统计" class="headerlink" title="字数统计"></a>字数统计</h3><ul><li><strong>统计范围</strong>：全站所有文章（posts）</li><li><strong>计算规则</strong>：中文字符数 + 英文单词数</li><li><strong>显示位置</strong>：页面底部 Footer 区域</li><li><strong>显示格式</strong>：<code>共发表 X 篇 Blog · 总计 XXXXX 字</code></li></ul><h3 id="技术细节"><a href="#技术细节" class="headerlink" title="技术细节"></a>技术细节</h3><h4 id="1-Helper-函数"><a href="#1-Helper-函数" class="headerlink" title="1. Helper 函数"></a>1. Helper 函数</h4><p>使用 <code>hexo.extend.helper.register</code> 注册全局辅助函数：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">hexo.<span class="property">extend</span>.<span class="property">helper</span>.<span class="title function_">register</span>(<span class="string">&#x27;totalcount&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="comment">// this.site 包含所有站点数据</span></span><br><span class="line">  <span class="keyword">var</span> posts = <span class="variable language_">this</span>.<span class="property">site</span>.<span class="property">posts</span>;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h4 id="2-文章遍历"><a href="#2-文章遍历" class="headerlink" title="2. 文章遍历"></a>2. 文章遍历</h4><p>遍历所有文章并累加字数：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">posts.<span class="title function_">forEach</span>(<span class="keyword">function</span>(<span class="params">post</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (post.<span class="property">content</span>) &#123;</span><br><span class="line">    <span class="comment">// 计算字数</span></span><br><span class="line">    total += chinese + english;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h4 id="3-字符匹配"><a href="#3-字符匹配" class="headerlink" title="3. 字符匹配"></a>3. 字符匹配</h4><ul><li><strong>中文</strong>：<code>[\u4e00-\u9fa5]</code> - Unicode 范围</li><li><strong>英文</strong>：<code>[a-zA-Z0-9_\u00C0-\u00FF]+</code> - 单词匹配</li></ul><h3 id="性能优化"><a href="#性能优化" class="headerlink" title="性能优化"></a>性能优化</h3><p>由于需要遍历所有文章，建议在生成时计算，而不是在页面加载时：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ✅ 生成时计算（推荐）</span></span><br><span class="line">el += <span class="string">&#x27;总计 &#x27;</span> + <span class="title function_">totalcount</span>(site) + <span class="string">&#x27; 字&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// ❌ 页面加载时计算（不推荐）</span></span><br><span class="line"><span class="comment">// 需要额外的 JavaScript 代码</span></span><br></pre></td></tr></table></figure><h2 id="自定义配置"><a href="#自定义配置" class="headerlink" title="自定义配置"></a>自定义配置</h2><h3 id="修改显示格式"><a href="#修改显示格式" class="headerlink" title="修改显示格式"></a>修改显示格式</h3><p>在 <code>footer.ejs</code> 中修改字符串：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 简洁版</span></span><br><span class="line">el += <span class="string">&#x27;&lt;span class=&quot;totalcount&quot;&gt;Posts: &#x27;</span> + site.<span class="property">posts</span>.<span class="property">length</span> + <span class="string">&#x27;&lt;/span&gt;&#x27;</span></span><br><span class="line">el += <span class="string">&#x27;&lt;span class=&quot;post-count&quot;&gt; | Words: &#x27;</span> + <span class="title function_">totalcount</span>(site) + <span class="string">&#x27;&lt;/span&gt;&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 详细版</span></span><br><span class="line">el += <span class="string">&#x27;&lt;span class=&quot;totalcount&quot;&gt;文章总数：&#x27;</span> + site.<span class="property">posts</span>.<span class="property">length</span> + <span class="string">&#x27; 篇&lt;/span&gt;&#x27;</span></span><br><span class="line">el += <span class="string">&#x27;&lt;span class=&quot;post-count&quot;&gt; · 总字数：&#x27;</span> + <span class="title function_">totalcount</span>(site) + <span class="string">&#x27; 字&lt;/span&gt;&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="修改样式"><a href="#修改样式" class="headerlink" title="修改样式"></a>修改样式</h3><p>在 <code>_custom.styl</code> 中调整：</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.post-count</span>, <span class="selector-class">.totalcount</span></span><br><span class="line">  <span class="attribute">color</span>: <span class="built_in">var</span>(--text-p1)  // 文字颜色</span><br><span class="line">  <span class="attribute">font-size</span>: <span class="variable">$fs</span>-<span class="number">13</span>      // 字体大小</span><br><span class="line">  <span class="attribute">font-weight</span>: <span class="number">500</span>       // 字重</span><br></pre></td></tr></table></figure><h3 id="添加千位分隔符"><a href="#添加千位分隔符" class="headerlink" title="添加千位分隔符"></a>添加千位分隔符</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在 totalcount.js 中修改返回值</span></span><br><span class="line"><span class="keyword">return</span> total.<span class="title function_">toLocaleString</span>();  <span class="comment">// 12345 -&gt; 12,345</span></span><br></pre></td></tr></table></figure><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><strong>性能考虑</strong>：文章数量多时可能影响生成速度</li><li><strong>缓存策略</strong>：建议在生产环境使用缓存</li><li><strong>准确性</strong>：代码块中的字符也会被统计</li><li><strong>兼容性</strong>：使用 <code>this.site</code> 访问站点数据</li></ol><h2 id="效果展示"><a href="#效果展示" class="headerlink" title="效果展示"></a>效果展示</h2><p>页面底部显示：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">© 2024 Kemeow0815</span><br><span class="line">共发表 5 篇 Blog · 总计 12345 字</span><br><span class="line"></span><br><span class="line">🦉 本站已安全运行：X 年 X 天 X 小时 X 分钟 X 秒 🦉</span><br></pre></td></tr></table></figure><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://hexo.io/api/helper">Hexo Helper API</a></li><li><a href="https://xaoxuu.com/wiki/stellar/">Stellar 主题文档</a></li><li><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions">JavaScript 正则表达式</a></li></ul><hr><p><strong>作者</strong>: Kemeow0815<br><strong>发布日期</strong>: 2026-04-25<br><strong>本文链接</strong>: &#x2F;2026&#x2F;04&#x2F;25&#x2F;site-wordcount&#x2F;</p>]]>
    </content>
    <id>https://blog.kemiaosw.top/posts/5d63715b</id>
    <link href="https://blog.kemiaosw.top/posts/5d63715b"/>
    <published>2026-04-25T11:00:00.000Z</published>
    <summary>为 Hexo Stellar 主题添加页面底部全站文章字数统计功能。</summary>
    <title>Hexo Stellar 添加全站字数统计</title>
    <updated>2026-04-30T05:53:47.322Z</updated>
  </entry>
  <entry>
    <author>
      <name>克喵爱吃卤面</name>
    </author>
    <content>
      <![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">&quot;My New Post&quot;</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]>
    </content>
    <id>https://blog.kemiaosw.top/posts/4a17b156</id>
    <link href="https://blog.kemiaosw.top/posts/4a17b156"/>
    <published>2026-04-25T10:49:27.000Z</published>
    <summary>
      <![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a>]]>
    </summary>
    <title>Hello World</title>
    <updated>2026-04-30T05:53:47.322Z</updated>
  </entry>
  <entry>
    <author>
      <name>克喵爱吃卤面</name>
    </author>
    <category term="技术教程" scheme="https://blog.kemiaosw.top/categories/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
    <category term="Hexo" scheme="https://blog.kemiaosw.top/tags/Hexo/"/>
    <category term="Stellar" scheme="https://blog.kemiaosw.top/tags/Stellar/"/>
    <category term="字数统计" scheme="https://blog.kemiaosw.top/tags/%E5%AD%97%E6%95%B0%E7%BB%9F%E8%AE%A1/"/>
    <category term="阅读时长" scheme="https://blog.kemiaosw.top/tags/%E9%98%85%E8%AF%BB%E6%97%B6%E9%95%BF/"/>
    <content>
      <![CDATA[<h1 id="Hexo-Stellar-添加文章字数统计和阅读时长"><a href="#Hexo-Stellar-添加文章字数统计和阅读时长" class="headerlink" title="Hexo Stellar 添加文章字数统计和阅读时长"></a>Hexo Stellar 添加文章字数统计和阅读时长</h1><h2 id="效果预览"><a href="#效果预览" class="headerlink" title="效果预览"></a>效果预览</h2><p>在文章标题下方、面包屑导航下方显示：</p><ul><li>📅 <strong>发布时间</strong>和<strong>更新时间</strong></li><li>📊 <strong>字数统计</strong>：显示文章总字数</li><li>⏱️ <strong>阅读时长</strong>：估算阅读所需时间</li><li>🏷️ <strong>标签列表</strong>：显示文章标签</li></ul><h2 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h2><h3 id="1-创建字数统计辅助函数"><a href="#1-创建字数统计辅助函数" class="headerlink" title="1. 创建字数统计辅助函数"></a>1. 创建字数统计辅助函数</h3><p>在 <code>themes/stellar/scripts/helpers/</code> 目录下创建 <code>wordcount.js</code> 文件：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 字数统计</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">string</span>&#125; <span class="variable">content</span> - 文章内容</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@returns</span> &#123;<span class="type">number</span>&#125; 字数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">hexo.<span class="property">extend</span>.<span class="property">helper</span>.<span class="title function_">register</span>(<span class="string">&#x27;wordcount&#x27;</span>, <span class="keyword">function</span>(<span class="params">content</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (!content) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 移除 HTML 标签</span></span><br><span class="line">  <span class="keyword">const</span> text = content.<span class="title function_">replace</span>(<span class="regexp">/&lt;[^&gt;]+&gt;/g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 计算中文字符数</span></span><br><span class="line">  <span class="keyword">const</span> chinese = (text.<span class="title function_">match</span>(<span class="regexp">/[\u4e00-\u9fa5]/g</span>) || []).<span class="property">length</span>;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 计算英文单词数</span></span><br><span class="line">  <span class="keyword">const</span> english = (text.<span class="title function_">match</span>(<span class="regexp">/[a-zA-Z0-9_\u00C0-\u00FF]+/g</span>) || []).<span class="property">length</span>;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> chinese + english;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 阅读时长计算（分钟）</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">string</span>&#125; <span class="variable">content</span> - 文章内容</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@returns</span> &#123;<span class="type">number</span>&#125; 阅读时长（分钟）</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">hexo.<span class="property">extend</span>.<span class="property">helper</span>.<span class="title function_">register</span>(<span class="string">&#x27;min2read&#x27;</span>, <span class="keyword">function</span>(<span class="params">content</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (!content) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">const</span> words = <span class="variable language_">this</span>.<span class="title function_">wordcount</span>(content);</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 假设每分钟阅读 300 字</span></span><br><span class="line">  <span class="keyword">const</span> minutes = <span class="title class_">Math</span>.<span class="title function_">ceil</span>(words / <span class="number">300</span>);</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> minutes &gt; <span class="number">0</span> ? minutes : <span class="number">1</span>;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="2-修改文章导航栏模板"><a href="#2-修改文章导航栏模板" class="headerlink" title="2. 修改文章导航栏模板"></a>2. 修改文章导航栏模板</h3><p>编辑 <code>themes/stellar/layout/_partial/main/navbar/article_banner.ejs</code> 文件，在 <code>// 3.left.bottom</code> 部分添加：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 3.left.bottom</span></span><br><span class="line">el += <span class="title function_">partial</span>(<span class="string">&#x27;dateinfo&#x27;</span>)</span><br><span class="line"><span class="comment">// 新增：字数显示 | 阅读时长显示</span></span><br><span class="line"><span class="keyword">if</span> (page.<span class="property">layout</span> == <span class="string">&quot;post&quot;</span>) &#123;</span><br><span class="line">  el += <span class="string">&#x27;&lt;div class=&quot;flex-row&quot; id=&quot;page-words&quot;&gt;&lt;span style=&quot;padding: 4px;&quot;&gt;本文：&#x27;</span> + <span class="title function_">wordcount</span>(page.<span class="property">content</span>) + <span class="string">&#x27;字&lt;/span&gt;&lt;span class=&quot;sep updated&quot; style=&quot;padding: 4px;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;text updated&quot; style=&quot;padding: 4px;&quot;&gt;阅读时长：&#x27;</span> + <span class="title function_">min2read</span>(page.<span class="property">content</span>) + <span class="string">&#x27;分&lt;/span&gt;&lt;/div&gt;&#x27;</span>;</span><br><span class="line">  <span class="comment">// 新增：标签显示</span></span><br><span class="line">  <span class="keyword">if</span> (page.<span class="property">tags</span> &amp;&amp; page.<span class="property">tags</span>.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">    el += <span class="string">&#x27;&lt;div class=&quot;flex-row&quot; id=&quot;tag&quot;&gt;&lt;span&gt;&amp;nbsp;标签：&lt;/span&gt;&#x27;</span>;</span><br><span class="line">    el += <span class="title function_">list_categories</span>(page.<span class="property">tags</span>, &#123;</span><br><span class="line">      <span class="attr">class</span>: <span class="string">&quot;cap breadcrumb&quot;</span>,</span><br><span class="line">      <span class="attr">show_count</span>: <span class="literal">false</span>,</span><br><span class="line">      <span class="attr">separator</span>: <span class="string">&#x27;&amp;nbsp; &#x27;</span>,</span><br><span class="line">      <span class="attr">style</span>: <span class="string">&quot;none&quot;</span></span><br><span class="line">    &#125;);</span><br><span class="line">    el += <span class="string">&#x27;&amp;nbsp;&lt;/div&gt;&#x27;</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// end 2.left</span></span><br><span class="line">el += <span class="string">`&lt;/div&gt;`</span></span><br></pre></td></tr></table></figure><h3 id="3-添加-CSS-样式"><a href="#3-添加-CSS-样式" class="headerlink" title="3. 添加 CSS 样式"></a>3. 添加 CSS 样式</h3><p>在 <code>themes/stellar/source/css/_custom.styl</code> 文件末尾添加：</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 文章内字数统计&amp;阅读时长 */</span></span><br><span class="line"><span class="selector-class">.bread-nav</span> div<span class="selector-id">#page-words</span> <span class="selector-tag">span</span><span class="selector-class">.sep</span><span class="selector-pseudo">:before</span></span><br><span class="line">  <span class="attribute">content</span>: <span class="string">&#x27;|&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="selector-class">.bread-nav</span> div<span class="selector-id">#page-words</span> <span class="selector-tag">span</span><span class="selector-class">.updated</span></span><br><span class="line">  <span class="attribute">visibility</span>: hidden</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.bread-nav</span><span class="selector-pseudo">:hover</span> div<span class="selector-id">#page-words</span> <span class="selector-tag">span</span><span class="selector-class">.updated</span></span><br><span class="line">  <span class="attribute">visibility</span>: visible</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#page-words</span></span><br><span class="line">  <span class="attribute">font-size</span>: <span class="variable">$fs</span>-<span class="number">14</span></span><br><span class="line">  <span class="attribute">color</span>: <span class="built_in">var</span>(--text-p3)</span><br><span class="line">  <span class="attribute">margin-top</span>: <span class="number">4px</span></span><br><span class="line"></span><br><span class="line"><span class="selector-id">#tag</span></span><br><span class="line">  <span class="attribute">font-size</span>: <span class="variable">$fs</span>-<span class="number">14</span></span><br><span class="line">  <span class="attribute">color</span>: <span class="built_in">var</span>(--text-p3)</span><br><span class="line">  <span class="attribute">margin-top</span>: <span class="number">4px</span></span><br><span class="line">  </span><br><span class="line">  <span class="selector-class">.cap</span><span class="selector-class">.breadcrumb</span></span><br><span class="line">    <span class="attribute">color</span>: <span class="built_in">var</span>(--text-link)</span><br><span class="line">    </span><br><span class="line">    <span class="selector-pseudo">&amp;:hover</span></span><br><span class="line">      <span class="attribute">color</span>: <span class="built_in">var</span>(--theme)</span><br></pre></td></tr></table></figure><h3 id="4-重新生成博客"><a href="#4-重新生成博客" class="headerlink" title="4. 重新生成博客"></a>4. 重新生成博客</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo generate</span><br><span class="line">hexo server</span><br></pre></td></tr></table></figure><h2 id="功能说明"><a href="#功能说明" class="headerlink" title="功能说明"></a>功能说明</h2><h3 id="字数统计"><a href="#字数统计" class="headerlink" title="字数统计"></a>字数统计</h3><ul><li><strong>计算规则</strong>：中文字符数 + 英文单词数</li><li><strong>显示位置</strong>：文章标题下方</li><li><strong>显示格式</strong>：<code>本文：XXX 字</code></li></ul><h3 id="阅读时长"><a href="#阅读时长" class="headerlink" title="阅读时长"></a>阅读时长</h3><ul><li><strong>计算规则</strong>：总字数 ÷ 300 字&#x2F;分钟</li><li><strong>向上取整</strong>：不足 1 分钟按 1 分钟计算</li><li><strong>显示格式</strong>：<code>阅读时长：X 分</code></li></ul><h3 id="标签显示"><a href="#标签显示" class="headerlink" title="标签显示"></a>标签显示</h3><ul><li><strong>条件显示</strong>：仅当文章有标签时显示</li><li><strong>格式</strong>：<code>标签：tag1  tag2  tag3</code></li><li><strong>可点击</strong>：点击标签可跳转到标签页面</li></ul><h2 id="自定义配置"><a href="#自定义配置" class="headerlink" title="自定义配置"></a>自定义配置</h2><h3 id="修改阅读速度"><a href="#修改阅读速度" class="headerlink" title="修改阅读速度"></a>修改阅读速度</h3><p>在 <code>wordcount.js</code> 中修改除数：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 每分钟阅读 400 字（适合快速阅读）</span></span><br><span class="line"><span class="keyword">const</span> minutes = <span class="title class_">Math</span>.<span class="title function_">ceil</span>(words / <span class="number">400</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 每分钟阅读 200 字（适合技术文章）</span></span><br><span class="line"><span class="keyword">const</span> minutes = <span class="title class_">Math</span>.<span class="title function_">ceil</span>(words / <span class="number">200</span>);</span><br></pre></td></tr></table></figure><h3 id="修改显示样式"><a href="#修改显示样式" class="headerlink" title="修改显示样式"></a>修改显示样式</h3><p>在 <code>_custom.styl</code> 中调整：</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#page-words</span></span><br><span class="line">  <span class="attribute">font-size</span>: <span class="variable">$fs</span>-<span class="number">13</span>      // 字体大小</span><br><span class="line">  <span class="attribute">color</span>: <span class="built_in">var</span>(--text-p2)  // 文字颜色</span><br><span class="line">  <span class="attribute">margin-top</span>: <span class="number">8px</span>        // 上边距</span><br></pre></td></tr></table></figure><h3 id="修改显示格式"><a href="#修改显示格式" class="headerlink" title="修改显示格式"></a>修改显示格式</h3><p>在 <code>article_banner.ejs</code> 中修改字符串：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 修改为英文显示</span></span><br><span class="line">el += <span class="string">&#x27;Words: &#x27;</span> + <span class="title function_">wordcount</span>(page.<span class="property">content</span>) + <span class="string">&#x27; | &#x27;</span></span><br><span class="line">el += <span class="string">&#x27;Reading time: &#x27;</span> + <span class="title function_">min2read</span>(page.<span class="property">content</span>) + <span class="string">&#x27; min&#x27;</span></span><br></pre></td></tr></table></figure><h2 id="技术细节"><a href="#技术细节" class="headerlink" title="技术细节"></a>技术细节</h2><h3 id="wordcount-函数"><a href="#wordcount-函数" class="headerlink" title="wordcount 函数"></a>wordcount 函数</h3><ol><li>移除 HTML 标签，避免统计标签字符</li><li>使用中文字符 Unicode 范围 <code>[\u4e00-\u9fa5]</code></li><li>使用英文单词正则 <code>[a-zA-Z0-9_\u00C0-\u00FF]+</code></li></ol><h3 id="min2read-函数"><a href="#min2read-函数" class="headerlink" title="min2read 函数"></a>min2read 函数</h3><ol><li>调用 <code>wordcount</code> 获取总字数</li><li>除以阅读速度（默认 300 字&#x2F;分钟）</li><li>使用 <code>Math.ceil</code> 向上取整</li></ol><h3 id="list-categories"><a href="#list-categories" class="headerlink" title="list_categories"></a>list_categories</h3><p>Hexo 内置的标签列表生成函数：</p><ul><li><code>class</code>: CSS 类名</li><li><code>show_count</code>: 是否显示文章数</li><li><code>separator</code>: 标签分隔符</li><li><code>style</code>: 列表样式</li></ul><h2 id="效果展示"><a href="#效果展示" class="headerlink" title="效果展示"></a>效果展示</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">主页 / 文章 / 博客 / 折腾</span><br><span class="line">发布于：53 分钟前 | 更新于：刚刚</span><br><span class="line">本文：880 字 / 阅读时长：4 分</span><br><span class="line">标签：hexo  博客</span><br><span class="line"></span><br><span class="line"># Hexo Stellar 主题装修笔记</span><br></pre></td></tr></table></figure><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><strong>仅对文章生效</strong>：<code>page.layout == &quot;post&quot;</code> 时才显示</li><li><strong>标签可选</strong>：没有标签时不显示标签行</li><li><strong>性能优化</strong>：字数统计在生成时计算，不影响页面加载速度</li><li><strong>主题适配</strong>：使用主题变量，自动适配明暗模式</li></ol><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://hexo.io/api/helper">Hexo Helper API</a></li><li><a href="https://xaoxuu.com/wiki/stellar/">Stellar 主题文档</a></li><li><a href="https://ejs.co/">EJS 模板语法</a></li></ul><hr><p><strong>作者</strong>: Kemeow0815<br><strong>发布日期</strong>: 2026-04-25<br><strong>本文链接</strong>: &#x2F;2026&#x2F;04&#x2F;25&#x2F;wordcount-reading-time&#x2F;</p>]]>
    </content>
    <id>https://blog.kemiaosw.top/posts/1a11017e</id>
    <link href="https://blog.kemiaosw.top/posts/1a11017e"/>
    <published>2026-04-25T10:00:00.000Z</published>
    <summary>为 Hexo Stellar 主题添加文章字数统计、阅读时长估算和标签显示功能。</summary>
    <title>Hexo Stellar 添加文章字数统计和阅读时长</title>
    <updated>2026-04-30T05:53:47.322Z</updated>
  </entry>
  <entry>
    <author>
      <name>克喵爱吃卤面</name>
    </author>
    <category term="测试文章" scheme="https://blog.kemiaosw.top/categories/%E6%B5%8B%E8%AF%95%E6%96%87%E7%AB%A0/"/>
    <category term="测试" scheme="https://blog.kemiaosw.top/tags/%E6%B5%8B%E8%AF%95/"/>
    <category term="代码块" scheme="https://blog.kemiaosw.top/tags/%E4%BB%A3%E7%A0%81%E5%9D%97/"/>
    <content>
      <![CDATA[<h1 id="代码块样式测试"><a href="#代码块样式测试" class="headerlink" title="代码块样式测试"></a>代码块样式测试</h1><p>本文用于测试新添加的 macOS 风格代码块样式。</p><h2 id="JavaScript-代码示例"><a href="#JavaScript-代码示例" class="headerlink" title="JavaScript 代码示例"></a>JavaScript 代码示例</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 主题切换功能</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">switchToTheme</span> = (<span class="params">theme, message</span>) =&gt; &#123;</span><br><span class="line">  <span class="title function_">applyTheme</span>(theme)</span><br><span class="line">  <span class="variable language_">window</span>.<span class="property">localStorage</span>.<span class="title function_">setItem</span>(<span class="string">&#x27;Stellar.theme&#x27;</span>, theme)</span><br><span class="line">  utils.<span class="property">dark</span>.<span class="property">mode</span> = theme === <span class="string">&#x27;auto&#x27;</span> </span><br><span class="line">    ? (<span class="variable language_">window</span>.<span class="title function_">matchMedia</span>(<span class="string">&quot;(prefers-color-scheme: dark)&quot;</span>).<span class="property">matches</span> ? <span class="string">&quot;dark&quot;</span> : <span class="string">&quot;light&quot;</span>) </span><br><span class="line">    : theme;</span><br><span class="line">  utils.<span class="property">dark</span>.<span class="property">method</span>.<span class="property">toggle</span>.<span class="title function_">start</span>();</span><br><span class="line">  hud?.<span class="property">toast</span>?.(message)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Hello, Stellar!&#x27;</span>)</span><br></pre></td></tr></table></figure><h2 id="Python-代码示例"><a href="#Python-代码示例" class="headerlink" title="Python 代码示例"></a>Python 代码示例</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 简单的 Python 示例</span></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">greet</span>(<span class="params">name</span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;打招呼函数&quot;&quot;&quot;</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;Hello, <span class="subst">&#123;name&#125;</span>!&quot;</span>)</span><br><span class="line">    </span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    greet(<span class="string">&quot;Kemeow0815&quot;</span>)</span><br></pre></td></tr></table></figure><h2 id="CSS-代码示例"><a href="#CSS-代码示例" class="headerlink" title="CSS 代码示例"></a>CSS 代码示例</h2><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* macOS 风格圆点按钮 */</span></span><br><span class="line"><span class="selector-class">.highlight</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">  <span class="attribute">content</span>: <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">  <span class="attribute">position</span>: absolute;</span><br><span class="line">  <span class="attribute">left</span>: <span class="number">12px</span>;</span><br><span class="line">  <span class="attribute">top</span>: <span class="number">12px</span>;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">12px</span>;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">12px</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">50%</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#ff5f56</span>;</span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="number">20px</span> <span class="number">0</span> <span class="number">#ffbd2e</span>, <span class="number">40px</span> <span class="number">0</span> <span class="number">#27c935</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="HTML-代码示例"><a href="#HTML-代码示例" class="headerlink" title="HTML 代码示例"></a>HTML 代码示例</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;zh-CN&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">title</span>&gt;</span>测试页面<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">h1</span>&gt;</span>Hello World<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="YAML-配置示例"><a href="#YAML-配置示例" class="headerlink" title="YAML 配置示例"></a>YAML 配置示例</h2><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Stellar 主题配置</span></span><br><span class="line"><span class="attr">inject:</span></span><br><span class="line">  <span class="attr">head:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">&#x27;&lt;link rel=&quot;stylesheet&quot; href=&quot;/css/custom-codeblock.css&quot;&gt;&#x27;</span></span><br><span class="line">    </span><br><span class="line"><span class="attr">style:</span></span><br><span class="line">  <span class="attr">prefers_theme:</span> <span class="string">auto</span></span><br><span class="line">  <span class="attr">smooth_scroll:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h2 id="Shell-命令示例"><a href="#Shell-命令示例" class="headerlink" title="Shell 命令示例"></a>Shell 命令示例</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Hexo 常用命令</span></span><br><span class="line">hexo clean</span><br><span class="line">hexo generate</span><br><span class="line">hexo server</span><br><span class="line">hexo deploy</span><br></pre></td></tr></table></figure><h2 id="Java-代码示例"><a href="#Java-代码示例" class="headerlink" title="Java 代码示例"></a>Java 代码示例</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloWorld</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Hello, Stellar!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="C-代码示例"><a href="#C-代码示例" class="headerlink" title="C++ 代码示例"></a>C++ 代码示例</h2><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Hello, World!&quot;</span> &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Go-代码示例"><a href="#Go-代码示例" class="headerlink" title="Go 代码示例"></a>Go 代码示例</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">    fmt.Println(<span class="string">&quot;Hello, Stellar!&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Rust-代码示例"><a href="#Rust-代码示例" class="headerlink" title="Rust 代码示例"></a>Rust 代码示例</h2><figure class="highlight rust"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">fn</span> <span class="title function_">main</span>() &#123;</span><br><span class="line">    <span class="built_in">println!</span>(<span class="string">&quot;Hello, Stellar!&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="PHP-代码示例"><a href="#PHP-代码示例" class="headerlink" title="PHP 代码示例"></a>PHP 代码示例</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="keyword">echo</span> <span class="string">&quot;Hello, Stellar!&quot;</span>;</span><br><span class="line"><span class="meta">?&gt;</span></span><br></pre></td></tr></table></figure><h2 id="SQL-查询示例"><a href="#SQL-查询示例" class="headerlink" title="SQL 查询示例"></a>SQL 查询示例</h2><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> users </span><br><span class="line"><span class="keyword">WHERE</span> status <span class="operator">=</span> <span class="string">&#x27;active&#x27;</span> </span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> created_at <span class="keyword">DESC</span>;</span><br></pre></td></tr></table></figure><h2 id="Ruby-代码示例"><a href="#Ruby-代码示例" class="headerlink" title="Ruby 代码示例"></a>Ruby 代码示例</h2><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">HelloWorld</span></span><br><span class="line">  <span class="keyword">def</span> <span class="title function_">self</span>.greet</span><br><span class="line">    puts <span class="string">&quot;Hello, Stellar!&quot;</span></span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure><h2 id="测试说明"><a href="#测试说明" class="headerlink" title="测试说明"></a>测试说明</h2><p>现在代码块应该显示：</p><ol><li>✅ <strong>三个 macOS 圆点按钮</strong>（红、黄、绿）</li><li>✅ <strong>“优雅借鉴”文字</strong>在圆点右侧</li><li>✅ <strong>鼠标悬停时变色</strong>效果</li><li>✅ <strong>作者签名</strong>在右下角</li><li>✅ <strong>精美的语法高亮</strong></li></ol><p>如果看不到圆点，请检查：</p><ul><li>CSS 文件是否正确加载</li><li>浏览器缓存是否已清除</li><li>代码块是否使用了正确的语言标记</li></ul><hr><p><strong>测试时间</strong>: 2026-04-25<br><strong>测试者</strong>: Kemeow0815</p>]]>
    </content>
    <id>https://blog.kemiaosw.top/posts/ed02a91f</id>
    <link href="https://blog.kemiaosw.top/posts/ed02a91f"/>
    <published>2026-04-25T09:00:00.000Z</published>
    <summary>测试 macOS 风格的代码块样式</summary>
    <title>代码块样式测试</title>
    <updated>2026-04-30T05:53:47.322Z</updated>
  </entry>
  <entry>
    <author>
      <name>克喵爱吃卤面</name>
    </author>
    <category term="技术教程" scheme="https://blog.kemiaosw.top/categories/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
    <category term="Hexo" scheme="https://blog.kemiaosw.top/tags/Hexo/"/>
    <category term="Stellar" scheme="https://blog.kemiaosw.top/tags/Stellar/"/>
    <category term="CSS" scheme="https://blog.kemiaosw.top/tags/CSS/"/>
    <category term="代码美化" scheme="https://blog.kemiaosw.top/tags/%E4%BB%A3%E7%A0%81%E7%BE%8E%E5%8C%96/"/>
    <content>
      <![CDATA[<h1 id="Hexo-Stellar-代码块美化指南"><a href="#Hexo-Stellar-代码块美化指南" class="headerlink" title="Hexo Stellar 代码块美化指南"></a>Hexo Stellar 代码块美化指南</h1><h2 id="效果预览"><a href="#效果预览" class="headerlink" title="效果预览"></a>效果预览</h2><p>通过本文的美化方案，你的代码块将会拥有：</p><ul><li>🎨 <strong>macOS 风格顶部按钮</strong>：三个彩色圆点，鼠标悬停时变色</li><li>✨ <strong>优雅借鉴提示</strong>：顶部显示”优雅借鉴”文字</li><li><strong>精美语法高亮</strong>：清晰的代码颜色区分</li><li>📝 <strong>作者签名</strong>：代码块右下角显示作者信息和站点名称（带月亮图标）</li><li>🎯 <strong>悬停效果</strong>：鼠标悬停时按钮变色提示</li><li>📱 <strong>响应式设计</strong>：完美适配移动端</li></ul><h2 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h2><h3 id="1-创建自定义-CSS-文件"><a href="#1-创建自定义-CSS-文件" class="headerlink" title="1. 创建自定义 CSS 文件"></a>1. 创建自定义 CSS 文件</h3><p>在博客的 <code>source/css/</code> 目录下创建 <code>custom-codeblock.css</code> 文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 文件路径</span></span><br><span class="line"><span class="built_in">source</span>/css/custom-codeblock.css</span><br></pre></td></tr></table></figure><h3 id="2-添加美化样式"><a href="#2-添加美化样式" class="headerlink" title="2. 添加美化样式"></a>2. 添加美化样式</h3><p>将以下代码复制到 <code>custom-codeblock.css</code> 文件中：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 代码块美化样式 */</span></span><br><span class="line"></span><br><span class="line"><span class="selector-pseudo">:root</span> &#123;</span><br><span class="line">  <span class="attr">--code-autor</span>: <span class="string">&#x27;© YourName🌙&#x27;</span>;</span><br><span class="line">  <span class="attr">--code-tip</span>: <span class="string">&quot;优雅借鉴&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 语法高亮容器 */</span></span><br><span class="line"><span class="selector-class">.md-text</span> <span class="selector-class">.highlight</span> &#123;</span><br><span class="line">  <span class="attribute">position</span>: relative;</span><br><span class="line">  <span class="attribute">display</span>: block;</span><br><span class="line">  <span class="attribute">overflow-x</span>: hidden;</span><br><span class="line">  <span class="attribute">background</span>: <span class="built_in">var</span>(--block);</span><br><span class="line">  <span class="attribute">color</span>: <span class="number">#9c67a1</span>;</span><br><span class="line">  <span class="attribute">padding</span>: <span class="number">30px</span> <span class="number">5px</span> <span class="number">2px</span> <span class="number">5px</span> <span class="meta">!important</span>;</span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="number">0</span> <span class="number">10px</span> <span class="number">30px</span> <span class="number">0px</span> <span class="built_in">rgb</span>(<span class="number">0</span> <span class="number">0</span> <span class="number">0</span> / <span class="number">40%</span>);</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">12px</span>;</span><br><span class="line">  <span class="attribute">margin</span>: <span class="number">1.5em</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 代码块顶部提示（类似 macOS 窗口按钮） */</span></span><br><span class="line"><span class="selector-class">.hljs</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">  <span class="attribute">content</span>: <span class="built_in">var</span>(--code-tip);</span><br><span class="line">  <span class="attribute">position</span>: absolute;</span><br><span class="line">  <span class="attribute">left</span>: <span class="number">15px</span>;</span><br><span class="line">  <span class="attribute">top</span>: <span class="number">10px</span>;</span><br><span class="line">  <span class="attribute">overflow</span>: visible;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">12px</span>;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">12px</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">16px</span>;</span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="number">20px</span> <span class="number">0</span> <span class="number">#a9a6a1</span>, <span class="number">40px</span> <span class="number">0</span> <span class="number">#999</span>;</span><br><span class="line">  -webkit-<span class="attribute">box-shadow</span>: <span class="number">20px</span> <span class="number">0</span> <span class="number">#a9a6a1</span>, <span class="number">40px</span> <span class="number">0</span> <span class="number">#999</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#999</span>;</span><br><span class="line">  <span class="attribute">white-space</span>: nowrap;</span><br><span class="line">  <span class="attribute">text-indent</span>: <span class="number">75px</span>;</span><br><span class="line">  <span class="attribute">font-size</span>: <span class="number">16px</span>;</span><br><span class="line">  <span class="attribute">line-height</span>: <span class="number">12px</span>;</span><br><span class="line">  <span class="attribute">font-weight</span>: <span class="number">700</span>;</span><br><span class="line">  <span class="attribute">color</span>: <span class="number">#999</span>;</span><br><span class="line">  <span class="attribute">transition</span>: all <span class="number">0.3s</span> ease;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 鼠标悬停时变色效果 */</span></span><br><span class="line"><span class="selector-class">.highlight</span><span class="selector-pseudo">:hover</span> <span class="selector-class">.hljs</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">  <span class="attribute">color</span>: <span class="number">#35cd4b</span>;</span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="number">20px</span> <span class="number">0</span> <span class="number">#fdbc40</span>, <span class="number">40px</span> <span class="number">0</span> <span class="number">#35cd4b</span>;</span><br><span class="line">  -webkit-<span class="attribute">box-shadow</span>: <span class="number">20px</span> <span class="number">0</span> <span class="number">#fdbc40</span>, <span class="number">40px</span> <span class="number">0</span> <span class="number">#35cd4b</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#fc625d</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* ... 更多样式请参考完整 CSS 文件 ... */</span></span><br></pre></td></tr></table></figure><h3 id="3-在主题配置中引入"><a href="#3-在主题配置中引入" class="headerlink" title="3. 在主题配置中引入"></a>3. 在主题配置中引入</h3><p>编辑 <code>_config.stellar.yml</code> 文件，添加 inject 配置：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">######## head tags ########</span></span><br><span class="line"><span class="attr">preconnect:</span></span><br><span class="line">  <span class="comment"># - https://gcore.jsdelivr.net</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 自定义注入到 head 的 HTML 代码</span></span><br><span class="line"><span class="attr">inject:</span></span><br><span class="line">  <span class="attr">head:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">&#x27;&lt;link rel=&quot;stylesheet&quot; href=&quot;/css/custom-codeblock.css&quot; type=&quot;text/css&quot;&gt;&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="4-重新生成博客"><a href="#4-重新生成博客" class="headerlink" title="4. 重新生成博客"></a>4. 重新生成博客</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo generate</span><br><span class="line">hexo server</span><br></pre></td></tr></table></figure><h2 id="自定义配置"><a href="#自定义配置" class="headerlink" title="自定义配置"></a>自定义配置</h2><h3 id="修改作者签名"><a href="#修改作者签名" class="headerlink" title="修改作者签名"></a>修改作者签名</h3><p>在 <code>custom-codeblock.css</code> 文件顶部修改：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-pseudo">:root</span> &#123;</span><br><span class="line">  <span class="attr">--code-autor</span>: <span class="string">&#x27;© 你的名字🌙&#x27;</span>;  <span class="comment">/* 修改这里 */</span></span><br><span class="line">  <span class="attr">--code-tip</span>: <span class="string">&quot;优雅借鉴&quot;</span>;        <span class="comment">/* 或者修改提示文字 */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="调整颜色方案"><a href="#调整颜色方案" class="headerlink" title="调整颜色方案"></a>调整颜色方案</h3><p>可以根据个人喜好修改语法高亮的颜色：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.hljs-keyword</span> &#123; <span class="attribute">color</span>: <span class="number">#c78300</span>; &#125;    <span class="comment">/* 关键字颜色 */</span></span><br><span class="line"><span class="selector-class">.hljs-string</span> &#123; <span class="attribute">color</span>: <span class="number">#4caf50</span>; &#125;     <span class="comment">/* 字符串颜色 */</span></span><br><span class="line"><span class="selector-class">.hljs-comment</span> &#123; <span class="attribute">color</span>: <span class="number">#57a64a</span>; &#125;    <span class="comment">/* 注释颜色 */</span></span><br><span class="line"><span class="selector-class">.hljs-number</span> &#123; <span class="attribute">color</span>: <span class="number">#2094f3</span>; &#125;     <span class="comment">/* 数字颜色 */</span></span><br></pre></td></tr></table></figure><h3 id="修改顶部按钮样式"><a href="#修改顶部按钮样式" class="headerlink" title="修改顶部按钮样式"></a>修改顶部按钮样式</h3><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 默认状态 */</span></span><br><span class="line"><span class="selector-class">.hljs</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="number">20px</span> <span class="number">0</span> <span class="number">#a9a6a1</span>, <span class="number">40px</span> <span class="number">0</span> <span class="number">#999</span>;  <span class="comment">/* 三个圆点的颜色 */</span></span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#999</span>;                    <span class="comment">/* 第一个圆点颜色 */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 悬停状态 */</span></span><br><span class="line"><span class="selector-class">.highlight</span><span class="selector-pseudo">:hover</span> <span class="selector-class">.hljs</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="number">20px</span> <span class="number">0</span> <span class="number">#fdbc40</span>, <span class="number">40px</span> <span class="number">0</span> <span class="number">#35cd4b</span>;  <span class="comment">/* 悬停时的颜色 */</span></span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#fc625d</span>;                    <span class="comment">/* 第一个圆点悬停颜色 */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="功能特点"><a href="#功能特点" class="headerlink" title="功能特点"></a>功能特点</h2><h3 id="1-macOS-风格顶部按钮"><a href="#1-macOS-风格顶部按钮" class="headerlink" title="1. macOS 风格顶部按钮"></a>1. macOS 风格顶部按钮</h3><p>代码块顶部显示三个类似 macOS 窗口的控制按钮，鼠标悬停时会变色：</p><ul><li><strong>默认状态</strong>：<ul><li>🔴 红色圆点 (#ff5f56)</li><li>🟡 黄色圆点 (#ffbd2e)</li><li>🟢 绿色圆点 (#27c935)</li></ul></li><li><strong>悬停状态</strong>：<ul><li>🔴 深红色 (#ff3b30)</li><li>🟠 橙色 (#ff9500)</li><li>🟢 鲜绿色 (#34c759)</li></ul></li></ul><h3 id="2-智能语法高亮"><a href="#2-智能语法高亮" class="headerlink" title="2. 智能语法高亮"></a>2. 智能语法高亮</h3><p>支持多种编程语言的语法高亮：</p><ul><li><strong>HTML&#x2F;XML</strong></li><li><strong>JavaScript&#x2F;TypeScript</strong></li><li><strong>CSS&#x2F;Less</strong></li><li><strong>Python</strong></li><li><strong>Java</strong></li><li><strong>C&#x2F;C++</strong></li><li><strong>Go&#x2F;Rust</strong></li><li><strong>PHP&#x2F;Ruby</strong></li><li><strong>SQL</strong></li><li><strong>Shell&#x2F;Bash</strong></li><li><strong>JSON&#x2F;YAML</strong></li><li><strong>Markdown</strong></li><li>等等…</li></ul><h3 id="3-作者签名"><a href="#3-作者签名" class="headerlink" title="3. 作者签名"></a>3. 作者签名</h3><p>在每个代码块的右下角显示作者信息和站点名称，格式为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">🌙 © YourName · SiteName</span><br></pre></td></tr></table></figure><p>默认带有半透明效果，鼠标悬停时变清晰。</p><h3 id="4-响应式设计"><a href="#4-响应式设计" class="headerlink" title="4. 响应式设计"></a>4. 响应式设计</h3><p>在移动端自动调整样式：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">@media</span> screen <span class="keyword">and</span> (<span class="attribute">max-width</span>: <span class="number">768px</span>) &#123;</span><br><span class="line">  <span class="selector-class">.md-text</span> <span class="selector-class">.highlight</span> &#123;</span><br><span class="line">    <span class="attribute">padding</span>: <span class="number">25px</span> <span class="number">3px</span> <span class="number">2px</span> <span class="number">3px</span> <span class="meta">!important</span>;</span><br><span class="line">    <span class="attribute">margin</span>: <span class="number">1em</span> <span class="number">0</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="5-暗色模式适配"><a href="#5-暗色模式适配" class="headerlink" title="5. 暗色模式适配"></a>5. 暗色模式适配</h3><p>自动适配 Stellar 主题的明暗模式：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-class">.hljs</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">  <span class="attribute">box-shadow</span>: <span class="number">20px</span> <span class="number">0</span> <span class="number">#666</span>, <span class="number">40px</span> <span class="number">0</span> <span class="number">#555</span>;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#555</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="高级定制"><a href="#高级定制" class="headerlink" title="高级定制"></a>高级定制</h2><h3 id="添加更多语言标签"><a href="#添加更多语言标签" class="headerlink" title="添加更多语言标签"></a>添加更多语言标签</h3><p>在 CSS 文件中添加：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.hljs</span><span class="selector-class">.language-kotlin</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">  <span class="attribute">content</span>: <span class="string">&quot;Kotlin&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.hljs</span><span class="selector-class">.language-scala</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">  <span class="attribute">content</span>: <span class="string">&quot;Scala&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="自定义滚动条样式"><a href="#自定义滚动条样式" class="headerlink" title="自定义滚动条样式"></a>自定义滚动条样式</h3><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.hljs-ln</span>::-webkit-scrollbar &#123;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">10px</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">5px</span>;</span><br><span class="line">  <span class="attribute">background</span>: <span class="number">#333</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.hljs-ln</span>::-webkit-scrollbar-thumb &#123;</span><br><span class="line">  <span class="attribute">background-color</span>: <span class="number">#bbb</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">5px</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="添加代码折叠功能"><a href="#添加代码折叠功能" class="headerlink" title="添加代码折叠功能"></a>添加代码折叠功能</h3><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">code</span><span class="selector-class">.hljs</span> &#123;</span><br><span class="line">  <span class="attribute">display</span>: -webkit-box;</span><br><span class="line">  <span class="attribute">overflow</span>: hidden;</span><br><span class="line">  -webkit-<span class="selector-tag">line</span>-clamp: <span class="number">10</span>;  <span class="comment">/* 默认显示 10 行 */</span></span><br><span class="line">  -webkit-<span class="attribute">box-orient</span>: vertical;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.hljsOpen</span> &#123;</span><br><span class="line">  -webkit-<span class="selector-tag">line</span>-clamp: <span class="number">99999</span> <span class="meta">!important</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="效果对比"><a href="#效果对比" class="headerlink" title="效果对比"></a>效果对比</h2><h3 id="美化前"><a href="#美化前" class="headerlink" title="美化前"></a>美化前</h3><ul><li>普通的代码块样式</li><li>无特色</li><li>缺少视觉层次</li></ul><h3 id="美化后"><a href="#美化后" class="headerlink" title="美化后"></a>美化后</h3><ul><li>✨ macOS 风格顶部按钮</li><li>🎨 精美的语法高亮</li><li>📝 作者签名</li><li>🌈 悬停交互效果</li><li>📱 完美的响应式支持</li></ul><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://log.cns.red/Stellar%E4%BB%A3%E7%A0%81%E5%9D%97%E4%B8%AA%E4%BA%BA%E5%90%91%E7%BE%8E%E5%8C%96/">Stellar 代码块个人向美化</a></li><li><a href="https://xaoxuu.com/wiki/stellar/">Stellar 主题文档</a></li><li><a href="https://highlightjs.org/">Highlight.js 文档</a></li></ul><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h3 id="Q-代码块样式没有变化？"><a href="#Q-代码块样式没有变化？" class="headerlink" title="Q: 代码块样式没有变化？"></a>Q: 代码块样式没有变化？</h3><p>A: 请检查：</p><ol><li>CSS 文件路径是否正确</li><li>是否在 <code>_config.stellar.yml</code> 中添加了 inject 配置</li><li>是否执行了 <code>hexo clean &amp;&amp; hexo generate</code></li><li>浏览器缓存是否已清除</li></ol><h3 id="Q-如何修改作者签名？"><a href="#Q-如何修改作者签名？" class="headerlink" title="Q: 如何修改作者签名？"></a>Q: 如何修改作者签名？</h3><p>A: 在 <code>custom-codeblock.css</code> 文件顶部的 <code>:root</code> 中修改 <code>--code-autor</code> 变量</p><h3 id="Q-顶部按钮不显示？"><a href="#Q-顶部按钮不显示？" class="headerlink" title="Q: 顶部按钮不显示？"></a>Q: 顶部按钮不显示？</h3><p>A: 请检查以下几点：</p><ol><li>确保 CSS 文件正确加载（打开浏览器开发者工具查看网络请求）</li><li>清除浏览器缓存（Ctrl+Shift+Delete）</li><li>确保代码块使用了正确的语法高亮标记，例如：</li></ol><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="code">```javascript</span></span><br><span class="line"><span class="code">// 你的代码</span></span><br><span class="line"><span class="code">```</span></span><br></pre></td></tr></table></figure><ol start="4"><li>检查 CSS 选择器是否正确（应该是 <code>.highlight::before</code>）</li></ol><h3 id="Q-移动端显示异常？"><a href="#Q-移动端显示异常？" class="headerlink" title="Q: 移动端显示异常？"></a>Q: 移动端显示异常？</h3><p>A: 检查是否正确添加了响应式样式，或调整移动端的 padding 和 margin 值</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过以上配置，你的 Hexo Stellar 博客代码块将拥有：</p><p>✅ <strong>高颜值</strong>：macOS 风格设计，视觉体验优秀<br>✅ <strong>易用性</strong>：配置简单，只需添加 CSS 文件<br>✅ <strong>可定制</strong>：所有元素都可以自定义<br>✅ <strong>响应式</strong>：完美适配各种设备<br>✅ <strong>主题适配</strong>：自动适配明暗模式  </p><p>立即动手美化你的代码块吧！</p><hr><p><strong>作者</strong>: Kemeow0815<br><strong>发布日期</strong>: 2026-04-25<br><strong>本文链接</strong>: &#x2F;2026&#x2F;04&#x2F;25&#x2F;codeblock-beautification&#x2F;</p>]]>
    </content>
    <id>https://blog.kemiaosw.top/posts/248a939e</id>
    <link href="https://blog.kemiaosw.top/posts/248a939e"/>
    <published>2026-04-25T08:00:00.000Z</published>
    <summary>参考其他博客的美化方案，为 Hexo Stellar 主题添加优雅的代码块样式，包含顶部按钮、语法高亮、作者签名等功能。</summary>
    <title>Hexo Stellar 代码块美化指南</title>
    <updated>2026-04-30T05:53:47.322Z</updated>
  </entry>
  <entry>
    <author>
      <name>克喵爱吃卤面</name>
    </author>
    <category term="技术教程" scheme="https://blog.kemiaosw.top/categories/%E6%8A%80%E6%9C%AF%E6%95%99%E7%A8%8B/"/>
    <category term="Hexo" scheme="https://blog.kemiaosw.top/tags/Hexo/"/>
    <category term="Stellar" scheme="https://blog.kemiaosw.top/tags/Stellar/"/>
    <category term="主题开发" scheme="https://blog.kemiaosw.top/tags/%E4%B8%BB%E9%A2%98%E5%BC%80%E5%8F%91/"/>
    <category term="JavaScript" scheme="https://blog.kemiaosw.top/tags/JavaScript/"/>
    <content>
      <![CDATA[<h1 id="Hexo-Stellar-主题明暗模式切换功能实现指南"><a href="#Hexo-Stellar-主题明暗模式切换功能实现指南" class="headerlink" title="Hexo Stellar 主题明暗模式切换功能实现指南"></a>Hexo Stellar 主题明暗模式切换功能实现指南</h1><h2 id="功能概述"><a href="#功能概述" class="headerlink" title="功能概述"></a>功能概述</h2><p>本文介绍如何在 Hexo Stellar 博客主题中实现一个优雅的主题切换功能，通过导航栏的三个按钮（月亮、太阳、AI 图标）来快速切换<strong>深色模式</strong>、<strong>浅色模式</strong>和<strong>跟随系统模式</strong>，切换时会显示一个 3 秒后自动消失的弹窗提示。</p><h2 id="效果展示"><a href="#效果展示" class="headerlink" title="效果展示"></a>效果展示</h2><ul><li>🌙 <strong>点击月亮图标</strong>：切换到深色模式，显示提示”切换到深色模式”</li><li>☀️ <strong>点击太阳图标</strong>：切换到浅色模式，显示提示”切换到浅色模式”</li><li>🤖 <strong>点击 AI 图标</strong>：切换到跟随系统模式，显示提示”跟随系统”</li></ul><h2 id="实现原理"><a href="#实现原理" class="headerlink" title="实现原理"></a>实现原理</h2><h3 id="1-Stellar-主题的主题机制"><a href="#1-Stellar-主题的主题机制" class="headerlink" title="1. Stellar 主题的主题机制"></a>1. Stellar 主题的主题机制</h3><p>Stellar 主题使用 <code>data-theme</code> 属性来控制明暗模式：</p><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 浅色模式</span></span><br><span class="line"><span class="selector-pseudo">:root</span><span class="selector-attr">[data-theme=<span class="string">&quot;light&quot;</span>]</span></span><br><span class="line">  <span class="built_in">dynamic-theme-light</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 深色模式</span></span><br><span class="line"><span class="selector-pseudo">:root</span><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span></span><br><span class="line">  <span class="built_in">dynamic-theme-dark</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 跟随系统（不设置 data-theme 属性）</span></span><br><span class="line"><span class="selector-pseudo">:root</span></span><br><span class="line">  <span class="built_in">dynamic-theme-light</span>()</span><br><span class="line">  <span class="keyword">@media</span> (<span class="attribute">prefers-color-scheme</span>: dark)</span><br><span class="line">    dynamic-theme-dark()</span><br></pre></td></tr></table></figure><p>主题会自动适配所有组件，包括：</p><ul><li>导航栏和侧边栏</li><li>文章内容和代码块</li><li>评论系统（Giscus、Artalk 等）</li><li>标签插件（投票、聊天框等）</li><li>搜索功能</li></ul><h3 id="2-核心实现代码"><a href="#2-核心实现代码" class="headerlink" title="2. 核心实现代码"></a>2. 核心实现代码</h3><p>在 <code>themes/stellar/layout/_partial/scripts/theme.ejs</code> 中添加以下功能：</p><h4 id="2-1-切换到指定主题的函数"><a href="#2-1-切换到指定主题的函数" class="headerlink" title="2.1 切换到指定主题的函数"></a>2.1 切换到指定主题的函数</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 切换到指定主题模式</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">switchToTheme</span> = (<span class="params">theme, message</span>) =&gt; &#123;</span><br><span class="line">  <span class="title function_">applyTheme</span>(theme)</span><br><span class="line">  <span class="variable language_">window</span>.<span class="property">localStorage</span>.<span class="title function_">setItem</span>(<span class="string">&#x27;Stellar.theme&#x27;</span>, theme)</span><br><span class="line">  utils.<span class="property">dark</span>.<span class="property">mode</span> = theme === <span class="string">&#x27;auto&#x27;</span> </span><br><span class="line">    ? (<span class="variable language_">window</span>.<span class="title function_">matchMedia</span>(<span class="string">&quot;(prefers-color-scheme: dark)&quot;</span>).<span class="property">matches</span> ? <span class="string">&quot;dark&quot;</span> : <span class="string">&quot;light&quot;</span>) </span><br><span class="line">    : theme;</span><br><span class="line">  utils.<span class="property">dark</span>.<span class="property">method</span>.<span class="property">toggle</span>.<span class="title function_">start</span>();</span><br><span class="line">  hud?.<span class="property">toast</span>?.(message)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>功能说明：</strong></p><ul><li><code>applyTheme(theme)</code>：应用主题到页面</li><li><code>localStorage</code>：保存用户偏好，下次访问时自动应用</li><li><code>utils.dark.mode</code>：更新内部状态</li><li><code>hud.toast(message)</code>：显示提示消息（3 秒后自动消失）</li></ul><h4 id="2-2-绑定主题切换按钮"><a href="#2-2-绑定主题切换按钮" class="headerlink" title="2.2 绑定主题切换按钮"></a>2.2 绑定主题切换按钮</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 绑定三个主题切换按钮</span></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">bindThemeButtons</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> moonBtn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;ThemeM&#x27;</span>)</span><br><span class="line">  <span class="keyword">const</span> sunBtn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;ThemeL&#x27;</span>)</span><br><span class="line">  <span class="keyword">const</span> aiBtn = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;ThemeAI&#x27;</span>)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (moonBtn) &#123;</span><br><span class="line">    moonBtn.<span class="title function_">closest</span>(<span class="string">&#x27;a&#x27;</span>)?.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">      e.<span class="title function_">preventDefault</span>()</span><br><span class="line">      <span class="title function_">switchToTheme</span>(<span class="string">&#x27;dark&#x27;</span>, <span class="string">&#x27;切换到深色模式&#x27;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (sunBtn) &#123;</span><br><span class="line">    sunBtn.<span class="title function_">closest</span>(<span class="string">&#x27;a&#x27;</span>)?.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">      e.<span class="title function_">preventDefault</span>()</span><br><span class="line">      <span class="title function_">switchToTheme</span>(<span class="string">&#x27;light&#x27;</span>, <span class="string">&#x27;切换到浅色模式&#x27;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (aiBtn) &#123;</span><br><span class="line">    aiBtn.<span class="title function_">closest</span>(<span class="string">&#x27;a&#x27;</span>)?.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">      e.<span class="title function_">preventDefault</span>()</span><br><span class="line">      <span class="title function_">switchToTheme</span>(<span class="string">&#x27;auto&#x27;</span>, <span class="string">&#x27;跟随系统&#x27;</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>功能说明：</strong></p><ul><li>通过按钮中的图片 ID 查找对应元素</li><li>使用 <code>closest(&#39;a&#39;)</code> 找到外层链接并绑定点击事件</li><li><code>e.preventDefault()</code> 阻止默认跳转行为</li><li>调用 <code>switchToTheme</code> 切换主题并显示提示</li></ul><h4 id="2-3-初始化和-PJAX-支持"><a href="#2-3-初始化和-PJAX-支持" class="headerlink" title="2.3 初始化和 PJAX 支持"></a>2.3 初始化和 PJAX 支持</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="comment">// 应用用户保存的主题偏好</span></span><br><span class="line">  <span class="keyword">const</span> theme = <span class="variable language_">window</span>.<span class="property">localStorage</span>.<span class="title function_">getItem</span>(<span class="string">&#x27;Stellar.theme&#x27;</span>)</span><br><span class="line">  <span class="keyword">if</span> (theme !== <span class="literal">null</span>) &#123;</span><br><span class="line">    <span class="title function_">applyTheme</span>(theme)</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    utils.<span class="property">dark</span>.<span class="property">mode</span> = <span class="variable language_">window</span>.<span class="title function_">matchMedia</span>(<span class="string">&quot;(prefers-color-scheme: dark)&quot;</span>).<span class="property">matches</span> ? <span class="string">&quot;dark&quot;</span> : <span class="string">&quot;light&quot;</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  utils.<span class="property">dark</span>.<span class="property">method</span>.<span class="property">toggle</span>.<span class="title function_">start</span>();</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 绑定主题切换按钮</span></span><br><span class="line">  <span class="title function_">bindThemeButtons</span>()</span><br><span class="line">&#125;)()</span><br><span class="line"></span><br><span class="line"><span class="comment">// PJAX 后重新绑定按钮（Stellar 使用 PJAX 实现无刷新导航）</span></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;pjax:complete&#x27;</span>, bindThemeButtons)</span><br></pre></td></tr></table></figure><h2 id="配置说明"><a href="#配置说明" class="headerlink" title="配置说明"></a>配置说明</h2><h3 id="1-在-config-stellar-yml-中配置导航栏按钮"><a href="#1-在-config-stellar-yml-中配置导航栏按钮" class="headerlink" title="1. 在 _config.stellar.yml 中配置导航栏按钮"></a>1. 在 <code>_config.stellar.yml</code> 中配置导航栏按钮</h3><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">nav:</span></span><br><span class="line">  <span class="attr">left:</span></span><br><span class="line">    <span class="comment"># 其他导航项...</span></span><br><span class="line">    <span class="attr">Moon:</span></span><br><span class="line">      <span class="attr">icon:</span> <span class="string">&#x27;&lt;img id=&quot;ThemeM&quot; src=&quot;https://upyun.thatcdn.cn/public/img/icon/Moon.png&quot;/&gt;&#x27;</span></span><br><span class="line">      <span class="attr">url:</span> <span class="string">javaScript:void(&#x27;永夜&#x27;);</span></span><br><span class="line">    <span class="attr">Sun:</span></span><br><span class="line">      <span class="attr">icon:</span> <span class="string">&#x27;&lt;img id=&quot;ThemeL&quot; src=&quot;https://upyun.thatcdn.cn/public/img/icon/Sun.png&quot;/&gt;&#x27;</span></span><br><span class="line">      <span class="attr">url:</span> <span class="string">javaScript:void(&#x27;永昼&#x27;);</span></span><br><span class="line">    <span class="attr">AI:</span></span><br><span class="line">      <span class="attr">icon:</span> <span class="string">&#x27;&lt;img id=&quot;ThemeAI&quot; src=&quot;https://upyun.thatcdn.cn/public/img/icon/AI.png&quot;/&gt;&#x27;</span></span><br><span class="line">      <span class="attr">url:</span> <span class="string">javaScript:void(&#x27;跟随系统&#x27;);</span></span><br></pre></td></tr></table></figure><p><strong>关键点：</strong></p><ul><li><code>id=&quot;ThemeM&quot;</code>：月亮按钮（深色模式）</li><li><code>id=&quot;ThemeL&quot;</code>：太阳按钮（浅色模式）</li><li><code>id=&quot;ThemeAI&quot;</code>：AI 按钮（跟随系统）</li><li><code>url: javaScript:void(&#39;...&#39;)</code>：阻止默认跳转</li></ul><h3 id="2-主题偏好设置"><a href="#2-主题偏好设置" class="headerlink" title="2. 主题偏好设置"></a>2. 主题偏好设置</h3><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">style:</span></span><br><span class="line">  <span class="attr">prefers_theme:</span> <span class="string">auto</span> <span class="comment"># auto / light / dark</span></span><br><span class="line">  <span class="attr">smooth_scroll:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><ul><li><code>auto</code>：跟随系统</li><li><code>light</code>：强制浅色</li><li><code>dark</code>：强制深色</li></ul><h2 id="技术细节"><a href="#技术细节" class="headerlink" title="技术细节"></a>技术细节</h2><h3 id="1-Toast-提示实现"><a href="#1-Toast-提示实现" class="headerlink" title="1. Toast 提示实现"></a>1. Toast 提示实现</h3><p>Stellar 主题内置了 <code>hud.toast</code> 函数：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> hud = &#123;</span><br><span class="line">  <span class="attr">toast</span>: <span class="function">(<span class="params">msg, duration</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> d = <span class="title class_">Number</span>(<span class="built_in">isNaN</span>(duration) ? <span class="number">2000</span> : duration);</span><br><span class="line">    <span class="keyword">var</span> el = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;div&#x27;</span>);</span><br><span class="line">    el.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&#x27;toast&#x27;</span>);</span><br><span class="line">    el.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&#x27;show&#x27;</span>);</span><br><span class="line">    el.<span class="property">innerHTML</span> = msg;</span><br><span class="line">    <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(el);</span><br><span class="line"></span><br><span class="line">    <span class="built_in">setTimeout</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123; <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">removeChild</span>(el) &#125;, d);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>特点：</strong></p><ul><li>默认显示 2 秒（可自定义）</li><li>自动添加和移除 DOM 元素</li><li>CSS 动画控制显示&#x2F;隐藏效果</li></ul><h3 id="2-主题状态管理"><a href="#2-主题状态管理" class="headerlink" title="2. 主题状态管理"></a>2. 主题状态管理</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">utils.<span class="property">dark</span> = &#123;</span><br><span class="line">  <span class="attr">mode</span>: <span class="string">&#x27;light&#x27;</span>, <span class="comment">// 当前模式</span></span><br><span class="line">  <span class="attr">method</span>: &#123;</span><br><span class="line">    <span class="attr">toggle</span>: <span class="keyword">new</span> <span class="title class_">RunItem</span>() <span class="comment">// 切换时的回调队列</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">push</span>: <span class="function">(<span class="params">fn</span>) =&gt;</span> utils.<span class="property">dark</span>.<span class="property">method</span>.<span class="property">toggle</span>.<span class="title function_">push</span>(fn) <span class="comment">// 添加回调</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>切换主题时会自动触发所有注册的回调函数，用于更新组件状态。</p><h3 id="3-本地存储"><a href="#3-本地存储" class="headerlink" title="3. 本地存储"></a>3. 本地存储</h3><p>使用 <code>localStorage</code> 保存用户偏好：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">localStorage</span>.<span class="title function_">setItem</span>(<span class="string">&#x27;Stellar.theme&#x27;</span>, theme)</span><br><span class="line"><span class="keyword">const</span> theme = <span class="variable language_">window</span>.<span class="property">localStorage</span>.<span class="title function_">getItem</span>(<span class="string">&#x27;Stellar.theme&#x27;</span>)</span><br></pre></td></tr></table></figure><p><strong>优势：</strong></p><ul><li>持久化存储，刷新页面不丢失</li><li>每个域名独立存储</li><li>容量 5MB，足够存储配置</li></ul><h2 id="自定义提示消息"><a href="#自定义提示消息" class="headerlink" title="自定义提示消息"></a>自定义提示消息</h2><p>如果想修改提示消息的内容或显示时长，可以修改 <code>switchToTheme</code> 函数：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">switchToTheme</span> = (<span class="params">theme, message, duration = <span class="number">3000</span></span>) =&gt; &#123;</span><br><span class="line">  <span class="comment">// ... 其他代码</span></span><br><span class="line">  hud?.<span class="property">toast</span>?.(message, duration) <span class="comment">// 自定义显示时长</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>或者自定义 Toast 样式：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.toast</span> &#123;</span><br><span class="line">  <span class="attribute">position</span>: fixed;</span><br><span class="line">  <span class="attribute">top</span>: <span class="number">80px</span>;</span><br><span class="line">  <span class="attribute">left</span>: <span class="number">50%</span>;</span><br><span class="line">  <span class="attribute">transform</span>: <span class="built_in">translateX</span>(-<span class="number">50%</span>);</span><br><span class="line">  <span class="attribute">background</span>: <span class="built_in">rgba</span>(<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0.8</span>);</span><br><span class="line">  <span class="attribute">color</span>: white;</span><br><span class="line">  <span class="attribute">padding</span>: <span class="number">12px</span> <span class="number">24px</span>;</span><br><span class="line">  <span class="attribute">border-radius</span>: <span class="number">8px</span>;</span><br><span class="line">  <span class="attribute">font-size</span>: <span class="number">14px</span>;</span><br><span class="line">  <span class="attribute">z-index</span>: <span class="number">9999</span>;</span><br><span class="line">  <span class="attribute">transition</span>: opacity <span class="number">0.3s</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.toast</span><span class="selector-class">.show</span> &#123;</span><br><span class="line">  <span class="attribute">opacity</span>: <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="扩展功能"><a href="#扩展功能" class="headerlink" title="扩展功能"></a>扩展功能</h2><h3 id="1-添加更多主题模式"><a href="#1-添加更多主题模式" class="headerlink" title="1. 添加更多主题模式"></a>1. 添加更多主题模式</h3><p>可以扩展为支持更多模式（如护眼模式、阅读模式等）：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">switchToTheme</span> = (<span class="params">theme, message</span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">if</span> (theme === <span class="string">&#x27;eye-protect&#x27;</span>) &#123;</span><br><span class="line">    <span class="variable language_">document</span>.<span class="property">documentElement</span>.<span class="title function_">setAttribute</span>(<span class="string">&#x27;data-theme&#x27;</span>, <span class="string">&#x27;eye-protect&#x27;</span>)</span><br><span class="line">    <span class="comment">// 添加特定样式</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="2-同步到后端"><a href="#2-同步到后端" class="headerlink" title="2. 同步到后端"></a>2. 同步到后端</h3><p>如果需要跨设备同步主题偏好：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title function_">switchToTheme</span> = (<span class="params">theme, message</span>) =&gt; &#123;</span><br><span class="line">  <span class="comment">// ... 应用主题</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 同步到后端</span></span><br><span class="line">  <span class="title function_">fetch</span>(<span class="string">&#x27;/api/user/preferences&#x27;</span>, &#123;</span><br><span class="line">    <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">    <span class="attr">body</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(&#123; theme &#125;)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="3-快捷键支持"><a href="#3-快捷键支持" class="headerlink" title="3. 快捷键支持"></a>3. 快捷键支持</h3><p>添加键盘快捷键快速切换：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;keydown&#x27;</span>, <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">if</span> (e.<span class="property">ctrlKey</span> &amp;&amp; e.<span class="property">key</span> === <span class="string">&#x27;t&#x27;</span>) &#123;</span><br><span class="line">    <span class="comment">// Ctrl+T 切换主题</span></span><br><span class="line">    <span class="title function_">switchTheme</span>()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过以上实现，我们为 Hexo Stellar 博客主题添加了一个功能完善、用户体验良好的主题切换功能：</p><p>✅ <strong>三个独立按钮</strong>：分别控制深色、浅色、跟随系统<br>✅ <strong>即时反馈</strong>：切换时显示 Toast 提示<br>✅ <strong>持久化</strong>：记住用户偏好<br>✅ <strong>完整适配</strong>：所有组件自动适配明暗主题<br>✅ <strong>PJAX 支持</strong>：无刷新导航后功能正常  </p><p>这个功能不仅提升了用户体验，也展示了 Stellar 主题强大的可扩展性。你可以根据自己的需求进一步定制和扩展这个功能。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul><li><a href="https://xaoxuu.com/wiki/stellar/">Stellar 主题文档</a></li><li><a href="https://github.com/xaoxuu/hexo-theme-stellar">Stellar GitHub 仓库</a></li><li><a href="https://hexo.io/zh-cn/">Hexo 官方文档</a></li></ul><hr><p><strong>作者</strong>: [你的名字]<br><strong>发布日期</strong>: 2026-04-25<br><strong>本文链接</strong>: &#x2F;2026&#x2F;04&#x2F;25&#x2F;theme-switch-guide&#x2F;</p>]]>
    </content>
    <id>https://blog.kemiaosw.top/posts/bbad5266</id>
    <link href="https://blog.kemiaosw.top/posts/bbad5266"/>
    <published>2026-04-25T07:30:00.000Z</published>
    <summary>详细介绍如何在 Hexo Stellar 博客主题中实现明暗模式切换功能，包含完整的代码实现和配置说明。</summary>
    <title>Hexo Stellar 主题明暗模式切换功能实现指南</title>
    <updated>2026-04-30T05:53:47.322Z</updated>
  </entry>
</feed>
