<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>短代码 - 标签 - 灿若星河 | 郝建锋</title><link>https://philohao.com/tags/%E7%9F%AD%E4%BB%A3%E7%A0%81/</link><description>短代码 - 标签 - 灿若星河 | 郝建锋</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><managingEditor>haojianfeng1997@gmail.com (Jianfeng.Hao)</managingEditor><webMaster>haojianfeng1997@gmail.com (Jianfeng.Hao)</webMaster><lastBuildDate>Thu, 28 Aug 2025 19:01:17 +0800</lastBuildDate><atom:link href="https://philohao.com/tags/%E7%9F%AD%E4%BB%A3%E7%A0%81/index.xml" rel="self" type="application/rss+xml"/><item><title>折腾 | 用数据文件优化短代码的使用</title><link>https://philohao.com/2025/08/20250828/</link><pubDate>Thu, 28 Aug 2025 19:01:17 +0800</pubDate><dc:creator>Jianfeng.Hao</dc:creator><author>haojianfeng1997@gmail.com (Jianfeng.Hao)</author><guid isPermaLink="true">https://philohao.com/2025/08/20250828/</guid><description>之前网站的书影记录页面，数据和代码都写在 markdown 文件里，内容一多就很难维护。本文记录了通过 Hugo 的数据文件（Data Files）功能，将数据和内容分离开，从而优化维护体验的过程。</description><content:encoded><![CDATA[<p>本文解决的是 Hugo 页面里结构化书影音记录难维护的问题：把原本塞在 Markdown 里的 Shortcode 参数迁移到 Data Files 中，让内容数据、页面结构和展示代码分离，后续新增记录时只改 YAML 数据即可。</p>
<h2 id="适用场景">适用场景</h2>
<p>适合在 Hugo 中维护书单、影单、友链、项目列表等重复卡片内容的页面。只要内容条目字段相对固定、数量会持续增加，就可以考虑用 Data Files 替代一条条手写 Shortcode。</p>
<h2 id="背景">背景</h2>
<p>网站上有一个<a href="https://philohao.com/pages/mentalfood/" rel="">阅览</a>页面，用来记录我看过的书和电影。之前为了显示效果，自定义了一个叫 <code>mediacard</code> 的 Shortcode，可以在页面上生成卡片。</p>
<p>在 Markdown 文件里，每条记录都是一次 Shortcode 调用，像这样：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">{{<span class="p">&lt;</span> <span class="nt">mediacard</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;大唐双龙传&#34;</span> 
</span></span><span class="line"><span class="cl">    <span class="na">coverurl</span><span class="o">=</span><span class="s">&#34;...&#34;</span> <span class="na">link</span><span class="o">=</span><span class="s">&#34;...&#34;</span> 
</span></span><span class="line"><span class="cl">    <span class="na">author</span><span class="o">=</span><span class="s">&#34;黄易&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;24-01&#34;</span> 
</span></span><span class="line"><span class="cl">    <span class="na">starscore</span><span class="o">=</span><span class="s">&#34;★★★&#34;</span> <span class="na">greystar</span><span class="o">=</span><span class="s">&#34;☆☆&#34;</span> 
</span></span><span class="line"><span class="cl">    <span class="na">intro</span><span class="o">=</span><span class="s">&#34;...&#34;</span> 
</span></span><span class="line"><span class="cl"><span class="p">&gt;</span>}}
</span></span></code></pre></td></tr></table>
</div>
</div><p>刚开始记录不多的时候，这个方法还行。但后来东西越来越多，整个 Markdown 文件就变得特别长，每次想加一条新记录，都要在文件里找很久，维护起来很麻烦。</p>
<h2 id="核心步骤">核心步骤</h2>
<h3 id="解决方法">解决方法</h3>
<p>主要思路就是把<strong>数据</strong>和<strong>页面</strong>分开。</p>
<p>Hugo 本身提供了 Data Files 功能，允许在 <code>/data</code> 目录下存放 YAML、JSON 或 TOML 格式的数据文件。这样，Markdown 文件就只负责页面结构和展示逻辑，而具体的书影条目数据，则统一放到数据文件里，方便管理。</p>
<h3 id="具体步骤">具体步骤</h3>
<h4 id="1-把数据转移到-data-文件夹">1. 把数据转移到 <code>data</code> 文件夹</h4>
<p>第一步是把之前写在 Markdown 文件里的所有条目数据，都整理出来，放到 <code>/data</code> 文件夹下，这种脏活累活当然是交给 AI 来完成啦！</p>
<p>我新建了 <code>books.yaml</code> 和 <code>movies.yaml</code> 两个文件。</p>
<p><strong>修改前 (在 <code>.md</code> 文件里):</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">{{<span class="p">&lt;</span> <span class="nt">mediacard</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;法师故事&#34;</span> <span class="na">coverurl</span><span class="o">=</span><span class="s">&#34;...&#34;</span> <span class="na">author</span><span class="o">=</span><span class="s">&#34;索斯&#34;</span> <span class="na">type</span><span class="o">=</span><span class="s">&#34;24-08&#34;</span> <span class="err">...</span> <span class="p">&gt;</span>}}
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>修改后 (在 <code>data/books.yaml</code> 文件里):</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl">- <span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;法师故事&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">coverurl</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;[https://bookcover.yuewen.com/qdbimg/349573/57821/600.webp](https://bookcover.yuewen.com/qdbimg/349573/57821/600.webp)&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">link</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;[https://www.qidian.com/book/57821/](https://www.qidian.com/book/57821/)&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">author</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;索斯&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;24-08&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">starscore</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;★★★★&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">greystar</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;☆&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">intro</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;魔兽践踏，巨龙咆哮，巫师诅咒，魔法璀璨之光照耀知识灯塔！&#34;</span><span class="w">
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>这样一来，所有的数据都集中管理了，之后增删改查也只用编辑这两个 <code>.yaml</code> 文件就行。</p>
<h4 id="2-写一个新的-shortcode">2. 写一个新的 Shortcode</h4>
<p>因为数据存放的位置变了，所以需要一个新的 Shortcode 来读取这些数据并显示出来。</p>
<p>我在 <code>layouts/shortcodes/</code> 目录下新建了一个 <code>medialist.html</code> 文件。这个 Shortcode 接收两个参数：第一个是数据文件名（比如 &ldquo;books&rdquo;），第二个是年份（比如 &ldquo;24&rdquo;），用来筛选对应年份的数据。</p>
<p>代码如下：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">{{- $dataFile := .Get 0 -}}
</span></span><span class="line"><span class="cl">{{- $yearPrefix := .Get 1 -}}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- if not $dataFile -}}
</span></span><span class="line"><span class="cl">  {{- errorf &#34;medialist shortcode in %s: 缺少第一个参数 (数据文件名)。&#34; .Page.Path -}}
</span></span><span class="line"><span class="cl">{{- end -}}
</span></span><span class="line"><span class="cl">{{- if not $yearPrefix -}}
</span></span><span class="line"><span class="cl">  {{- errorf &#34;medialist shortcode in %s: 缺少第二个参数 (年份)。&#34; .Page.Path -}}
</span></span><span class="line"><span class="cl">{{- end -}}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- $mediaData := index site.Data $dataFile -}}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{{- if $mediaData -}}
</span></span><span class="line"><span class="cl">  {{- $count := 0 -}}
</span></span><span class="line"><span class="cl">  {{- range $mediaData -}}
</span></span><span class="line"><span class="cl">    {{- if (hasPrefix .type $yearPrefix) -}}
</span></span><span class="line"><span class="cl">      {{- $count = add $count 1 -}}
</span></span><span class="line"><span class="cl">      <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;media&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;media-cover&#34;</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;background-image:url(\{\{ .coverurl \}\})&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;media-meta&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;media-meta-item title&#34;</span><span class="p">&gt;&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&#34;\{\{ .link \}\}&#34;</span> <span class="na">target</span><span class="o">=</span><span class="s">&#34;_blank&#34;</span> <span class="na">rel</span><span class="o">=</span><span class="s">&#34;noopener noreferrer&#34;</span><span class="p">&gt;</span>\{\{ .title \}\}<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;&lt;</span><span class="nt">span</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;float:right;font-weight:400&#34;</span><span class="p">&gt;</span>\{\{ .type \}\}<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;media-meta-item&#34;</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;author&#34;</span><span class="p">&gt;</span>\{\{ .author \}\}<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">            <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;star-score&#34;</span><span class="p">&gt;</span>\{\{ .starscore \}\}<span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;grey-star&#34;</span><span class="p">&gt;</span>\{\{ .greystar \}\}<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">          <span class="p">&lt;</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;media-meta-item intro&#34;</span><span class="p">&gt;</span>\{\{ .intro | safeHTML \}\}<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">    {{- end -}}
</span></span><span class="line"><span class="cl">  {{- end -}}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  {{- if eq $count 0 -}}
</span></span><span class="line"><span class="cl">    <span class="p">&lt;</span><span class="nt">p</span> <span class="na">style</span><span class="o">=</span><span class="s">&#34;text-align: center; color: #888;&#34;</span><span class="p">&gt;</span>本年度暂无记录。<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">  {{- end -}}
</span></span><span class="line"><span class="cl">{{- else -}}
</span></span><span class="line"><span class="cl">  <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>警告：找不到数据文件 data/\{\{ $dataFile \}\}.yaml (或 .json/.toml)<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl">{{- end -}}
</span></span></code></pre></td></tr></table>
</div>
</div><p>这个 shortcode 的工作原理：</p>
<ol>
<li><code>{{ $dataFile := .Get 0 }}</code> 获取第一个参数<code>（&quot;books&quot;）</code></li>
<li><code>{{ $yearPrefix := .Get 1 }}</code> 获取第二个参数<code>（&quot;24&quot;）</code></li>
<li><code>{{ range $mediaData }}</code> 遍历数据文件中的所有条目</li>
<li><code>{{ if (hasPrefix .type $yearPrefix) }}</code> 是最关键的一行，它检查每个条目的 type 字段（如 <code>&quot;24-01&quot;</code>）是否以我们传入的年份前缀（<code>&quot;24&quot;</code>）开头，只有匹配的条目才会被渲染成 HTML</li>
<li>还增加了一个计数器，如果某一年份下没有任何记录，会显示“本年度暂无记录”</li>
</ol>
<h4 id="3-修改-markdown-文件">3. 修改 Markdown 文件</h4>
<p>最后一步，就是把原来的 Markdown 文件里大段的 <code>mediacard</code> 调用，换成新的 <code>medialist</code>。</p>
<p><strong>修改前 (2024年影剧部分):</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">{{<span class="p">&lt;</span> <span class="nt">admonition</span> <span class="na">type</span><span class="o">=</span><span class="s">tip</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;影剧（20部）&#34;</span> <span class="na">open</span><span class="o">=</span><span class="s">false</span> <span class="p">&gt;</span>}}
</span></span><span class="line"><span class="cl">  {{<span class="p">&lt;</span> <span class="nt">mediacard</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;非诚勿扰3 (2023)&#34;</span> <span class="err">...</span> <span class="p">&gt;</span>}}
</span></span><span class="line"><span class="cl">  {{<span class="p">&lt;</span> <span class="nt">mediacard</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;葬送的芙莉莲 (2023)&#34;</span> <span class="err">...</span> <span class="p">&gt;</span>}}
</span></span><span class="line"><span class="cl">  ... (还有很多条)
</span></span><span class="line"><span class="cl">{{<span class="p">&lt;</span> <span class="p">/</span><span class="nt">admonition</span> <span class="p">&gt;</span>}}
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>修改后:</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">{{<span class="p">&lt;</span> <span class="nt">admonition</span> <span class="na">type</span><span class="o">=</span><span class="s">tip</span> <span class="na">title</span><span class="o">=</span><span class="s">&#34;影剧&#34;</span> <span class="na">open</span><span class="o">=</span><span class="s">false</span> <span class="p">&gt;</span>}}
</span></span><span class="line"><span class="cl">  {{<span class="p">&lt;</span> <span class="nt">medialist</span> <span class="err">&#34;</span><span class="na">movies</span><span class="err">&#34;</span> <span class="err">&#34;</span><span class="na">24</span><span class="err">&#34;</span> <span class="p">&gt;</span>}}
</span></span><span class="line"><span class="cl">{{<span class="p">&lt;</span> <span class="p">/</span><span class="nt">admonition</span> <span class="p">&gt;</span>}}
</span></span></code></pre></td></tr></table>
</div>
</div><p>原来几十行的内容，现在一行就够了，整个 Markdown 文件清爽了很多。</p>
<h2 id="最终效果">最终效果</h2>
<p>这么修改之后，解决了之前维护困难的问题。</p>
<ul>
<li><strong>Markdown 文件变干净了</strong>，只负责页面结构，不再包含具体数据。</li>
<li><strong>数据管理方便</strong>，所有条目都在 <code>.yaml</code> 文件里，一目了然。</li>
<li><strong>之后扩展也容易</strong>，这些数据可以很方便地在网站其他地方复用。</li>
</ul>
<p>总的来说，对 Hugo 这种需要管理大量结构化数据的情况，用 Data Files 功能是个不错的选择。</p>
<h2 id="小结">小结</h2>
<p>最终方案是用 <code>data/books.yaml</code>、<code>data/movies.yaml</code> 承载条目数据，再用 <code>medialist</code> Shortcode 按年份筛选并渲染。它牺牲了一点模板复杂度，换来了 Markdown 页面更清爽、数据更易批量维护的收益。后续可优化的方向，是继续抽象评分、分类和封面字段，并为数据文件增加更稳定的校验规则。</p>
<h2 id="参考资料">参考资料</h2>
<ul>
<li><a href="https://gohugo.io/templates/data-templates/" target="_blank" rel="noopener noreffer">Hugo Data Templates</a></li>
<li><a href="https://gohugo.io/content-management/shortcodes/" target="_blank" rel="noopener noreffer">Hugo Shortcodes</a></li>
</ul>
<p>（2025-08-28@深圳）</p>
]]></content:encoded></item><item><title>折腾 | 博文热力图</title><link>https://philohao.com/2024/01/20240110/</link><pubDate>Wed, 10 Jan 2024 03:01:17 +0800</pubDate><dc:creator>Jianfeng.Hao</dc:creator><author>haojianfeng1997@gmail.com (Jianfeng.Hao)</author><guid isPermaLink="true">https://philohao.com/2024/01/20240110/</guid><description>博文热力图折腾记录，介绍用 Hugo Shortcode 和 ECharts 展示发文节奏。</description><content:encoded><![CDATA[<p>本文解决的是归档页缺少直观写作节奏的问题：借助 Hugo Shortcode 引入 ECharts 热力图，把每天的发文数量转换成日历小方块，方便回看写作频率和内容沉淀。</p>
<h2 id="适用场景">适用场景</h2>
<p>适合有持续写作习惯、希望在归档页展示产出节奏的 Hugo 博客。它也适合需要把站点数据做成轻量可视化模块的场景，比如文章数量、阅读记录或照片更新频率。</p>
<h2 id="核心步骤">核心步骤</h2>
<p>最近看到<a href="https://blog.douchi.space/hugo-blog-heatmap/#115-%E6%9B%B4%E6%96%B0---%E6%AF%8F%E5%A4%A9%E5%A4%9A%E7%AF%87%E6%96%87%E7%AB%A0" target="_blank" rel="noopener noreffer">椒盐豆豉</a>更新文章给博客增加了文章热力图，直接被种草。这种展现方式能直接的显示最近的产量（没眼看没眼看🤣），一方面能够作为催更动力让我别太懒，另一方面如果坚持写作贴满小瓷砖的话也能提供满满成就感。不过我最看重的一点是它使我回顾以往的文章更加容易也更有 feel，我可太爱循着日历回看文章这种形式了！</p>
<ul>
<li><i class="far fa-check-square fa-fw"></i> 我是用 shortcodes 形式<a href="https://github.com/DivinerHJF/hugo-theme-Aether/commit/0f3df8c716da8838beeda84b0d7a7bad9df1b2c3" target="_blank" rel="noopener noreffer">引入的代码</a>，这样子在想引入的页面直接嵌入短代码即可，目前把成品放在了 <a href="https://philohao.com/posts/" rel="">归档</a> 页面了。</li>
<li><i class="far fa-check-square fa-fw"></i> 我按着 Echart 官方文档和其他博主的样式教程修改了一些显示样式，使这个热力图控件和我的博客风格更搭，同时也调整了一下颜色控制部分的代码，使 Echart 图表自带的自动适配暗色模式的特性可以生效。</li>
</ul>
<h2 id="最终效果">最终效果</h2>
<p>热力图被放在归档页，作为文章列表之前的总览入口。它既能展示某段时间的写作密度，也能提醒自己哪些阶段断更较久，回看时比单纯的年月列表更有时间感。</p>
<h2 id="小结">小结</h2>
<p>最终方案选择 Shortcode 封装 ECharts 配置，优点是复用方便、页面嵌入简单；取舍是需要维护一段图表配置代码，并关注主题暗色模式下的颜色表现。后续可以继续优化移动端显示、年份切换，以及多篇文章同日发布时的提示信息。</p>
<h2 id="参考资料">参考资料</h2>
<ul>
<li><a href="https://blog.douchi.space/hugo-blog-heatmap/#115-%E6%9B%B4%E6%96%B0---%E6%AF%8F%E5%A4%A9%E5%A4%9A%E7%AF%87%E6%96%87%E7%AB%A0" target="_blank" rel="noopener noreffer">椒盐豆豉：Hugo 博客热力图</a></li>
<li><a href="https://github.com/DivinerHJF/hugo-theme-Aether/commit/0f3df8c716da8838beeda84b0d7a7bad9df1b2c3" target="_blank" rel="noopener noreffer">引入热力图的主题提交</a></li>
</ul>
<p>（2024-01-10@广州）</p>
]]></content:encoded></item><item><title>折腾 | 图片瀑布流</title><link>https://philohao.com/2024/01/20240107/</link><pubDate>Sun, 07 Jan 2024 11:43:07 +0800</pubDate><dc:creator>Jianfeng.Hao</dc:creator><author>haojianfeng1997@gmail.com (Jianfeng.Hao)</author><guid isPermaLink="true">https://philohao.com/2024/01/20240107/</guid><description>图片瀑布流折腾记录，介绍 Hugo 文章中多图展示和相册化排版的实现思路。</description><content:encoded><![CDATA[<p>本文解决的是博客多图展示占用空间大、排版不够相册化的问题：在不引入复杂组件的前提下，用 Hugo 内容组织配合 CSS 多列布局，让照片在文章和相册页面里以瀑布流形式展示。</p>
<h2 id="适用场景">适用场景</h2>
<p>适合需要在 Hugo 文章中集中展示多张照片、游记配图或作品集的页面。它的目标不是做完整图片管理系统，而是用尽量轻量的样式，让图片阅读更紧凑、更美观。</p>
<h2 id="核心步骤">核心步骤</h2>
<p>最近在给一系列博文配图，随着添加的图片多了之后，一直想实现的「图片瀑布流」的心思又活络起来了。Google 大法好，最终找到了<a href="https://immmmm.com/hi-waterfall-js/" target="_blank" rel="noopener noreffer">图片瀑布流折腾记</a>、<a href="https://immmmm.com/about-images-gird/" target="_blank" rel="noopener noreffer">Hugo 多图排版这样来</a> 这两篇文章，两种不同的方法都很简单，都可以实现我想要的效果，感恩！</p>
<p>目前我主要在网站的两个地方进行应用，第一种是在文章中大量展示自己拍的照片时达到类似相册效果，这样既美观又省网页空间；另一种是专门的「<a href="https://philohao.com/pages/album/" rel="">回忆</a>」页面，不断添加我自己拍的较为满意的照片，相当于照片画廊。</p>
<p>目前对网站图片进行了以下操作：</p>
<ul>
<li><i class="far fa-check-square fa-fw"></i> 圆角处理：<code>border-radius: 5px;</code></li>
<li><i class="far fa-check-square fa-fw"></i> 阴影效果：<code>box-shadow: 0px 0px 5px rgba(0,0,0,0.3);</code></li>
<li><i class="far fa-check-square fa-fw"></i> 滑过放大：<code>img:hover</code> 和 <code>transform</code> 的<a href="https://www.cnblogs.com/chervehong/p/10286961.html" target="_blank" rel="noopener noreffer">纯 CSS 方案</a></li>
<li><i class="far fa-check-square fa-fw"></i> 多图排版：<code>column-count</code> 和 <code>p:has(&gt; img:nth-child)</code> 的<a href="https://immmmm.com/about-images-gird/" target="_blank" rel="noopener noreffer">纯 CSS 方案</a></li>
</ul>
<h2 id="最终效果">最终效果</h2>
<p><img
        class="lazyload"
        data-src="https://image.philohao.com/images/retouch_2023122421225662.jpg"
        data-srcset="https://image.philohao.com/images/retouch_2023122421225662.jpg, https://image.philohao.com/images/retouch_2023122421225662.jpg 1.5x, https://image.philohao.com/images/retouch_2023122421225662.jpg 2x"
        data-sizes="auto"
        alt="https://image.philohao.com/images/retouch_2023122421225662.jpg"
        title="https://image.philohao.com/images/retouch_2023122421225662.jpg"
    />
<img
        class="lazyload"
        data-src="https://image.philohao.com/images/retouch_2023122421215472.jpg"
        data-srcset="https://image.philohao.com/images/retouch_2023122421215472.jpg, https://image.philohao.com/images/retouch_2023122421215472.jpg 1.5x, https://image.philohao.com/images/retouch_2023122421215472.jpg 2x"
        data-sizes="auto"
        alt="https://image.philohao.com/images/retouch_2023122421215472.jpg"
        title="https://image.philohao.com/images/retouch_2023122421215472.jpg"
    />
<img
        class="lazyload"
        data-src="https://image.philohao.com/images/20231224123258_IMG_1435.JPG"
        data-srcset="https://image.philohao.com/images/20231224123258_IMG_1435.JPG, https://image.philohao.com/images/20231224123258_IMG_1435.JPG 1.5x, https://image.philohao.com/images/20231224123258_IMG_1435.JPG 2x"
        data-sizes="auto"
        alt="https://image.philohao.com/images/20231224123258_IMG_1435.JPG"
        title="https://image.philohao.com/images/20231224123258_IMG_1435.JPG"
    /></p>
<h2 id="小结">小结</h2>
<p>最终方案倾向于纯 CSS 实现，优点是简单、无需额外 JavaScript，和 Hugo 原本的 Markdown 图片写法也比较兼容；取舍是瀑布流控制能力不如专门图库组件精细。后续可以继续优化懒加载、移动端列数和图片说明文字，让相册页面在性能和可读性之间更平衡。</p>
<h2 id="参考资料">参考资料</h2>
<ul>
<li><a href="https://immmmm.com/hi-waterfall-js/" target="_blank" rel="noopener noreffer">图片瀑布流折腾记</a></li>
<li><a href="https://immmmm.com/about-images-gird/" target="_blank" rel="noopener noreffer">Hugo 多图排版这样来</a></li>
<li><a href="https://www.cnblogs.com/chervehong/p/10286961.html" target="_blank" rel="noopener noreffer">CSS3 图片 Hover 放大效果</a></li>
</ul>
<p>（2023-12-16@广州）</p>
]]></content:encoded></item></channel></rss>