<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/templates/atom.xsl" ?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>LeoC</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://blog.didabi.cloud/</id>
  <link href="https://blog.didabi.cloud/" rel="alternate"/>
  <link href="https://blog.didabi.cloud/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, LeoC</rights>
  <subtitle>第五局的间隙 | 记下那些比永远多一天的琐事</subtitle>
  <title>六月の余白</title>
  <updated>2026-04-23T05:13:50.521Z</updated>
  <entry>
    <author>
      <name>LeoC</name>
    </author>
    <category term="Hello" scheme="https://blog.didabi.cloud/categories/Hello/"/>
    <category term="hexo" scheme="https://blog.didabi.cloud/tags/hexo/"/>
    <category term="stellar" scheme="https://blog.didabi.cloud/tags/stellar/"/>
    <content>
      <![CDATA[<p>Stellar 主题完全满足了我的两个需求：一是 wiki 功能（这也是 Stellar 主题最大的卖点），第二个就是简洁，比起臃肿的 anzhiyu 主题，真的轻量化。</p><p>本来不打算修改任何主题文件，但是玩了一个多星期后，真的有些功能还是决定加上，就开了这个文章，作为索引，汇总一下修改内容。</p><details class="tag-plugin colorful folding" ><summary><p>规避直接修改主题文件办法</p></summary><div class="body"><p>很简单的做法，直接利用 <code>hexo.theme.setView()</code>，在渲染前覆盖主题模板内容。把之前写的模板替换脚本直接拷过来：</p> <figure class="highlight js"><figcaption><span>/scripts/theme-override.js</span></figcaption><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">&#x27;fs&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">&#x27;path&#x27;</span>);</span><br><span class="line"></span><br><span class="line">hexo.<span class="title function_">on</span>(<span class="string">&#x27;generateBefore&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> themeLayoutDir = path.<span class="title function_">join</span>(hexo.<span class="property">theme_dir</span>, <span class="string">&#x27;layout&#x27;</span>);</span><br><span class="line">  <span class="keyword">const</span> customLayoutDir = path.<span class="title function_">join</span>(hexo.<span class="property">base_dir</span>, <span class="string">&#x27;layout&#x27;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">walkDir</span>(<span class="params">dir, baseDir, fileList = []</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!fs.<span class="title function_">existsSync</span>(dir)) <span class="keyword">return</span> fileList;</span><br><span class="line">    fs.<span class="title function_">readdirSync</span>(dir).<span class="title function_">forEach</span>(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> full = path.<span class="title function_">join</span>(dir, item);</span><br><span class="line">      <span class="keyword">if</span> (fs.<span class="title function_">statSync</span>(full).<span class="title function_">isDirectory</span>()) &#123;</span><br><span class="line">        <span class="title function_">walkDir</span>(full, baseDir, fileList);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        fileList.<span class="title function_">push</span>(&#123; full, <span class="attr">relative</span>: path.<span class="title function_">relative</span>(baseDir, full).<span class="title function_">replace</span>(<span class="regexp">/\\/g</span>, <span class="string">&#x27;/&#x27;</span>) &#125;);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">return</span> fileList;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">walkDir</span>(customLayoutDir, customLayoutDir).<span class="title function_">forEach</span>(<span class="function">(<span class="params">&#123; full, relative &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(path.<span class="title function_">join</span>(themeLayoutDir, relative))) &#123;</span><br><span class="line">      hexo.<span class="property">theme</span>.<span class="title function_">setView</span>(relative, fs.<span class="title function_">readFileSync</span>(full, <span class="string">&#x27;utf-8&#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> </div></details><details class="tag-plugin colorful folding" ><summary><p><strong><a href="https://github.com/xaoxuu/hexo-theme-stellar/issues/662">#662：侧边栏时间轴在 PJAX 跳转后重复加载的问题</a></strong></p></summary><div class="body"><figure class="highlight diff"><figcaption><span>/source/js/plugins/pjax.js</span></figcaption><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></pre></td><td class="code"><pre><span class="line">                if (op &amp;&amp; np) &#123;</span><br><span class="line">                  if (part <span class="comment">=== &#x27;.widgets&#x27;) &#123;</span></span><br><span class="line"><span class="deletion">-                    const savedScrollTop = op.scrollTop || 0;</span></span><br><span class="line"><span class="deletion">-                    const oldChildren = Array.from(op.children);</span></span><br><span class="line"><span class="deletion">-                    const newChildren = Array.from(np.children);</span></span><br><span class="line"><span class="deletion">-</span></span><br><span class="line"><span class="deletion">-                    // Simple positional merger for performance and order preservation</span></span><br><span class="line"><span class="deletion">-                    const maxLength = Math.max(oldChildren.length, newChildren.length);</span></span><br><span class="line"><span class="deletion">-                    for (let i = 0; i &lt; maxLength; i++) &#123;</span></span><br><span class="line"><span class="deletion">-                      const oc = oldChildren[i];</span></span><br><span class="line"><span class="deletion">-                      const nc = newChildren[i];</span></span><br><span class="line"><span class="deletion">-                      if (oc &amp;&amp; nc) &#123;</span></span><br><span class="line"><span class="deletion">-                        if (!isWidgetIdentical(oc, nc)) &#123;</span></span><br><span class="line"><span class="deletion">-                          oc.replaceWith(nc);</span></span><br><span class="line"><span class="deletion">-                        &#125;</span></span><br><span class="line"><span class="deletion">-                      &#125; else if (oc) &#123;</span></span><br><span class="line"><span class="deletion">-                        oc.remove();</span></span><br><span class="line"><span class="deletion">-                      &#125; else if (nc) &#123;</span></span><br><span class="line"><span class="deletion">-                        op.appendChild(nc);</span></span><br><span class="line"><span class="deletion">-                      &#125;</span></span><br><span class="line"><span class="deletion">-                    &#125;</span></span><br><span class="line"><span class="deletion">-                    // 恢复滚动位置（在 DOM 更新后重新获取引用）</span></span><br><span class="line"><span class="deletion">-                    const widgetsContainer = oSide.querySelector(&#x27;.widgets&#x27;);</span></span><br><span class="line"><span class="deletion">-                    if (widgetsContainer) &#123;</span></span><br><span class="line"><span class="deletion">-                      widgetsContainer.style.scrollBehavior = &#x27;auto&#x27;;</span></span><br><span class="line"><span class="deletion">-                      widgetsContainer.scrollTop = savedScrollTop;</span></span><br><span class="line"><span class="deletion">-                      // 延迟恢复 scroll-behavior 以确保滚动完成</span></span><br><span class="line"><span class="deletion">-                      requestAnimationFrame(() =&gt; &#123;</span></span><br><span class="line"><span class="deletion">-                        widgetsContainer.style.scrollBehavior = &#x27;&#x27;;</span></span><br><span class="line"><span class="deletion">-                      &#125;);</span></span><br><span class="line"><span class="deletion">-                    &#125;</span></span><br><span class="line"><span class="addition">+                    if (op &amp;&amp; np) &#123;</span></span><br><span class="line"><span class="addition">+                      op.replaceWith(np);</span></span><br><span class="line"><span class="addition">+                    &#125; else if (op) &#123;</span></span><br><span class="line"><span class="addition">+                      op.remove();</span></span><br><span class="line"><span class="addition">+                    &#125; else if (np) &#123;</span></span><br><span class="line"><span class="addition">+                      oSide.appendChild(np);</span></span><br><span class="line"><span class="addition">+                    &#125;</span></span><br><span class="line">                  &#125; else &#123;</span><br></pre></td></tr></table></figure> </div></details><details class="tag-plugin colorful folding" ><summary><p><strong><a href="https://github.com/xaoxuu/hexo-theme-stellar/pull/664">#664：feature: 新增文章页字数统计功能</a></strong></p></summary><div class="body"><p>Resolves #302</p> <p><strong>功能说明</strong></p> <p>通过调用 <a href="https://github.com/willin/hexo-wordcount">hexo-wordcount</a> 插件，为博客文章添加：</p> <ul> <li><p>文章页字数统计：在文章顶部信息栏显示正文总字数。</p> </li> <li><p>文章页阅读时长估算：根据设定的阅读速度（默认 300 字&#x2F;分钟，英文减半）计算并显示预计阅读时间。</p> </li> <li><p>首页文章卡片字数统计：每篇文章卡片上显示字数图标和字数。</p> </li> </ul> <p><strong>使用前提</strong></p> <p>安装 hexo-wordcount 插件：<code>npm install hexo-wordcount --save</code>。</p> <p>已经在包管理里集成了插件依赖，安装命令可简化：<code>npm install</code>。</p> <p><strong>配置方式</strong></p> <p>在主题配置文件 <code>_config.stellar.yml</code> 中添加以下字段：</p> <figure class="highlight yml"><figcaption><span>/_config.stellar.yml</span></figcaption><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">wordcount:</span> <span class="comment"># 需要安装 hexo-wordcount 插件</span></span><br><span class="line">  <span class="attr">card_wordcount:</span> <span class="literal">true</span>     <span class="comment"># 首页文章卡是否显示字数</span></span><br><span class="line">  <span class="attr">post_wordcount:</span> <span class="literal">true</span>     <span class="comment"># 文章页是否显示字数</span></span><br><span class="line">  <span class="attr">reading_speed:</span> <span class="number">300</span>       <span class="comment"># 每分钟阅读字数（中文）</span></span><br><span class="line">  <span class="attr">min2read:</span> <span class="literal">true</span>           <span class="comment"># 是否显示阅读时间</span></span><br></pre></td></tr></table></figure>  <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></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#post-count</span> <span class="selector-tag">svg</span> &#123;</span><br><span class="line">    <span class="attribute">display</span>: none;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>  <p><strong>涉及文件</strong></p> <table> <thead> <tr> <th>文件路径</th> <th>修改说明</th> </tr> </thead> <tbody><tr> <td><code>config.yml</code></td> <td>新增 wordcount 配置段</td> </tr> <tr> <td><code>layout/_partial/main/navbar/article_banner.ejs</code></td> <td>引入 countinfo 局部模板</td> </tr> <tr> <td><code>layout/partial/main/navbar/countinfo.ejs</code></td> <td>文章页字数和阅读时长</td> </tr> <tr> <td><code>layout/partial/main/post_list/post_card.ejs</code></td> <td>卡片中增加字数显示</td> </tr> <tr> <td><code>languages/*</code></td> <td>多语言适配</td> </tr> <tr> <td><code>package.json</code></td> <td>默认 hexo-wordcount 插件依赖</td> </tr> </tbody></table> </div></details>]]>
    </content>
    <id>https://blog.didabi.cloud/posts/519005143/</id>
    <link href="https://blog.didabi.cloud/posts/519005143/"/>
    <published>2026-04-15T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>Stellar 主题完全满足了我的两个需求：一是 wiki 功能（这也是 Stellar 主题最大的卖点），第二个就是简洁，比起臃肿的 anzhiyu 主题，真的轻量化。</p>
<p>本来不打算修改任何主题文件，但是玩了一个多星期后，真的有些功能还是决定加上，就开了这个文]]>
    </summary>
    <title>Stellar 主题修改</title>
    <updated>2026-04-23T05:13:50.521Z</updated>
  </entry>
  <entry>
    <author>
      <name>LeoC</name>
    </author>
    <category term="Hello" scheme="https://blog.didabi.cloud/categories/Hello/"/>
    <category term="hexo" scheme="https://blog.didabi.cloud/tags/hexo/"/>
    <category term="stellar" scheme="https://blog.didabi.cloud/tags/stellar/"/>
    <content>
      <![CDATA[<p>在鼓捣了一段时间 butteryfly、heo 系主题后，审美疲劳，同时烦透了”臃肿”的主题，回归简洁吧。</p><h2 id="博客框架"><a href="#博客框架" class="headerlink" title="博客框架"></a>博客框架</h2><p>基于<a href="https://hexo.io/">Hexo</a>。</p><h2 id="主题代码"><a href="#主题代码" class="headerlink" title="主题代码"></a>主题代码</h2><p><a href="https://github.com/xaoxuu/hexo-theme-stellar/">Stellar</a> 主题：</p><p>一些案例：</p><ul><li><a href="https://xaoxuu.com/">xaoxuu</a>：主题创建者<ul><li><a href="https://xaoxuu.com/wiki/stellar/">官方文档</a></li><li><a href="https://github.com/xaoxuu/hexo-theme-stellar-examples/">官方示例</a></li></ul></li><li><a href="https://log.cns.red/">钟意博客</a></li><li><a href="https://cn.5mg.fun/">薩魔5mg</a></li><li><a href="https://blog.hzchu.top/">Thun888</a></li><li><a href="https://www.chenliss.cn/">二月初二</a></li><li><a href="https://www.cayzlh.com/">CAYZLH</a></li><li><a href="https://blog.xiaohanys.top/">XiaoHanYS</a></li><li><a href="https://dusays.com/">杜老师说</a></li><li><a href="https://blog.bxzdyg.cn/">BoBoBlog</a></li><li><a href="https://lingjun.life/">Jun</a></li><li><a href="https://www.xscnet.cn/">壹人小站</a></li></ul>]]>
    </content>
    <id>https://blog.didabi.cloud/posts/3145260216/</id>
    <link href="https://blog.didabi.cloud/posts/3145260216/"/>
    <published>2026-04-04T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>在鼓捣了一段时间 butteryfly、heo 系主题后，审美疲劳，同时烦透了”臃肿”的主题，回归简洁吧。</p>
