Jekyll不使用插件生成「书单」页面

调用_data数据,不使用豆瓣API接口

作者: Duter2016 | 2019-10-27 | 阅读
「编辑」 「本文源码」

效果见「我的书单页面」

目前已经有一个在 Hexo 页面中嵌入豆瓣个人主页的小插件项目「hexo-douban」。 但是「hexo-douban」需要调用豆瓣的API数据接口,还要用到豆瓣帐号,而且据反馈会经常出现爬取失败和部分浏览器加载不正常的问题。而且如果遇到豆瓣书单数量上百时,每次打开站点都要耗费大量资源重新生成页面,严重拖慢相应速度!因此,我想把书单功能本地化!

经过搜集资料,认为可以通过“Jekyll 支持从 _data 目录下的 YAML、JSON 和 CSV 载入数据”的特性并新建一些变量来实现, 于是我抓取了「hexo-douban」生成的页面CSS样式数据和脚本,多次修改,终于实现了“书单本地化”! 本“书单”功能只调用_data数据,不需使用豆瓣API接口。

1.创建books.html文件

在根目录创建books.html文件,代码如下


---
title: 书单
layout: default
permalink: /books/
description: 读万卷书,行万里路
header-img: "img/post-bg-coffee.jpeg"
---

<!-- Page Header -->
<header class="intro-header" style="background-image: url('{{ site.baseurl }}/{% if page.header-img %}{{ page.header-img }}{% else %}{{ site.header-img }}{% endif %}')">
    <div class="container">
        <div class="row">
            <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
                <div class="site-heading" id="tag-heading">
                    <h1>{% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}</h1>
                    <span class="subheading">{{ page.description }}</span>
                </div>
            </div>
        </div>
    </div>
<style>
.hexo-douban-tabs {
    margin-bottom: 15px;
    margin-top: 15px;
}

.hexo-douban-tab {
    padding: 5px;
}

.hexo-douban-active {
    background: #657b83;
    color: #fff;
}

.hexo-douban-active:hover{
    background: #657b83;
    color: red;
}

.hexo-douban-item {
    padding-bottom: 10px;
    position: relative;
    clear: both;
    min-height: 170px;
    padding: 10px 0;
    border-bottom: 1px #ddd solid;
}

@media screen and (max-width: 600px) {
    .hexo-douban-item {
        width: 100%;
    }
}

.hexo-douban-picture {
    position: absolute;
    left: 0;
    top: 10px;
    width: 100px;
}

.hexo-douban-info {
    padding-left: 120px;
}

.hexo-douban-meta {
    font-size: 12px;
    padding-right: 10px;
}

.hexo-douban-comments {
    font-size: 12px;
}

.hexo-douban-pagination {
    margin-top: 15px;
    text-align: center;
    margin-bottom: 10px;
}

.hexo-douban-button {
    padding: 5px;
}

.hexo-douban-button:hover {
    background: #657b83;
    color: #fff;
}

.hexo-douban-hide {
    display: none;
}

.hexo-douban-show {
    display: block;
}

.hexo-douban-picture img{
    width:92px;
    height:131px
}
</style>
</header>

<!-- Main Content start-->
<div class="container">
<!--
<h1>这里是我的书籍清单</h1>
-->
<blockquote>
    <p>{{ site.data.bookstj.booknote }}</p>
</blockquote>

<div class="hexo-douban-tabs">
    <a class="hexo-douban-tab" id="hexo-douban-tab1" href="javascript:;" rel="external">
        在读
        ({{ site.data.bookstj.zdnum }})</a>
    <a class="hexo-douban-tab" id="hexo-douban-tab2" href="javascript:;" rel="external">
        想读
        ({{ site.data.bookstj.xdnum }})</a>
    <a class="hexo-douban-tab" id="hexo-douban-tab3" href="javascript:;" rel="external">
        已读
        ({{ site.data.bookstj.ydnum }})</a>
</div>

