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

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实现现在这种效果拉。

  • 创建时间 2022-07-21 02:06
  • 发布时间 2022-07-21 02:49
  • 最后更新 2022-07-21 02:53