Ghost 利用 CSS 选择器实现归档按月分组

Ghost 利用 CSS 选择器实现归档按月分组

July 21, 2022
分享 , 设计 ,

JavaScript 方案

关于 Ghost 如何实现文章归档页面我之前有在关于页面的 BLogs 部分有提到过如何用 JavaScript 脚本来实现。

2016 年 & 丙申年 12 月 18 日
优化了文章归档页的实现,之前 xknow 写的 js 感觉略微繁琐,这次改用之前发现的 jquery 选择器,用 [year="2015"] 这种选择器语法直接获得当前年份的所有文章数,7 行代码就搞定了,之后完善下细节,增加年份月份折叠等功能把。

    var currentYear = "";
    $("#hidden-temp-container ul li").each(function(i){
        var year = $(this).find("em").attr("year");
        if(year < currentYear || currentYear == ""){
            currentYear = year;
            $(this).before("<h3 class='"+currentYear+"'>"+currentYear+"</h3><em>(" + $("[year='"+ currentYear +"']").length +"篇文章)</em>");
        }

    });
    
站点更新 12 月 18 日

有没有其他选择?

我前些日子研究 douban 数据展示的时候在 immmm 的博客里看到了 Hugo 这个静态博客生成器是通过类似 Groupby 的方式通过时间来分组获得数据,我就想着 Ghost 有没有这个功能呢?

{{- range  (where (where .Site.Pages "Type" "in" "posts") "Kind" "page").GroupByDate "2006" }}
    <div class="post archive__group-posts ">
        {{- range .Pages.GroupByDate "2006-01" }}
        <div class="archive__group-month">
          <h3>{{ .Key }}</h3>
          <div class="archive__post">
          {{- range .Pages }}
          <div class="archive__post-title">
            <a href="{{.Permalink}}">{{.Title}}<span class="post-date">{{ .Date.Format ($.Site.Params.DateFormatList | default "2006-01-02") }}</span></a>
          </div>
          {{ end }}
          </div>
        </div>
        {{- end }}
    </div>
    {{- end }}
hugo 的方式

后端方案尝试

Ghost 使用的是 handlebars 作为主题模板的,可惜我找遍了文档也没有这方面的资料,而且官方提供的 Functional helpers 里并没有相关可以用的组件,所以从服务器端处理的方法肯定就行不通了。

虽然你可以用 get 的 filter 属性来做一些复杂查询,但是无法实现 Groupby 这种功能

{{! Only get posts that are featured }}
{{#get "posts" limit="all" filter="featured:true"}}
    {{#foreach posts}}
        <a href="{{slug}}">{{title}}</a>
    {{/foreach}}
{{/get}}
get 助手的 filter 工具

如果不通过 JavaScript、后端的的方式来处理就只能使用 CSS 了,但是要怎么写可把我难坏了,第一天晚上冥思苦想了很久不知道怎么下手,一晚上也没想出个什么好的办法。

CSS 方案

而且 Baidu、Google 都没有找到合适的解决方案,无奈之下就去 Ghost 的官方论坛看看有没有其他人对这个方案提过建议。

运气不错的我很快就找到了一个帖子讨论过归档页的问题,看来广大用户对这个东西还是很有共鸣的,有大佬直接丢了一个 Demo 结构

You’re in luck @pts, we’ve got something just for that. The post loop looks like this:
{{#foreach posts}}
  <article class="post post-date-{{date format="M"}}">
    <div class="post-label">{{date format="MMMM YYYY"}}</div>
    <a class="post-link" href="{{url}}">
      <h2 class="post-title">{{title}}</h2>
    </a>
  </article>
{{/foreach}}
模板页面
This renders each post with the date above it in the format of Month and year, e.g. January 2020. They key part is the <article> element has a class which includes the post month as a single digit number, e.g. post-date-1 for January. We can then hook into that class using some CSS:
.post-date-1 + .post-date-1 .post-label,
.post-date-2 + .post-date-2 .post-label,
.post-date-3 + .post-date-3 .post-label,
.post-date-4 + .post-date-4 .post-label,
.post-date-5 + .post-date-5 .post-label,
.post-date-6 + .post-date-6 .post-label,
.post-date-7 + .post-date-7 .post-label,
.post-date-8 + .post-date-8 .post-label,
.post-date-9 + .post-date-9 .post-label,
.post-date-10 + .post-date-10 .post-label,
.post-date-11 + .post-date-11 .post-label,
.post-date-12 + .post-date-12 .post-label {
  display: none;
}
css 样式
This CSS will pick out any post which immediately follows a post with a matching post-date-X class. The result is exactly as desired and meets accessibility expectations. Even works with pagination.
Hope this helps!

我查了一下 .class + .class 这种语法的文档说明:

element+element div + p 选择紧跟 <div> 元素的首个 <p> 元素。

这就好理解了现在的归档列表结构是这样的,红框部分为月份,我们只需要通过 .class + .class  这个选择器获取第一个元素之后的同名元素进行隐藏即可只保留第一个月份元素。

有了这个再给结构写一些样式就能只通过 CSS 实现现在这种效果拉。

加入评论