<div>
  <!--      在读 start      -->
  <div id="hexo-douban-item1">
    <!-- 在读000开始 -->
    {% for book in site.data.bookszd %}
    <div class="hexo-douban-item">
      <div class="hexo-douban-picture"><img src="{{ book.bookimg }}" data-src="{{ book.bookimg }}" referrerpolicy="no-referrer"></div>
      <div class="hexo-douban-info">
          <div class="hexo-douban-title"><a target="_blank" href="{{ book.doubanurl }}"> {{ book.name }}</a></div>
          <div class="hexo-douban-meta">
            {{ book.author }} | {{ book.translator }}译 | {{ book.press }} | {{ book.publishdate }} | {{ book.price }}
          </div>
          <div class="hexo-douban-meta">{{ book.readdate }} 在读 | {{ book.booktag }}</div>
          <div class="hexo-douban-comments"></div>
      </div>
    </div>
    {% endfor %}
    <!-- 在读000结束 -->
    
    <!-- 分页 开始 -->
    <div class="hexo-douban-pagination">
      <a class="hexo-douban-button hexo-douban-firstpage" href="javascript:;"> 首页</a>
      <a class="hexo-douban-button hexo-douban-previouspage" href="javascript:;">上一页</a>
      <span class="hexo-douban-pagenum">2 / 3</span>
      <a class="hexo-douban-button hexo-douban-nextpage" href="javascript:;">下一页</a>
      <a class="hexo-douban-button hexo-douban-lastpage" href="javascript:;">尾页</a>
    </div>
    <!-- 分页 结束 -->
    
  </div>
  <!--      在读 end      -->


  <!-- 想读 start -->
  <div id="hexo-douban-item2">
    <!-- 想读000开始 -->
    {% for book in site.data.booksxd %}
    <div class="hexo-douban-item">
      <div class="hexo-douban-picture"><img src="{{ book.bookimg }}" data-src="{{ book.bookimg }}" referrerpolicy="no-referrer"></div>
      <div class="hexo-douban-info">
          <div class="hexo-douban-title"><a target="_blank" href="{{ book.doubanurl }}"> {{ book.name }}</a></div>
          <div class="hexo-douban-meta">
            {{ book.author }} | {{ book.translator }}译 | {{ book.press }} | {{ book.publishdate }} | {{ book.price }}
          </div>
          <div class="hexo-douban-meta">{{ book.readdate }} 想读 | {{ book.booktag }}</div>
          <div class="hexo-douban-comments"></div>
      </div>
    </div>
    {% endfor %}
    <!-- 想读000结束 -->
    
    <!-- 分页 开始 -->
    <div class="hexo-douban-pagination">
      <a class="hexo-douban-button hexo-douban-firstpage" href="javascript:;"> 首页</a>
      <a class="hexo-douban-button hexo-douban-previouspage" href="javascript:;">上一页</a>
      <span class="hexo-douban-pagenum">2 / 3</span>
      <a class="hexo-douban-button hexo-douban-nextpage" href="javascript:;">下一页</a>
      <a class="hexo-douban-button hexo-douban-lastpage" href="javascript:;">尾页</a>
    </div>
    <!-- 分页 结束 -->
    
  </div>
  <!--      想读 end      -->


  <!--      已读 start      -->
  <div id="hexo-douban-item3">
    <!-- 已读000开始 -->
    {% for book in site.data.booksyd %}
    <div class="hexo-douban-item">
      <div class="hexo-douban-picture"><img src="{{ book.bookimg }}" data-src="{{ book.bookimg }}" referrerpolicy="no-referrer"></div>
      <div class="hexo-douban-info">
          <div class="hexo-douban-title"><a target="_blank" href="{{ book.doubanurl }}"> {{ book.name }}</a></div>
          <div class="hexo-douban-meta">
            {{ book.author }} | {{ book.translator }}译 | {{ book.press }} | {{ book.publishdate }} | {{ book.price }}
          </div>
          <div class="hexo-douban-meta">{{ book.readdate }}
            读过 | {{ book.booktag }} | {{ book.stars }} {{ book.rate }}</div>
          <div class="hexo-douban-comments">我的书评:{{ book.review }}</div>
      </div>
    </div>
    {% endfor %}
    <!-- 已读000结束 -->
    
    <!-- 分页 开始 -->
    <div class="hexo-douban-pagination">
      <a class="hexo-douban-button hexo-douban-firstpage" href="javascript:;"> 首页</a>
      <a class="hexo-douban-button hexo-douban-previouspage" href="javascript:;">上一页</a>
      <span class="hexo-douban-pagenum">2 / 3</span>
      <a class="hexo-douban-button hexo-douban-nextpage" href="javascript:;">下一页</a>
      <a class="hexo-douban-button hexo-douban-lastpage" href="javascript:;">尾页</a>
    </div>
    <!-- 分页 结束 -->
    
  </div>
  <!--      已读 end      -->