<h2 id="博客框架"><a href="#博客框架" class="headerlink" title="博客框架"></a>博客框架</h2><p>基]]>
    </summary>
    <title>Stellar 主题</title>
    <updated>2026-04-23T05:13:50.521Z</updated>
  </entry>
  <entry>
    <author>
      <name>LeoC</name>
    </author>
    <category term="Hello" scheme="https://blog.didabi.cloud/categories/Hello/"/>
    <category term="World" scheme="https://blog.didabi.cloud/categories/Hello/World/"/>
    <category term="hexo" scheme="https://blog.didabi.cloud/tags/hexo/"/>
    <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.didabi.cloud/posts/1243066710/</id>
    <link href="https://blog.didabi.cloud/posts/1243066710/"/>
    <published>2026-03-28T16:00:00.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> for]]>
    </summary>
    <title>Hello World</title>
    <updated>2026-04-23T05:13:50.521Z</updated>
  </entry>
  <entry>
    <author>
      <name>LeoC</name>
    </author>
    <category term="hexo" scheme="https://blog.didabi.cloud/tags/hexo/"/>
    <category term="anzhiyu" scheme="https://blog.didabi.cloud/tags/anzhiyu/"/>
    <content>
      <![CDATA[<h2 id="开发思路"><a href="#开发思路" class="headerlink" title="开发思路"></a>开发思路</h2><p>这今天利用安知鱼主题的 timeline 标签来整理大叔<a href="/wiki/timeline">作品年表</a>。时间跨度从 1951 年至今，条目众多，想着要不搞个筛选器，分门别类显示，应该还不错。老规矩，说干就干。</p><p>流程分析：</p><ul><li>建立筛选器：在对应页面插入<code>&lt;button&gt;</code>，通过添加 <code>active</code> 类显示激活</li><li>建立按钮关联：建立 <code>bindFilterButtons()</code></li><li>筛选条件：在每条内容里添加个图标作为筛选条件 <code>getCategoryFromIcon(icon)</code>，返回筛选类别</li><li>进行筛选：<code>filterTimeline(category)</code> 给对应的 <code>category</code> 打上 <code>hidden</code> 类</li><li>pjax 处理</li></ul><p>不算复杂，快速搞定。等下，做都做了，给站点<a href="/updates/">更新记录</a>也加上这个功能吧，但是更新记录用图标不太得劲，改为文字标题吧，加一个 <code>getCategoryFromText(text)</code>。再等下，顺便做个计数器吧，给各个分类做个统计 <code>updateFilterCounts()</code>。</p><p>行了，测试通过。</p><p>但是，漫画类还是太长了，在底部同步加个筛选器吧。额……为啥头尾的筛选器不同步？得，接着改，来个 <code>syncActiveButtons()</code>。</p><h2 id="最终成果"><a href="#最终成果" class="headerlink" title="最终成果"></a>最终成果</h2><div class="tag-plugin tabs"id="tab_1"><div class="nav-tabs"><div class="tab active"><a href="#tab_1-1">_config.anzhiyu.yml</a></div><div class="tab"><a href="#tab_1-2">timeline-filter.js</a></div><div class="tab"><a href="#tab_1-3">timeline-filter.css</a></div><div class="tab"><a href="#tab_1-4">.md 调用</a></div></div><div class="tab-content"><div class="tab-pane active" id="tab_1-1"><figure class="highlight yml"><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">&lt;link</span> <span class="string">rel=&quot;stylesheet&quot;</span> <span class="string">href=&quot;/css/timeline-filter.css&quot;&gt;</span></span><br><span class="line">    <span class="attr">bottom:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">&lt;script</span> <span class="string">src=&quot;/js/timeline-filter.js&quot;&gt;&lt;/script&gt;</span></span><br></pre></td></tr></table></figure><!-- endtab --></div><div class="tab-pane" id="tab_1-2"><figure class="highlight js"><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><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</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="keyword">function</span> <span class="title function_">getCategoryFromIcon</span>(<span class="params">spanElem</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> classNames = spanElem.<span class="property">className</span>.<span class="title function_">split</span>(<span class="regexp">/\s+/</span>);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> cls <span class="keyword">of</span> classNames) &#123;</span><br><span class="line">      <span class="keyword">if</span> (cls.<span class="title function_">startsWith</span>(<span class="string">&#x27;icon-&#x27;</span>)) &#123;</span><br><span class="line">        <span class="keyword">return</span> cls.<span class="title function_">replace</span>(<span class="regexp">/^icon-/</span>, <span class="string">&#x27;&#x27;</span>).<span class="title function_">toLowerCase</span>();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</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="keyword">function</span> <span class="title function_">getCategoryFromText</span>(<span class="params">textElem</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> text = textElem.<span class="property">innerText</span>.<span class="title function_">trim</span>();</span><br><span class="line">    text = text.<span class="title function_">replace</span>(<span class="regexp">/[：:、\s]+$/</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">    <span class="keyword">return</span> text.<span class="title function_">toLowerCase</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_">findItemCategories</span>(<span class="params">item</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> categories = <span class="keyword">new</span> <span class="title class_">Set</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> textElems = item.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.timeline-item-content strong&#x27;</span>);</span><br><span class="line">    textElems.<span class="title function_">forEach</span>(<span class="function"><span class="params">elem</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> cat = <span class="title function_">getCategoryFromText</span>(elem);</span><br><span class="line">      <span class="keyword">if</span> (cat) categories.<span class="title function_">add</span>(cat);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (categories.<span class="property">size</span> === <span class="number">0</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> spans = item.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.timeline-item-content span&#x27;</span>);</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> span <span class="keyword">of</span> spans) &#123;</span><br><span class="line">        <span class="keyword">const</span> cat = <span class="title function_">getCategoryFromIcon</span>(span);</span><br><span class="line">        <span class="keyword">if</span> (cat) categories.<span class="title function_">add</span>(cat);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Array</span>.<span class="title function_">from</span>(categories);</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_">filterTimeline</span>(<span class="params">category</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> effectiveCategory = category;</span><br><span class="line">    <span class="keyword">if</span> (category !== <span class="string">&#x27;all&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (category.<span class="title function_">startsWith</span>(<span class="string">&#x27;icon &#x27;</span>) || category.<span class="title function_">startsWith</span>(<span class="string">&#x27;text &#x27;</span>)) &#123;</span><br><span class="line">        effectiveCategory = category.<span class="title function_">substring</span>(<span class="number">5</span>);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        effectiveCategory = category;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    effectiveCategory = effectiveCategory.<span class="title function_">trim</span>().<span class="title function_">toLowerCase</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> containers = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.timeline&#x27;</span>);</span><br><span class="line">    containers.<span class="title function_">forEach</span>(<span class="function"><span class="params">container</span> =&gt;</span> &#123;</span><br><span class="line">      container.<span class="property">style</span>.<span class="property">display</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">let</span> hasMatch = <span class="literal">false</span>;</span><br><span class="line">      <span class="keyword">const</span> items = container.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.timeline-item&#x27;</span>);</span><br><span class="line">      items.<span class="title function_">forEach</span>(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (item.<span class="property">classList</span>.<span class="title function_">contains</span>(<span class="string">&#x27;headline&#x27;</span>)) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> itemCategories = <span class="title function_">findItemCategories</span>(item);</span><br><span class="line">        <span class="keyword">const</span> hasIdentifier = itemCategories.<span class="property">length</span> &gt; <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">if</span> (!hasIdentifier) &#123;</span><br><span class="line">          item.<span class="property">style</span>.<span class="property">display</span> = (category === <span class="string">&#x27;all&#x27;</span>) ? <span class="string">&#x27;&#x27;</span> : <span class="string">&#x27;none&#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">        <span class="keyword">const</span> matches = (category === <span class="string">&#x27;all&#x27;</span>) || itemCategories.<span class="title function_">includes</span>(effectiveCategory);</span><br><span class="line">        <span class="keyword">if</span> (matches) &#123;</span><br><span class="line">          hasMatch = <span class="literal">true</span>;</span><br><span class="line">          item.<span class="property">style</span>.<span class="property">display</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          item.<span class="property">style</span>.<span class="property">display</span> = <span class="string">&#x27;none&#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">const</span> headline = container.<span class="title function_">querySelector</span>(<span class="string">&#x27;.timeline-item.headline&#x27;</span>);</span><br><span class="line">      <span class="keyword">if</span> (headline) &#123;</span><br><span class="line">        headline.<span class="property">style</span>.<span class="property">display</span> = (category === <span class="string">&#x27;all&#x27;</span> || hasMatch) ? <span class="string">&#x27;&#x27;</span> : <span class="string">&#x27;none&#x27;</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">if</span> (category !== <span class="string">&#x27;all&#x27;</span> &amp;&amp; !hasMatch) &#123;</span><br><span class="line">        container.<span class="property">style</span>.<span class="property">display</span> = <span class="string">&#x27;none&#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">const</span> allContainers = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.timeline&#x27;</span>);</span><br><span class="line">    <span class="keyword">let</span> firstVisible = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; allContainers.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="keyword">if</span> (allContainers[i].<span class="property">style</span>.<span class="property">display</span> !== <span class="string">&#x27;none&#x27;</span>) &#123;</span><br><span class="line">        firstVisible = allContainers[i];</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    allContainers.<span class="title function_">forEach</span>(<span class="function"><span class="params">container</span> =&gt;</span> &#123;</span><br><span class="line">      container.<span class="property">style</span>.<span class="property">marginTop</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">if</span> (firstVisible &amp;&amp; <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;.category-filter&#x27;</span>)) &#123;</span><br><span class="line">      firstVisible.<span class="property">style</span>.<span class="property">marginTop</span> = <span class="string">&#x27;0&#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">function</span> <span class="title function_">bindFilterButtons</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> btns = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.filter-btn&#x27;</span>);</span><br><span class="line">    <span class="keyword">if</span> (btns.<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">    btns.<span class="title function_">forEach</span>(<span class="function"><span class="params">btn</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (btn.<span class="property">_filterBound</span>) <span class="keyword">return</span>;</span><br><span class="line">      btn.<span class="property">_filterBound</span> = <span class="literal">true</span>;</span><br><span class="line">      btn.<span class="title function_">addEventListener</span>(<span class="string">&#x27;click&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> category = <span class="variable language_">this</span>.<span class="title function_">getAttribute</span>(<span class="string">&#x27;data-category&#x27;</span>);</span><br><span class="line">        <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.filter-btn&#x27;</span>).<span class="title function_">forEach</span>(<span class="function"><span class="params">b</span> =&gt;</span> b.<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">&#x27;active&#x27;</span>));</span><br><span class="line">        <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.filter-btn&#x27;</span>).<span class="title function_">forEach</span>(<span class="function"><span class="params">b</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="keyword">if</span> (b.<span class="title function_">getAttribute</span>(<span class="string">&#x27;data-category&#x27;</span>) === category) &#123;</span><br><span class="line">            b.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&#x27;active&#x27;</span>);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="title function_">filterTimeline</span>(category);</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_">syncActiveButtons</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> activeBtn = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;.filter-btn.active&#x27;</span>);</span><br><span class="line">    <span class="keyword">if</span> (activeBtn) &#123;</span><br><span class="line">      <span class="keyword">const</span> category = activeBtn.<span class="title function_">getAttribute</span>(<span class="string">&#x27;data-category&#x27;</span>);</span><br><span class="line">      <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.filter-btn&#x27;</span>).<span class="title function_">forEach</span>(<span class="function"><span class="params">btn</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (btn.<span class="title function_">getAttribute</span>(<span class="string">&#x27;data-category&#x27;</span>) === category) &#123;</span><br><span class="line">          btn.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&#x27;active&#x27;</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          btn.<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">&#x27;active&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> allBtn = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;.filter-btn[data-category=&quot;all&quot;]&#x27;</span>);</span><br><span class="line">      <span class="keyword">if</span> (allBtn) allBtn.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&#x27;active&#x27;</span>);</span><br><span class="line">      <span class="title function_">syncActiveButtons</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">function</span> <span class="title function_">updateFilterCounts</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> containers = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.timeline&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> allItems = [];</span><br><span class="line">    containers.<span class="title function_">forEach</span>(<span class="function"><span class="params">container</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> items = container.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.timeline-item:not(.headline)&#x27;</span>);</span><br><span class="line">      items.<span class="title function_">forEach</span>(<span class="function"><span class="params">item</span> =&gt;</span> allItems.<span class="title function_">push</span>(item));</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> itemsData = allItems.<span class="title function_">map</span>(<span class="function"><span class="params">item</span> =&gt;</span> (&#123;</span><br><span class="line">      <span class="attr">item</span>: item,</span><br><span class="line">      <span class="attr">categories</span>: <span class="title function_">findItemCategories</span>(item)</span><br><span class="line">    &#125;));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> totalCount = itemsData.<span class="property">length</span>;</span><br><span class="line">    <span class="keyword">const</span> btns = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.filter-btn&#x27;</span>);</span><br><span class="line">    btns.<span class="title function_">forEach</span>(<span class="function"><span class="params">btn</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> existingCount = btn.<span class="title function_">querySelector</span>(<span class="string">&#x27;.filter-count&#x27;</span>);</span><br><span class="line">      <span class="keyword">if</span> (existingCount) existingCount.<span class="title function_">remove</span>();</span><br><span class="line"></span><br><span class="line">      <span class="keyword">let</span> count = <span class="number">0</span>;</span><br><span class="line">      <span class="keyword">const</span> category = btn.<span class="title function_">getAttribute</span>(<span class="string">&#x27;data-category&#x27;</span>);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (category === <span class="string">&#x27;all&#x27;</span>) &#123;</span><br><span class="line">        count = totalCount;</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">let</span> effectiveCategory = category;</span><br><span class="line">        <span class="keyword">if</span> (category.<span class="title function_">startsWith</span>(<span class="string">&#x27;icon &#x27;</span>) || category.<span class="title function_">startsWith</span>(<span class="string">&#x27;text &#x27;</span>)) &#123;</span><br><span class="line">          effectiveCategory = category.<span class="title function_">substring</span>(<span class="number">5</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        effectiveCategory = effectiveCategory.<span class="title function_">trim</span>().<span class="title function_">toLowerCase</span>();</span><br><span class="line">        count = itemsData.<span class="title function_">filter</span>(<span class="function"><span class="params">data</span> =&gt;</span> data.<span class="property">categories</span>.<span class="title function_">includes</span>(effectiveCategory)).<span class="property">length</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">const</span> countSpan = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;span&#x27;</span>);</span><br><span class="line">      countSpan.<span class="property">className</span> = <span class="string">&#x27;filter-count&#x27;</span>;</span><br><span class="line">      countSpan.<span class="property">textContent</span> = <span class="string">` (<span class="subst">$&#123;count&#125;</span>)`</span>;</span><br><span class="line"></span><br><span class="line">      btn.<span class="title function_">appendChild</span>(countSpan);</span><br><span class="line">      <span class="keyword">if</span> (count === <span class="number">0</span>) &#123;</span><br><span class="line">        btn.<span class="title function_">setAttribute</span>(<span class="string">&#x27;hidden&#x27;</span>, <span class="string">&#x27;hidden&#x27;</span>);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        btn.<span class="title function_">removeAttribute</span>(<span class="string">&#x27;hidden&#x27;</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="keyword">function</span> <span class="title function_">init</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">bindFilterButtons</span>();</span><br><span class="line">    <span class="title function_">syncActiveButtons</span>();</span><br><span class="line">    <span class="title function_">updateFilterCounts</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>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">      <span class="title function_">bindFilterButtons</span>();</span><br><span class="line">      <span class="title function_">syncActiveButtons</span>();</span><br><span class="line">      <span class="title function_">updateFilterCounts</span>();</span><br><span class="line">      <span class="keyword">const</span> allBtn = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;.filter-btn[data-category=&quot;all&quot;]&#x27;</span>);</span><br><span class="line">      <span class="keyword">if</span> (allBtn) allBtn.<span class="title function_">click</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> (<span class="variable language_">document</span>.<span class="property">readyState</span> === <span class="string">&#x27;loading&#x27;</span>) &#123;</span><br><span class="line">    <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;DOMContentLoaded&#x27;</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><!-- endtab --></div><div class="tab-pane" id="tab_1-3"><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></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.category-filter</span> &#123;</span><br><span class="line">    <span class="attribute">display</span>: flex;</span><br><span class="line">    <span class="attribute">flex-wrap</span>: wrap;</span><br><span class="line">    <span class="attribute">margin</span>: <span class="number">20px</span> <span class="number">0</span>;</span><br><span class="line">    <span class="attribute">gap</span>: <span class="number">12px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.category-filter</span> <span class="selector-class">.filter-btn</span> &#123;</span><br><span class="line">    <span class="attribute">padding</span>: <span class="number">6px</span> <span class="number">16px</span>;</span><br><span class="line">    <span class="attribute">border-radius</span>: <span class="number">30px</span>;</span><br><span class="line">    <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="built_in">var</span>(--anzhiyu-theme);</span><br><span class="line">    <span class="attribute">color</span>: <span class="built_in">var</span>(--anzhiyu-theme);</span><br><span class="line">    <span class="attribute">font-size</span>: <span class="number">14px</span>;</span><br><span class="line">    <span class="attribute">cursor</span>: pointer;</span><br><span class="line">    <span class="attribute">transition</span>: all <span class="number">0.2s</span> ease;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.category-filter</span> <span class="selector-class">.filter-btn</span><span class="selector-class">.active</span>,</span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.category-filter</span> <span class="selector-class">.filter-btn</span><span class="selector-pseudo">:hover</span> &#123;</span><br><span class="line">    <span class="attribute">border-color</span>: <span class="built_in">var</span>(--anzhiyu-theme);</span><br><span class="line">    <span class="attribute">background</span>: <span class="built_in">var</span>(--anzhiyu-theme);</span><br><span class="line">    <span class="attribute">color</span>: <span class="number">#fff</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.category-filter</span> <span class="selector-class">.filter-btn</span><span class="selector-class">.active</span> <span class="selector-tag">span</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">    <span class="attribute">color</span>: <span class="number">#fff</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.category-filter</span> <span class="selector-class">.filter-btn</span><span class="selector-attr">[hidden]</span> &#123;</span><br><span class="line">  <span class="attribute">display</span>: none;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.timeline</span> &#123;</span><br><span class="line">    <span class="attribute">border-left-color</span>: <span class="built_in">var</span>(--anzhiyu-theme);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.timeline</span> <span class="selector-class">.timeline-item</span><span class="selector-class">.headline</span> <span class="selector-class">.timeline-item-title</span> <span class="selector-class">.item-circle</span><span class="selector-pseudo">::before</span>,</span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.timeline</span> <span class="selector-class">.timeline-item</span> <span class="selector-class">.item-circle</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">    <span class="attribute">border-color</span>:<span class="built_in">var</span>(--anzhiyu-theme);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.timeline</span> <span class="selector-class">.timeline-item</span><span class="selector-class">.headline</span> <span class="selector-class">.timeline-item-title</span><span class="selector-pseudo">:hover</span> <span class="selector-class">.item-circle</span><span class="selector-pseudo">::before</span>,</span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.timeline</span> <span class="selector-class">.timeline-item</span><span class="selector-pseudo">:hover</span> <span class="selector-class">.item-circle</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">    <span class="attribute">border-color</span>: <span class="built_in">var</span>(--pseudo-hover);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#article-container</span> <span class="selector-class">.timeline</span> <span class="selector-class">.timeline-item</span> <span class="selector-class">.item-circle</span><span class="selector-pseudo">:not</span>(<span class="selector-pseudo">:has</span>(<span class="selector-tag">p</span>))<span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">    <span class="attribute">display</span>: none;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><!-- endtab --></div><div class="tab-pane" id="tab_1-4"><figure class="highlight md"><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="section"># example</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;category-filter&quot;</span>&gt;</span></span></span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">class</span>=<span class="string">&quot;filter-btn active&quot;</span> <span class="attr">data-category</span>=<span class="string">&quot;all&quot;</span>&gt;</span></span>全部<span class="language-xml"><span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">class</span>=<span class="string">&quot;filter-btn&quot;</span> <span class="attr">data-category</span>=<span class="string">&quot;icon book-text&quot;</span>&gt;</span></span>漫画<span class="language-xml"><span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">button</span> <span class="attr">class</span>=<span class="string">&quot;filter-btn&quot;</span> <span class="attr">data-category</span>=<span class="string">&quot;text docs&quot;</span>&gt;</span></span>记录文档<span class="language-xml"><span class="tag">&lt;/<span class="name">button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br></pre></td></tr></table></figure><!-- endtab --></div></div></div>]]>
    </content>
    <id>https://blog.didabi.cloud/posts/2070635610/</id>
    <link href="https://blog.didabi.cloud/posts/2070635610/"/>
    <published>2026-03-28T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="开发思路"><a href="#开发思路" class="headerlink" title="开发思路"></a>开发思路</h2><p>这今天利用安知鱼主题的 timeline 标签来整理大叔<a href="/wiki/timeline">作品年表</a>。]]>
    </summary>
    <title>为使用 timeline 标签功能页面增加筛选功能（安知鱼版）</title>
    <updated>2026-04-23T05:13:50.521Z</updated>
  </entry>
  <entry>
    <author>
      <name>LeoC</name>
    </author>
    <category term="hexo" scheme="https://blog.didabi.cloud/tags/hexo/"/>
    <content>
      <![CDATA[<p>闲逛<a href="https://blog.xiowo.net/">Mo 的记事簿</a>的时候，看到了页脚的宠物挂件，瞬间来了灵感，大叔刚刚重刷的 Season’s Album 封面素材，正好可以用上，所以话不多说，搞起。</p><div class="tag-plugin link dis-select"><a class="link-card plain" title="梦爱吃鱼, https://blog.bsgun.cn/posts/55b29cdb/" href="给你的博客添加一个宠物挂件," cardlink autofill="icon,desc"><div class="left"><span class="title">梦爱吃鱼, https://blog.bsgun.cn/posts/55b29cdb/</span><span class="cap link footnote">https://blog.didabi.cloud/%E7%BB%99%E4%BD%A0%E7%9A%84%E5%8D%9A%E5%AE%A2%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%E5%AE%A0%E7%89%A9%E6%8C%82%E4%BB%B6,</span></div><div class="right"><div class="lazy img" data-bg="https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.12/link/8f277b4ee0ecd.svg"></div></div></a></div><h2 id="梦爱吃鱼做法"><a href="#梦爱吃鱼做法" class="headerlink" title="梦爱吃鱼做法"></a>梦爱吃鱼做法</h2><p>简单分析一下梦爱吃鱼的做法：通过修改 “bbTimeList.pug”，在首页顶部插入挂件。页脚的做法就简单多了，直接把 “footer-animal.js” inject 进去。</p><div class="tag-plugin tabs"id="tab_2"><div class="nav-tabs"><div class="tab active"><a href="#tab_2-1">顶部挂件</a></div><div class="tab"><a href="#tab_2-2">页脚挂件</a></div></div><div class="tab-content"><div class="tab-pane active" id="tab_2-1"><p>如果是安知鱼主题，直接替换 <code>themes\anzhiyu\layout\includes\bbTimeList.pug</code> 文件。</p><figure class="highlight plaintext"><figcaption><span>bbTimeList.pug</span></figcaption><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></pre></td><td class="code"><pre><span class="line">if site.data.essay</span><br><span class="line">  each i in site.data.essay</span><br><span class="line">    if i.home_essay</span><br><span class="line">      - let onclick_value = theme.pjax.enable ? `pjax.loadUrl(&quot;/essay/&quot;);` : &#x27;&#x27;;</span><br><span class="line">      - let href_value = theme.pjax.enable ? &#x27;javascript:void(0);&#x27; : `/essay/`;</span><br><span class="line">      #bbTimeList.bbTimeList.container</span><br><span class="line">          i.anzhiyufont.anzhiyu-icon-jike.bber-logo.fontbold(onclick=onclick_value, title=&quot;即刻短文&quot;, href=href_value, aria-hidden=&quot;true&quot;)</span><br><span class="line">          #bbtalk.swiper-container.swiper-no-swiping.essay_bar_swiper_container(tabindex=&quot;-1&quot;)</span><br><span class="line">            #bber-talk.swiper-wrapper(onclick=onclick_value)</span><br><span class="line">              each i in site.data.essay</span><br><span class="line">                each item, index in i.essay_list</span><br><span class="line">                  if index &lt; 10</span><br><span class="line">                    - var contentText = item.image ? item.content + &#x27; [图片]&#x27; : (item.video ? item.content + &#x27; [视频]&#x27; : item.content)</span><br><span class="line">                    a.li-style.swiper-slide(href=href_value)= contentText</span><br><span class="line">          a.bber-gotobb.anzhiyufont.anzhiyu-icon-circle-arrow-right(onclick=onclick_value, href=href_value, title=&quot;查看全文&quot;)</span><br><span class="line">          img.con-animals.entered.loaded(id=&quot;new-con-animals&quot; src=&quot;&quot;)</span><br><span class="line">      script(src=url_for(theme.home_top.swiper.swiper_js))</span><br><span class="line"></span><br><span class="line">style.</span><br><span class="line">  #bbTimeList &#123;</span><br><span class="line">    position: relative;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  .con-animals &#123;</span><br><span class="line">    display: block;</span><br><span class="line">    position: absolute;</span><br><span class="line">    max-width: 260px;</span><br><span class="line">    top: -85px;</span><br><span class="line">    z-index: 2;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  @media screen and (max-width: 1200px) &#123;</span><br><span class="line">    .con-animals &#123;</span><br><span class="line">      display: none;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">script.</span><br><span class="line">  // 将lastImageUrl移到全局作用域</span><br><span class="line">  window.lastImageUrl = window.lastImageUrl || &#x27;&#x27;;</span><br><span class="line"></span><br><span class="line">  function setRandomImage() &#123;</span><br><span class="line">    const img = document.getElementById(&#x27;new-con-animals&#x27;);</span><br><span class="line">    const imageUrls = [</span><br><span class="line">      &quot;https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/901216.webp&quot;,</span><br><span class="line">      &quot;https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/074167.webp&quot;,</span><br><span class="line">      &quot;https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/759434.webp&quot;,</span><br><span class="line">      &quot;https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/526748.webp&quot;,</span><br><span class="line">      &quot;https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/429029.webp&quot;</span><br><span class="line">    ];</span><br><span class="line"></span><br><span class="line">    let randomImage;</span><br><span class="line">    do &#123;</span><br><span class="line">      randomImage = imageUrls[Math.floor(Math.random() * imageUrls.length)];</span><br><span class="line">    &#125; while (randomImage === window.lastImageUrl);</span><br><span class="line"></span><br><span class="line">    window.lastImageUrl = randomImage;</span><br><span class="line"></span><br><span class="line">    if (img) &#123;</span><br><span class="line">      img.src = randomImage;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  function initializeDragImage() &#123;</span><br><span class="line">    const img = document.getElementById(&#x27;new-con-animals&#x27;);</span><br><span class="line">    const container = document.getElementById(&#x27;bbTimeList&#x27;);</span><br><span class="line"></span><br><span class="line">    if (!img || !container) return;</span><br><span class="line"></span><br><span class="line">    if (!window.lastImageUrl) &#123;</span><br><span class="line">      setRandomImage();</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">      img.src = window.lastImageUrl;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    let isDragging = false, wasDragged = false, startX, startLeft;</span><br><span class="line">    const containerWidth = container.clientWidth;</span><br><span class="line">    const imgWidth = img.clientWidth;</span><br><span class="line">    const maxLeft = containerWidth - imgWidth;</span><br><span class="line">    const edgeThreshold = 20;</span><br><span class="line">    let lastLeft = parseInt(localStorage.getItem(&#x27;imgPositionLeft&#x27;)) || 0;</span><br><span class="line">    lastLeft = Math.min(maxLeft, Math.max(0, lastLeft));</span><br><span class="line">    img.style.left = `$&#123;lastLeft&#125;px`;</span><br><span class="line"></span><br><span class="line">    const savePosition = (left) =&gt; localStorage.setItem(&#x27;imgPositionLeft&#x27;, left);</span><br><span class="line"></span><br><span class="line">    img.addEventListener(&#x27;click&#x27;, () =&gt; &#123;</span><br><span class="line">      if (!wasDragged) &#123;</span><br><span class="line">        let currentLeft = lastLeft;</span><br><span class="line">        let newLeft;</span><br><span class="line"></span><br><span class="line">        if (currentLeft &lt;= edgeThreshold) &#123;</span><br><span class="line">          newLeft = Math.min(currentLeft + 200, maxLeft);</span><br><span class="line">        &#125; else if (currentLeft &gt;= maxLeft - edgeThreshold) &#123;</span><br><span class="line">          newLeft = Math.max(currentLeft - 200, 0);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">          newLeft = currentLeft + (Math.random() &lt; 0.5 ? -200 : 200);</span><br><span class="line">          newLeft = Math.max(0, Math.min(newLeft, maxLeft));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        if (newLeft !== lastLeft) &#123;</span><br><span class="line">          lastLeft = newLeft;</span><br><span class="line">          img.style.left = `$&#123;newLeft&#125;px`;</span><br><span class="line">          savePosition(newLeft);</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">    img.addEventListener(&#x27;mousedown&#x27;, (e) =&gt; &#123;</span><br><span class="line">      isDragging = true;</span><br><span class="line">      wasDragged = false;</span><br><span class="line">      startX = e.clientX;</span><br><span class="line">      startLeft = lastLeft;</span><br><span class="line">      img.style.transition = &#x27;none&#x27;;</span><br><span class="line"></span><br><span class="line">      const onMouseMove = (e) =&gt; &#123;</span><br><span class="line">        if (!isDragging) return;</span><br><span class="line">        wasDragged = true;</span><br><span class="line">        const offsetX = e.clientX - startX;</span><br><span class="line">        lastLeft = Math.max(0, Math.min(startLeft + offsetX, maxLeft));</span><br><span class="line">        requestAnimationFrame(() =&gt; &#123;</span><br><span class="line">          img.style.left = `$&#123;lastLeft&#125;px`;</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;;</span><br><span class="line"></span><br><span class="line">      const onMouseUp = () =&gt; &#123;</span><br><span class="line">        isDragging = false;</span><br><span class="line">        img.style.transition = &#x27;left 0.5s ease-in-out&#x27;;</span><br><span class="line">        savePosition(lastLeft);</span><br><span class="line">        document.removeEventListener(&#x27;mousemove&#x27;, onMouseMove);</span><br><span class="line">        document.removeEventListener(&#x27;mouseup&#x27;, onMouseUp);</span><br><span class="line">      &#125;;</span><br><span class="line"></span><br><span class="line">      document.addEventListener(&#x27;mousemove&#x27;, onMouseMove);</span><br><span class="line">      document.addEventListener(&#x27;mouseup&#x27;, onMouseUp);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  document.addEventListener(&#x27;DOMContentLoaded&#x27;, initializeDragImage);</span><br><span class="line">  document.addEventListener(&#x27;pjax:success&#x27;, initializeDragImage);</span><br><span class="line"></span><br></pre></td></tr></table></figure><!-- endtab --></div><div class="tab-pane" id="tab_2-2"><p>在 <code>_config.anzhiyu.yml</code> 的 <code>inject</code> 中指定脚本位置：<code>&lt;script src=&quot;/static/footer-animal.js&quot; defer&gt;&lt;/script&gt;</code>。新建 <code>footer-animal.js</code> 文件：</p><figure class="highlight js"><figcaption><span>footer-animal.js</span></figcaption><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">initFooterAnimal</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> footerBar = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;#footer-bar&#x27;</span>);</span><br><span class="line">    <span class="keyword">if</span> (!footerBar)</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">console</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="keyword">const</span> footerAnimal = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;div&#x27;</span>);</span><br><span class="line">    footerAnimal.<span class="property">id</span> = <span class="string">&#x27;footer-animal&#x27;</span>;</span><br><span class="line">    footerAnimal.<span class="property">innerHTML</span> = <span class="string">`</span></span><br><span class="line"><span class="string">        &lt;img class=&quot;animal entered loaded&quot;</span></span><br><span class="line"><span class="string">            src=&quot;https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/473503.webp&quot;</span></span><br><span class="line"><span class="string">            alt=&quot;动物&quot; /&gt;</span></span><br><span class="line"><span class="string">    `</span>;</span><br><span class="line"></span><br><span class="line">    footerBar.<span class="title function_">insertAdjacentElement</span>(<span class="string">&#x27;beforebegin&#x27;</span>, footerAnimal);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> style = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;style&#x27;</span>);</span><br><span class="line">    style.<span class="property">textContent</span> = <span class="string">`</span></span><br><span class="line"><span class="string">        #footer-animal &#123;</span></span><br><span class="line"><span class="string">            position: relative;</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">        #footer-animal::before &#123;</span></span><br><span class="line"><span class="string">            content: &#x27;&#x27;;</span></span><br><span class="line"><span class="string">            position: absolute;</span></span><br><span class="line"><span class="string">            bottom: 0;</span></span><br><span class="line"><span class="string">            width: 100%;</span></span><br><span class="line"><span class="string">            height: 36px;</span></span><br><span class="line"><span class="string">            background: url(https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/351933.webp) repeat center / auto 100%;</span></span><br><span class="line"><span class="string">            box-shadow: 0 4px 7px rgba(0,0,0,.15);</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">        .animal &#123;</span></span><br><span class="line"><span class="string">            position: relative;</span></span><br><span class="line"><span class="string">            max-width: min(974px, 100vw);</span></span><br><span class="line"><span class="string">            margin: 0 auto;</span></span><br><span class="line"><span class="string">            display: block;</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">        #footer-bar &#123;</span></span><br><span class="line"><span class="string">            margin-top: 0 !important;</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">        @media screen and (max-width: 1023px) &#123;</span></span><br><span class="line"><span class="string">            #footer-animal::before &#123;</span></span><br><span class="line"><span class="string">                height: 4vw;</span></span><br><span class="line"><span class="string">            &#125;</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">        [data-theme=dark] #footer-animal &#123;</span></span><br><span class="line"><span class="string">            filter: brightness(.8);</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">    `</span>;</span><br><span class="line">    <span class="variable language_">document</span>.<span class="property">head</span>.<span class="title function_">appendChild</span>(style);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;DOMContentLoaded&#x27;</span>, initFooterAnimal);</span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;pjax:success&#x27;</span>, initFooterAnimal);</span><br><span class="line"></span><br></pre></td></tr></table></figure><!-- endtab --></div></div></div><h2 id="修改思路"><a href="#修改思路" class="headerlink" title="修改思路"></a>修改思路</h2><p>首先，要修改主题文件，嗯，不能做，不能做，后期升级维护，太麻烦，老规矩，直接 inject 解决一切问题。</p><p>无论是顶部还是页脚，插入动作一致，插入 function 可以复用。稍等，顶部还是随机出现的小动物？有点意思，这个随机，页脚也能用的吧。行，先琢磨一下调用时的参数：</p><ul><li>containerId：注入的容器 ID</li><li>imgId： 图片 ID</li><li>imgUrl - 图片 URL</li><li>imgPos - 图片位置</li><li>initMode - 初始位置，left、right、random、stored</li></ul><p>顶部是查询 ID <code>bbTimeList</code>，插入 <code>&lt;img&gt;</code>，底部是插入带 <code>&lt;div&gt;</code> 包裹的 <code>&lt;img&gt;</code>，不行，得改……先自己 <code>initFooterBar()</code> 一个 <code>footerList</code>，这样插入流程就一样了。</p><p>好，结构搭好了：</p><figure class="highlight js"><figcaption><span>plugged-imgs.js</span></figcaption><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="keyword">function</span> <span class="title function_">createDraggableImage</span>(<span class="params">containerId, imgId, imgUrl, storageKey, initMode</span>) &#123;</span><br><span class="line">    ...</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_">initAll</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="title function_">initFooterBar</span>();</span><br><span class="line">  <span class="title function_">initHeaderImage</span>();</span><br><span class="line">  <span class="title function_">initFooterImage</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;DOMContentLoaded&#x27;</span>, initAll);</span><br><span class="line"><span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;pjax:success&#x27;</span>, initAll);</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>其中，<code>createDraggableImage</code> 参考梦爱吃鱼页脚的做法就可以了。</p><h3 id="顶部修改"><a href="#顶部修改" class="headerlink" title="顶部修改"></a>顶部修改</h3><p>发现一个小问题，全屏首页时，在最底部露出插入图片的一部分，看着难受，接着改吧…</p><p>本来打算直接监听滚动来隐藏图片，反复观察滚动首页时发现可以通过监听 <code>&lt;header class=&quot;full_page&quot;&gt;</code> 的 <code>class</code> 属性变化，当 <code>nav-fixed</code> 被添加或移除时，动态更新图片的 <code>hidden</code> 类。这种方式比直接监听滚动更可靠，因为它不依赖滚动事件，而是直接观察 DOM 属性的变化。好，搞起：</p><figure class="highlight js"><figcaption><span>plugged-imgs.js</span></figcaption><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">initHeaderImage</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> <span class="title class_">HeaderImageUrl</span> = <span class="variable constant_">HEADER_IMG</span>[<span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="variable constant_">HEADER_IMG</span>.<span class="property">length</span>)];</span><br><span class="line"></span><br><span class="line">  <span class="title function_">createDraggableImage</span>(</span><br><span class="line">    <span class="string">&#x27;bbTimeList&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;new-header-img&#x27;</span>,</span><br><span class="line">    <span class="title class_">HeaderImageUrl</span>,</span><br><span class="line">    <span class="string">&#x27;headerImgPos&#x27;</span>,</span><br><span class="line">    <span class="string">&#x27;stored&#x27;</span></span><br><span class="line">  );</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> headerImg = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;new-header-img&#x27;</span>);</span><br><span class="line">  <span class="keyword">const</span> headerElem = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;header.full_page&#x27;</span>);</span><br><span class="line">  <span class="keyword">if</span> (!headerImg || !headerElem) <span class="keyword">return</span>;</span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">updateImageClass</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (headerElem.<span class="property">classList</span>.<span class="title function_">contains</span>(<span class="string">&#x27;nav-fixed&#x27;</span>)) &#123;</span><br><span class="line">      headerImg.<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">&#x27;hidden&#x27;</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      headerImg.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&#x27;hidden&#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="title function_">updateImageClass</span>();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (headerObserver) headerObserver.<span class="title function_">disconnect</span>();</span><br><span class="line">  headerObserver = <span class="keyword">new</span> <span class="title class_">MutationObserver</span>(<span class="function">(<span class="params">mutations</span>) =&gt;</span> &#123;</span><br><span class="line">    mutations.<span class="title function_">forEach</span>(<span class="function">(<span class="params">mutation</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (mutation.<span class="property">type</span> === <span class="string">&#x27;attributes&#x27;</span> &amp;&amp; mutation.<span class="property">attributeName</span> === <span class="string">&#x27;class&#x27;</span>) <span class="title function_">updateImageClass</span>();</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  headerObserver.<span class="title function_">observe</span>(headerElem, &#123; <span class="attr">attributes</span>: <span class="literal">true</span> &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="页脚修改"><a href="#页脚修改" class="headerlink" title="页脚修改"></a>页脚修改</h3><p>页脚部分就简单的多了，直接一个随机函数，用洗牌算法，每次随机 1 ~ 3 个图片，像这样：</p><figure class="highlight js"><figcaption><span>plugged-imgs.js</span></figcaption><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">initFooterImage</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> footerContainer = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;footerList&#x27;</span>);</span><br><span class="line">  <span class="keyword">if</span> (!footerContainer) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> existingImages = footerContainer.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.draggable-img&#x27;</span>);</span><br><span class="line">  existingImages.<span class="title function_">forEach</span>(<span class="function"><span class="params">img</span> =&gt;</span> img.<span class="title function_">remove</span>());</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> imgCount = <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">3</span>) + <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">const</span> shuffled = [...<span class="variable constant_">FOOTER_IMG</span>];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = shuffled.<span class="property">length</span> - <span class="number">1</span>; i &gt; <span class="number">0</span>; i--) &#123;</span><br><span class="line">    <span class="keyword">const</span> j = <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * (i + <span class="number">1</span>));</span><br><span class="line">    [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">const</span> footerImgUrls = shuffled.<span class="title function_">slice</span>(<span class="number">0</span>, imgCount);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; footerImgUrls.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    <span class="title function_">createDraggableImage</span>(</span><br><span class="line">      <span class="string">&#x27;footerList&#x27;</span>,</span><br><span class="line">      <span class="string">`new-footer-img-<span class="subst">$&#123;i+<span class="number">1</span>&#125;</span>`</span>,</span><br><span class="line">      footerImgUrls[i],</span><br><span class="line">      <span class="string">`footerImgPos_<span class="subst">$&#123;i+<span class="number">1</span>&#125;</span>`</span>,</span><br><span class="line">      <span class="string">&#x27;random&#x27;</span></span><br><span class="line">    );</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="css-修改"><a href="#css-修改" class="headerlink" title="css 修改"></a>css 修改</h3><p>css 还是不集成到 js 里吧，独立管理，这样方便后续修改。都是些常规操作，只要注意下页脚图片的 <code>z-index</code> 顺序就可以了。</p><h2 id="最终成果"><a href="#最终成果" class="headerlink" title="最终成果"></a>最终成果</h2><div class="tag-plugin tabs"id="tab_3"><div class="nav-tabs"><div class="tab active"><a href="#tab_3-1">_config.anzhiyu.yml</a></div><div class="tab"><a href="#tab_3-2">plugged-imgs.js</a></div><div class="tab"><a href="#tab_3-3">plugged_imgs.css</a></div></div><div class="tab-content"><div class="tab-pane active" id="tab_3-1"><figure class="highlight yml"><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">&lt;link</span> <span class="string">rel=&quot;stylesheet&quot;</span> <span class="string">href=&quot;/css/plugged-imgs.css&quot;&gt;</span></span><br><span class="line">    <span class="attr">bottom:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">&lt;script</span> <span class="string">src=&quot;/js/plugged-imgs.js&quot;&gt;&lt;/script&gt;</span></span><br></pre></td></tr></table></figure><!-- endtab --></div><div class="tab-pane" id="tab_3-2"><figure class="highlight js"><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><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</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="keyword">const</span> <span class="variable constant_">HEADER_IMG</span> = [</span><br><span class="line">    <span class="string">&quot;/img/header-01.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/header-02.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/header-03.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/header-04.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/header-05.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/header-06.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/header-07.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/header-08.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/header-09.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/header-10.png&quot;</span></span><br><span class="line">  ];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> <span class="variable constant_">FOOTER_IMG</span> = [</span><br><span class="line">    <span class="string">&quot;/img/footer-01.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/footer-02.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/footer-03.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/footer-04.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/footer-05.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/footer-06.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/footer-07.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/footer-08.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/footer-09.png&quot;</span>,</span><br><span class="line">    <span class="string">&quot;/img/footer-10.png&quot;</span></span><br><span class="line">  ];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> headerObserver = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">function</span> <span class="title function_">createDraggableImage</span>(<span class="params">containerId, imgId, imgUrl, storageKey, initMode</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> container = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(containerId);</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> (<span class="variable language_">document</span>.<span class="title function_">getElementById</span>(imgId)) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> originalPosition = <span class="title function_">getComputedStyle</span>(container).<span class="property">position</span>;</span><br><span class="line">    <span class="keyword">if</span> (originalPosition === <span class="string">&#x27;static&#x27;</span>) &#123;</span><br><span class="line">      container.<span class="property">style</span>.<span class="property">position</span> = <span class="string">&#x27;relative&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> img = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;img&#x27;</span>);</span><br><span class="line">    img.<span class="property">id</span> = imgId;</span><br><span class="line">    img.<span class="property">className</span> = <span class="string">&#x27;draggable-img entered loaded&#x27;</span>;</span><br><span class="line">    img.<span class="property">draggable</span> = <span class="literal">false</span>;</span><br><span class="line">    img.<span class="property">src</span> = imgUrl;</span><br><span class="line">    container.<span class="title function_">appendChild</span>(img);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> isDragging = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">let</span> wasDragged = <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">let</span> startX = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">let</span> startLeft = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">let</span> currentLeft = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> edgeThreshold = <span class="number">20</span>;</span><br><span class="line">    <span class="keyword">const</span> moveStep = <span class="number">200</span>;</span><br><span class="line">    <span class="keyword">const</span> shouldStore = initMode === <span class="string">&#x27;stored&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">getMaxLeft</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">      <span class="keyword">const</span> containerWidth = container.<span class="property">clientWidth</span>;</span><br><span class="line">      <span class="keyword">const</span> imgWidth = img.<span class="property">clientWidth</span>;</span><br><span class="line">      <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">max</span>(<span class="number">0</span>, containerWidth - imgWidth);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">setPosition</span> = (<span class="params">left, store = shouldStore</span>) =&gt; &#123;</span><br><span class="line">      <span class="keyword">const</span> maxLeft = <span class="title function_">getMaxLeft</span>();</span><br><span class="line">      <span class="keyword">const</span> clampedLeft = <span class="title class_">Math</span>.<span class="title function_">min</span>(maxLeft, <span class="title class_">Math</span>.<span class="title function_">max</span>(<span class="number">0</span>, left));</span><br><span class="line">      img.<span class="property">style</span>.<span class="property">left</span> = <span class="string">`<span class="subst">$&#123;clampedLeft&#125;</span>px`</span>;</span><br><span class="line">      currentLeft = clampedLeft;</span><br><span class="line">      <span class="keyword">if</span> (store) <span class="variable language_">localStorage</span>.<span class="title function_">setItem</span>(storageKey, clampedLeft);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">initPosition</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">      <span class="keyword">const</span> maxLeft = <span class="title function_">getMaxLeft</span>();</span><br><span class="line">      <span class="keyword">let</span> initLeft;</span><br><span class="line">      <span class="keyword">if</span> (initMode === <span class="string">&#x27;random&#x27;</span>) &#123;</span><br><span class="line">        initLeft = <span class="title class_">Math</span>.<span class="title function_">random</span>() * maxLeft;</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (initMode === <span class="string">&#x27;left&#x27;</span>) &#123;</span><br><span class="line">        initLeft = <span class="number">0</span>; </span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (initMode === <span class="string">&#x27;right&#x27;</span>) &#123;</span><br><span class="line">        initLeft = maxLeft;</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">const</span> storedLeft = <span class="built_in">parseInt</span>(<span class="variable language_">localStorage</span>.<span class="title function_">getItem</span>(storageKey));</span><br><span class="line">        <span class="keyword">if</span> (!<span class="built_in">isNaN</span>(storedLeft) &amp;&amp; storedLeft &gt;= <span class="number">0</span> &amp;&amp; storedLeft &lt;= maxLeft) &#123;</span><br><span class="line">          initLeft = storedLeft;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          initLeft = maxLeft;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="title function_">setPosition</span>(initLeft, shouldStore);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (img.<span class="property">complete</span>) &#123;</span><br><span class="line">      <span class="title function_">initPosition</span>();</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      img.<span class="title function_">addEventListener</span>(<span class="string">&#x27;load&#x27;</span>, initPosition);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;resize&#x27;</span>, <span class="function">() =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (currentLeft !== <span class="literal">undefined</span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> maxLeft = <span class="title function_">getMaxLeft</span>();</span><br><span class="line">        <span class="keyword">if</span> (currentLeft &gt; maxLeft) &#123;</span><br><span class="line">          <span class="title function_">setPosition</span>(maxLeft, shouldStore);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          img.<span class="property">style</span>.<span class="property">left</span> = <span class="string">`<span class="subst">$&#123;currentLeft&#125;</span>px`</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">    img.<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">      <span class="keyword">if</span> (!wasDragged) &#123;</span><br><span class="line">        <span class="keyword">const</span> maxLeft = <span class="title function_">getMaxLeft</span>();</span><br><span class="line">        <span class="keyword">let</span> newLeft = currentLeft;</span><br><span class="line">        <span class="keyword">if</span> (currentLeft &lt;= edgeThreshold) &#123;</span><br><span class="line">          newLeft = <span class="title class_">Math</span>.<span class="title function_">min</span>(currentLeft + moveStep, maxLeft);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (currentLeft &gt;= maxLeft - edgeThreshold) &#123;</span><br><span class="line">          newLeft = <span class="title class_">Math</span>.<span class="title function_">max</span>(currentLeft - moveStep, <span class="number">0</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          newLeft = currentLeft + (<span class="title class_">Math</span>.<span class="title function_">random</span>() &lt; <span class="number">0.5</span> ? -moveStep : moveStep);</span><br><span class="line">          newLeft = <span class="title class_">Math</span>.<span class="title function_">max</span>(<span class="number">0</span>, <span class="title class_">Math</span>.<span class="title function_">min</span>(newLeft, maxLeft));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (newLeft !== currentLeft) <span class="title function_">setPosition</span>(newLeft, shouldStore);</span><br><span class="line">      &#125;</span><br><span class="line">      wasDragged = <span class="literal">false</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    img.<span class="title function_">addEventListener</span>(<span class="string">&#x27;mousedown&#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">      isDragging = <span class="literal">true</span>;</span><br><span class="line">      wasDragged = <span class="literal">false</span>;</span><br><span class="line">      startX = e.<span class="property">clientX</span>;</span><br><span class="line">      startLeft = currentLeft;</span><br><span class="line">      img.<span class="property">style</span>.<span class="property">transition</span> = <span class="string">&#x27;none&#x27;</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">const</span> <span class="title function_">onMouseMove</span> = (<span class="params">e</span>) =&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (!isDragging) <span class="keyword">return</span>;</span><br><span class="line">        wasDragged = <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">const</span> offsetX = e.<span class="property">clientX</span> - startX;</span><br><span class="line">        <span class="keyword">const</span> maxLeft = <span class="title function_">getMaxLeft</span>();</span><br><span class="line">        <span class="keyword">let</span> newLeft = startLeft + offsetX;</span><br><span class="line">        newLeft = <span class="title class_">Math</span>.<span class="title function_">min</span>(maxLeft, <span class="title class_">Math</span>.<span class="title function_">max</span>(<span class="number">0</span>, newLeft));</span><br><span class="line">        <span class="title function_">requestAnimationFrame</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">          img.<span class="property">style</span>.<span class="property">left</span> = <span class="string">`<span class="subst">$&#123;newLeft&#125;</span>px`</span>;</span><br><span class="line">          currentLeft = newLeft;</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">const</span> <span class="title function_">onMouseUp</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        <span class="keyword">if</span> (!isDragging) <span class="keyword">return</span>;</span><br><span class="line">        isDragging = <span class="literal">false</span>;</span><br><span class="line">        img.<span class="property">style</span>.<span class="property">transition</span> = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        <span class="keyword">if</span> (shouldStore) <span class="variable language_">localStorage</span>.<span class="title function_">setItem</span>(storageKey, currentLeft);</span><br><span class="line">        <span class="variable language_">document</span>.<span class="title function_">removeEventListener</span>(<span class="string">&#x27;mousemove&#x27;</span>, onMouseMove);</span><br><span class="line">        <span class="variable language_">document</span>.<span class="title function_">removeEventListener</span>(<span class="string">&#x27;mouseup&#x27;</span>, onMouseUp);</span><br><span class="line">      &#125;;</span><br><span class="line"></span><br><span class="line">      <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;mousemove&#x27;</span>, onMouseMove);</span><br><span class="line">      <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;mouseup&#x27;</span>, onMouseUp);</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_">initFooterBar</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;footerList&#x27;</span>)) <span class="keyword">return</span>;</span><br><span class="line">    <span class="keyword">const</span> footerBar = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;footer-bar&#x27;</span>);</span><br><span class="line">    <span class="keyword">if</span> (!footerBar) <span class="keyword">return</span>;</span><br><span class="line">    <span class="keyword">const</span> footerList = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;div&#x27;</span>);</span><br><span class="line">    footerList.<span class="property">id</span> = <span class="string">&#x27;footerList&#x27;</span>;</span><br><span class="line">    footerList.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&#x27;footerList&#x27;</span>, <span class="string">&#x27;container&#x27;</span>);</span><br><span class="line">    footerBar.<span class="title function_">insertAdjacentElement</span>(<span class="string">&#x27;beforebegin&#x27;</span>, footerList);</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_">initHeaderImage</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> <span class="title class_">HeaderImageUrl</span> = <span class="variable constant_">HEADER_IMG</span>[<span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="variable constant_">HEADER_IMG</span>.<span class="property">length</span>)];</span><br><span class="line"></span><br><span class="line">    <span class="title function_">createDraggableImage</span>(</span><br><span class="line">      <span class="string">&#x27;bbTimeList&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;new-header-img&#x27;</span>,</span><br><span class="line">      <span class="title class_">HeaderImageUrl</span>,</span><br><span class="line">      <span class="string">&#x27;headerImgPos&#x27;</span>,</span><br><span class="line">      <span class="string">&#x27;random&#x27;</span></span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> headerImg = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;new-header-img&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> headerElem = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;header.full_page&#x27;</span>);</span><br><span class="line">    <span class="keyword">if</span> (!headerImg || !headerElem) <span class="keyword">return</span>;</span><br><span class="line">    <span class="keyword">const</span> <span class="title function_">updateImageClass</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">      <span class="keyword">if</span> (headerElem.<span class="property">classList</span>.<span class="title function_">contains</span>(<span class="string">&#x27;nav-fixed&#x27;</span>)) &#123;</span><br><span class="line">        headerImg.<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">&#x27;hidden&#x27;</span>);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        headerImg.<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">&#x27;hidden&#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="title function_">updateImageClass</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (headerObserver) headerObserver.<span class="title function_">disconnect</span>();</span><br><span class="line">    headerObserver = <span class="keyword">new</span> <span class="title class_">MutationObserver</span>(<span class="function">(<span class="params">mutations</span>) =&gt;</span> &#123;</span><br><span class="line">      mutations.<span class="title function_">forEach</span>(<span class="function">(<span class="params">mutation</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (mutation.<span class="property">type</span> === <span class="string">&#x27;attributes&#x27;</span> &amp;&amp; mutation.<span class="property">attributeName</span> === <span class="string">&#x27;class&#x27;</span>) <span class="title function_">updateImageClass</span>();</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    headerObserver.<span class="title function_">observe</span>(headerElem, &#123; <span class="attr">attributes</span>: <span class="literal">true</span> &#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_">initFooterImage</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> footerContainer = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;footerList&#x27;</span>);</span><br><span class="line">    <span class="keyword">if</span> (!footerContainer) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> existingImages = footerContainer.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.draggable-img&#x27;</span>);</span><br><span class="line">    existingImages.<span class="title function_">forEach</span>(<span class="function"><span class="params">img</span> =&gt;</span> img.<span class="title function_">remove</span>());</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> imgCount = <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">3</span>) + <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">const</span> shuffled = [...<span class="variable constant_">FOOTER_IMG</span>];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = shuffled.<span class="property">length</span> - <span class="number">1</span>; i &gt; <span class="number">0</span>; i--) &#123;</span><br><span class="line">      <span class="keyword">const</span> j = <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * (i + <span class="number">1</span>));</span><br><span class="line">      [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> footerImgUrls = shuffled.<span class="title function_">slice</span>(<span class="number">0</span>, imgCount);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; footerImgUrls.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="title function_">createDraggableImage</span>(</span><br><span class="line">        <span class="string">&#x27;footerList&#x27;</span>,</span><br><span class="line">        <span class="string">`new-footer-img-<span class="subst">$&#123;i+<span class="number">1</span>&#125;</span>`</span>,</span><br><span class="line">        footerImgUrls[i],</span><br><span class="line">        <span class="string">`footerImgPos_<span class="subst">$&#123;i+<span class="number">1</span>&#125;</span>`</span>,</span><br><span class="line">        <span class="string">&#x27;random&#x27;</span></span><br><span class="line">      );</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_">initAll</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="title function_">initFooterBar</span>();</span><br><span class="line">    <span class="title function_">initHeaderImage</span>();</span><br><span class="line">    <span class="title function_">initFooterImage</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;DOMContentLoaded&#x27;</span>, initAll);</span><br><span class="line">  <span class="variable language_">document</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;pjax:success&#x27;</span>, initAll);</span><br><span class="line">&#125;)();</span><br></pre></td></tr></table></figure><!-- endtab --></div><div class="tab-pane" id="tab_3-3"><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><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></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#footerList</span> &#123;</span><br><span class="line">    <span class="attribute">position</span>: relative;</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">260px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#footerList</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">bottom</span>: <span class="number">0px</span>;</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">110px</span>;</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">background</span>: <span class="built_in">url</span>(<span class="string">&quot;/img/footerbg.webp&quot;</span>) repeat center / auto <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">z-index</span>: <span class="number">3</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#footer-bar</span> &#123;</span><br><span class="line">    <span class="attribute">margin-top</span>: <span class="number">0</span>;</span><br><span class="line">    <span class="attribute">box-shadow</span>: <span class="number">0</span> -<span class="number">3px</span> <span class="number">7px</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">15</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-id">#footer</span> &#123;</span><br><span class="line">    <span class="attribute">background</span>: none;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-id">#footerList</span><span class="selector-pseudo">::before</span> &#123;</span><br><span class="line">    <span class="attribute">filter</span>: <span class="built_in">brightness</span>(.<span class="number">5</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-id">#footer-bar</span> &#123;</span><br><span class="line">    <span class="attribute">box-shadow</span>: <span class="number">0</span> -<span class="number">3px</span> <span class="number">7px</span> <span class="built_in">rgba</span>(<span class="number">255</span>,<span class="number">255</span>,<span class="number">255</span>,.<span class="number">12</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#new-header-img</span>, <span class="selector-id">#new-footer-img-1</span>,</span><br><span class="line"><span class="selector-id">#new-footer-img-2</span>, <span class="selector-id">#new-footer-img-3</span> &#123;</span><br><span class="line">    <span class="attribute">display</span>: block;</span><br><span class="line">    <span class="attribute">position</span>: absolute;</span><br><span class="line">    <span class="attribute">margin</span>: <span class="number">0</span> auto;</span><br><span class="line">    <span class="attribute">cursor</span>: grab;</span><br><span class="line">    <span class="attribute">pointer-events</span>: auto;</span><br><span class="line">    -webkit-<span class="attribute">user-select</span>: none;</span><br><span class="line">    <span class="attribute">user-select</span>: none;</span><br><span class="line">    <span class="attribute">transition</span>: left <span class="number">0.5s</span> ease-in-out;</span><br><span class="line">    <span class="attribute">z-index</span>: <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#new-header-img</span><span class="selector-class">.hidden</span> &#123;</span><br><span class="line">    <span class="attribute">display</span>: none;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#new-header-img</span><span class="selector-pseudo">:active</span>, <span class="selector-id">#new-footer-img-1</span><span class="selector-pseudo">:active</span>,</span><br><span class="line"><span class="selector-id">#new-footer-img-2</span><span class="selector-pseudo">:active</span>, <span class="selector-id">#new-footer-img-3</span><span class="selector-pseudo">:active</span> &#123;</span><br><span class="line">    <span class="attribute">cursor</span>: grabbing;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#new-header-img</span> &#123;</span><br><span class="line">    <span class="attribute">top</span>: -<span class="number">85px</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-id">#new-footer-img-1</span>, <span class="selector-id">#new-footer-img-2</span>, <span class="selector-id">#new-footer-img-3</span> &#123;</span><br><span class="line">    <span class="attribute">bottom</span>: <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-id">#new-footer-img-1</span>,</span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-id">#new-footer-img-2</span>,</span><br><span class="line"><span class="selector-attr">[data-theme=<span class="string">&quot;dark&quot;</span>]</span> <span class="selector-id">#new-footer-img-3</span> &#123;</span><br><span class="line">    <span class="attribute">filter</span>: <span class="built_in">brightness</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">@media</span> screen <span class="keyword">and</span> (<span class="attribute">max-width</span>:<span class="number">1200px</span>)&#123;</span><br><span class="line">    <span class="selector-id">#new-footer-img-3</span> &#123;</span><br><span class="line">        <span class="attribute">display</span>: none;</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">@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-id">#new-header-img</span>,</span><br><span class="line">    <span class="selector-id">#new-footer-img-2</span> &#123;</span><br><span class="line">        <span class="attribute">display</span>: none;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><!-- endtab --></div></div></div>]]>
    </content>
    <id>https://blog.didabi.cloud/posts/1961618578/</id>
    <link href="https://blog.didabi.cloud/posts/1961618578/"/>
    <published>2026-03-24T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>闲逛<a href="https://blog.xiowo.net/">Mo 的记事簿</a>的时候，看到了页脚的宠物挂件，瞬间来了灵感，大叔刚刚重刷的 Season’s Album 封面素材，正好可以用上，所以话不多说，搞起。</p>
<div class="tag-pl]]>
    </summary>
    <title>为安知鱼主题插入顶部及页脚挂件</title>
    <updated>2026-03-25T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>LeoC</name>
    </author>
    <category term="指尖余温" scheme="https://blog.didabi.cloud/categories/%E6%8C%87%E5%B0%96%E4%BD%99%E6%B8%A9/"/>
    <category term="hexo" scheme="https://blog.didabi.cloud/tags/hexo/"/>
    <content>
      <![CDATA[<p>玩了几天 hexo，一直在鼓捣主题，今天系统的梳理一下 butteryfly、HEO 系主题关系。</p><h2 id="博客框架"><a href="#博客框架" class="headerlink" title="博客框架"></a>博客框架</h2><p>基于 <a href="https://hexo.io/">Hexo</a>。</p><h2 id="主题代码"><a href="#主题代码" class="headerlink" title="主题代码"></a>主题代码</h2><p>在 <a href="https://butterfly.js.org/">Butterfly</a> 的基础上重构，<a href="https://github.com/jerryc127/hexo-theme-butterfly">Github</a>，<a href="https://github.com/jerryc127/butterfly.js.org">博客示例</a>。</p><ul><li><a href="https://butterfly.js.org/posts/21cfbf15/">Butterfly 文档(一) 快速开始</a></li><li><a href="https://butterfly.js.org/posts/dc584b87/">Butterfly 文档(二) 主题页面</a></li><li><a href="https://butterfly.js.org/posts/4aa8abbe/">Butterfly 文档(三) 主题配置</a></li><li><a href="https://butterfly.js.org/posts/ceeb73f/">Butterfly 文档(四) 标签外挂</a></li><li><a href="https://butterfly.js.org/posts/98d20436/">Butterfly 文档(五) 主题问答</a></li><li><a href="https://butterfly.js.org/posts/4073eda/">Butterfly 文档(六) 进阶教程</a></li></ul><h2 id="主题魔改"><a href="#主题魔改" class="headerlink" title="主题魔改"></a>主题魔改</h2><p>由 <a href="https://blog.zhheo.com/">HEO</a> 开发设计，其<a href="https://butterfly.zhheo.com/">魔改教程</a>为个人开发者提供一个交流的空间。</p><p><a href="https://blog.zhheo.com/">HEO</a> 开发者授权<a href="https://hexo.anheyu.com/">安知鱼</a>、<a href="https://solitude.js.org/">Solitude</a> 等移植其主题风格。</p><p><strong><a href="https://hexo.anheyu.com/">安知鱼</a></strong></p><ul><li><a href="https://hexo.anheyu.com/">展示站</a></li><li><a href="https://docs.anheyu.com/">官方文档</a></li><li><a href="https://github.com/anzhiyu-c/hexo-theme-anzhiyu">Github</a></li><li><a href="https://www.iconfont.cn/collections/detail?cid=44481">定制ICON</a></li></ul><h2 id="参考站点"><a href="#参考站点" class="headerlink" title="参考站点"></a>参考站点</h2><ul><li><a href="https://prorise666.site/">Prorise</a></li><li><a href="https://blog.dong4j.site/">司机带你开车</a></li><li><a href="https://blog.liushen.fun/">清羽飞扬</a></li><li><a href="https://blog.guole.fun/">郭乐</a></li></ul><h2 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h2><ul><li><a href="https://prorise666.site/posts/55552.html">SEO 终极攻略与实践</a></li><li><a href="https://blog.guole.fun/posts/18158/">使用 Charts 插件给 Butterfly 增加统计图表</a></li><li><a href="https://blog.liushen.fun/posts/40702a0d/">本地实现 HEXO 文章 AI 摘要</a></li><li><a href="https://blog.liushen.fun/posts/1dfd1f41/">安全跳转页面·插件版</a></li><li><a href="https://blog.guole.fun/posts/32784/">部署 Umami 统计</a><ul><li><a href="https://ums.bsgun.cn/">工具</a></li><li><a href="https://blog.bsgun.cn/posts/d0612c0e/">API</a></li></ul></li></ul><figure class="highlight yml"><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="attr">categories:</span> <span class="comment"># 并列层级</span></span><br><span class="line">  <span class="bullet">-</span> [<span class="string">檐下听风</span>]</span><br><span class="line">  <span class="bullet">-</span> [<span class="string">指尖余温</span>]</span><br><span class="line"></span><br><span class="line"><span class="attr">categories:</span> <span class="comment"># 父子层级</span></span><br><span class="line">  <span class="bullet">-</span> [<span class="string">檐下听风</span>, <span class="string">指尖余温</span>]</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.didabi.cloud/posts/4089086272/</id>
    <link href="https://blog.didabi.cloud/posts/4089086272/"/>
    <published>2026-02-26T16:00:00.000Z</published>
    <summary>作者在玩了几天的hexo后，对主题进行了系统的梳理，重点关注了butterfly和heo系主题的关系。文章首先提到博客框架是基于Hexo的，然后详细介绍了主题代码是在Butterfly的基础上重构的，并托管在Github上。接着，文章强调了HEO主题的魔改是由HEO开发设计的，并且其魔改教程为个人开发者提供了一个交流的空间。</summary>
    <title>HEO 系主题总结</title>
    <updated>2026-04-23T05:13:50.521Z</updated>
  </entry>
</feed>