</div>

    <!-- 书单统计 开始 -->
    <div align="center">
    在读书单共 <script language="JavaScript">
    var numitem1 = document.getElementById('hexo-douban-item1').getElementsByClassName('hexo-douban-item').length;
    document.write(numitem1)
</script> 本;
    想读书单共 <script language="JavaScript">
    var numitem2 = document.getElementById('hexo-douban-item2').getElementsByClassName('hexo-douban-item').length;
    document.write(numitem2)
</script> 本;
    已读书单共 <script language="JavaScript">
    var numitem3 = document.getElementById('hexo-douban-item3').getElementsByClassName('hexo-douban-item').length;
    document.write(numitem3)
</script></div>
    <!-- 书单统计 结束 -->

</div>
<!-- Main Content end-->


<!-- 标签切换脚本 -->
<script>
    /**
 * Created by myths on 18-2-8.
 */

Element.prototype.siblings = function () {
    var siblingElement = [];
    var sibs = this.parentNode.children;
    for (var i = 0; i < sibs.length; i++) {
        if (sibs[i] !== this) {
            siblingElement.push(sibs[i]);
        }
    }
    return siblingElement;
};
function tabClick() {
    //修改标签样式
    this.classList.add('hexo-douban-active');
    var sibs = this.siblings();
    for (var j = 0; j < sibs.length; j++) {
        sibs[j].classList.remove('hexo-douban-active');
    }
    //显示对应板块
    var itemId = this.id.replace('tab', 'item');
    var target = document.getElementById(itemId);
    target.classList.remove('hexo-douban-hide');
    target.classList.add('hexo-douban-show');
    sibs = document.getElementById(itemId).siblings();
    for (var k = 0; k < sibs.length; k++) {
        sibs[k].classList.remove('hexo-douban-show');
        sibs[k].classList.add('hexo-douban-hide');
    }
}
var tabs = document.getElementsByClassName("hexo-douban-tab");
for (var i = 0; i < tabs.length; i++) {
    tabs[i].onclick = tabClick;
    tabs[i].onclick.apply(tabs[i]);
}
tabs[2].click();

    var firstpages = document.getElementsByClassName("hexo-douban-firstpage");
var previouspages = document.getElementsByClassName("hexo-douban-previouspage");
var nextpages = document.getElementsByClassName("hexo-douban-nextpage");
var lastpages = document.getElementsByClassName("hexo-douban-lastpage");
var pagenums = document.getElementsByClassName("hexo-douban-pagenum");

function makePageNum(num, arr) {
    return (num + 1) + ' / ' + (Math.ceil(arr.length / 10 === 0 ? 1 : Math.ceil(arr.length / 10)));
}

function firstBtn() {
    var sibs = this.parentNode.siblings();
    displayPage(sibs, 0);
    this.parentNode.getElementsByClassName('hexo-douban-pagenum')[0].innerText = makePageNum(0, sibs);
}

function previousBtn() {
    var sibs = this.parentNode.siblings();
    var currNum = this.parentNode.getElementsByClassName('hexo-douban-pagenum')[0].innerText;
    currNum = currNum.substr(0, currNum.indexOf('/') - 1);
    currNum = parseInt(currNum, 10) - 1;
    if (currNum > 0) {
        currNum--;
    }
    displayPage(sibs, currNum);
    this.parentNode.getElementsByClassName('hexo-douban-pagenum')[0].innerText = makePageNum(currNum, sibs);
}

function nextBtn() {
    var sibs = this.parentNode.siblings();
    var currNum = this.parentNode.getElementsByClassName('hexo-douban-pagenum')[0].innerText;
    currNum = currNum.substr(0, currNum.indexOf('/') - 1);
    currNum = parseInt(currNum, 10) - 1;
    if (currNum < Math.ceil(sibs.length / 10) - 1) {
        currNum++;
    }
    displayPage(sibs, currNum);
    this.parentNode.getElementsByClassName('hexo-douban-pagenum')[0].innerText = makePageNum(currNum, sibs);
}

function lastBtn() {
    var sibs = this.parentNode.siblings();
    displayPage(sibs, Math.ceil(sibs.length / 10) - 1);
    this.parentNode.getElementsByClassName('hexo-douban-pagenum')[0].innerText = makePageNum(Math.ceil(sibs.length / 10) - 1 === -1 ? 0 : Math.ceil(sibs.length / 10) - 1, sibs);
}

function displayPage(arr, num) {
    for (var i = 0; i < arr.length; i++) {
        if (Math.floor(i / 10) === num) {
            arr[i].classList.remove('hexo-douban-hide');
            var img = arr[i].getElementsByTagName('img')[0];
            img.src = img.getAttribute('data-src');
        } else {
            arr[i].classList.add('hexo-douban-hide');
        }
    }
}

for (var i = 0; i < firstpages.length; i++) {

    //add listener
    firstpages[i].onclick = firstBtn;
    previouspages[i].onclick = previousBtn;
    nextpages[i].onclick = nextBtn;
    lastpages[i].onclick = lastBtn;

    //set page num
    var size = pagenums[i].parentNode.siblings().length;
    pagenums[i].innerText = '1 / ' + (Math.ceil(size / 10) === 0 ? 1 : Math.ceil(size / 10));
    firstpages[i].click();
}
</script>

2.创建_data书单数据文件

在根目录创建目录_data,然后在_data目录下创建如下四个文件:booksyd.ymlbookszd.ymlbooksxd.ymlbookstj.yml

(1)已读书单数据

已读书单数据文件为booksyd.yml,数据格式为:

- name: "风雪追击01"    #书名
  author: "[日] 东野圭吾"    #作者
  translator: "赵文梅"    #翻译者
  press: "现代出版社"    #出版社
  publishdate: "2017-4"    #出版日期
  price: "39.80元"    #价格
  bookimg: "https://img1.doubanio.com/view/subject/m/public/s29362779.jpg"    #封面图片链接地址
  doubanurl: "https://book.douban.com/subject/26971148/"    #豆瓣书单地址
  readdate: "2018-12-29"    #阅读日期
  booktag: "文学"    #书的分类标签
  stars: "★★★☆☆"    #评价星级
  rate: "还行"    #1到5星分别为很差、较差、还行、推荐、力荐
  review: "等待也是种信念,海的爱太深,时间太浅。"    #书评

以上数据信息可以在豆瓣上查找。
评价等级(stars)与推荐等级(rate)的对应关系:

  • ★☆☆☆☆ 很差
  • ★★☆☆☆ 较差
  • ★★★☆☆ 还行
  • ★★★★☆ 推荐
  • ★★★★★ 力荐

(2)想读书单数据

已读书单数据文件为booksxd.yml,数据格式为:

- name: "风雪追击03"    #书名
  author: "[日] 东野圭吾"    #作者
  translator: "赵文梅"    #翻译者
  press: "现代出版社"    #出版社
  publishdate: "2017-4"    #出版日期
  price: "39.80元"    #价格
  bookimg: "https://img1.doubanio.com/view/subject/m/public/s29362779.jpg"    #封面图片链接地址
  doubanurl: "https://book.douban.com/subject/26971148/"    #豆瓣书单地址
  readdate: "2018-12-29"    #阅读日期
  booktag: "文学"    #书的分类标签

(3)在读书单数据

已读书单数据文件为bookszd.yml,数据格式为:

- name: "风雪追击05"    #书名
  author: "[日] 东野圭吾"    #作者
  translator: "赵文梅"    #翻译者
  press: "现代出版社"    #出版社
  publishdate: "2017-4"    #出版日期
  price: "39.80元"    #价格
  bookimg: "https://img1.doubanio.com/view/subject/m/public/s29362779.jpg"    #封面图片链接地址
  doubanurl: "https://book.douban.com/subject/26971148/"    #豆瓣书单地址
  readdate: "2018-12-29"    #阅读日期
  booktag: "文学"    #书的分类标签

(4)书单数目统计

已读书单数据文件为bookstj.yml,数据格式为:

zdnum: "2"    #在读书单数目
xdnum: "2"    #想读书单数目
ydnum: "12"    #已读书单数目
booknote: "本页面正在测试中。"    #书单页面的提示语

完成!


版权声明:本文由 Duter2016 在 2019年10月27日发表。本文采用CC BY-NC-SA 4.0许可协议,非商业转载请注明出处,不得用于商业目的。
文章题目及链接:《Jekyll不使用插件生成「书单」页面》




  相关文章:

「游客及非Github用户留言」:

「Github登录用户留言」:

TOP