Hexo next 博客增加瀑布流相册页面

参考:asdfv1929’s Home - Hexo NexT主题内添加相册功能

要展示自己拍摄的一些照片,可以给博客添加一个瀑布流的相册页面。

1. 创建页面和导航栏

首先新建相册页面 hexo new page photos,这样会在 /source/ 下创建 photos/index.md,在其中添加 type: picture

之后在主题配置文件中对应位置 menu 里添加 photos: /photos || camera-retro ,这样生成后就有导航栏菜单了。

2. json 文件处理图片信息

在博客根目录的 /scripts/ 文件夹下新建一个 phototool.js 文件,内容如下。主要功能是访问照片文件夹,获取每张照片的大小和文件名,并生成对应的 json 文件:

"use strict";
    const fs = require("fs");
    const sizeOf = require('image-size');
    //本地照片所在目录
    const path = "source/photos/images"; 
    //要放置生成的照片信息文件目录,建议直接放在 source/photos/ 文件夹下
    const output = "source/photos/photoslist.json";
    var dimensions;
    fs.readdir(path, function (err, files) {
        if (err) {
            return;
        }
        let arr = [];
        (function iterator(index) {
            if (index == files.length) {
                fs.writeFileSync(output, JSON.stringify(arr, null, "\t"));
                return;
            }
            fs.stat(path + "/" + files[index], function (err, stats) {
                if (err) {
                    return;
                }
                if (stats.isFile()) {
                    dimensions = sizeOf(path + "/" + files[index]);
                    console.log(dimensions.width, dimensions.height);
                    arr.push(dimensions.width + '.' + dimensions.height + ' ' + files[index]);
                }
                iterator(index + 1);
            })
        }(0));
    });

创建好并把照片放在目录后,执行以下命令:

cd <folder-path>  #定位到 Hexo 博客目录
npm install image-size  #如果已安装了 image-size 可以跳过
node scripts/phototool.js  #生成对应的 json 文件

node script/phototool.js这个步骤以后可以不用手动执行,每次 hexo s 或者 hexo deploy 时候会被自动执行。 json 文件样例如下:

[
	"4032.3024 IMG_0391.JPG",
	"12500.3874 IMG_0404.JPG",
	"4032.3024 IMG_0416.JPG",
	"4032.3024 IMG_0424.JPG",
	"3024.4032 IMG_0427.JPG",
	"4032.3024 IMG_0429.JPG",
	"4032.3024 IMG_0430.JPG"
]

3. photo.js 和 minigrid.min.js

/themes/next/source/js/src/ 目录下创建一个 photo.js,内容如下:

photo ={
    page: 1,
    //offset 用于设置照片数量的上限
    offset: 100,
    init: function () {
        var that = this;
        //这里设置的是刚才生成的 json 文件路径
        $.getJSON("/photos/photoslist.json", function (data) {
            that.render(that.page, data);
            //that.scroll(data);
        });
    },
    render: function (page, data) {
        var begin = (page - 1) * this.offset;
        var end = page * this.offset;
        if (begin >= data.length) return;
        var html, imgNameWithPattern, imgName, imageSize, imageX, imageY, li = "";
        for (var i = begin; i < end && i < data.length; i++) {
           imgNameWithPattern = data[i].split(' ')[1];
           imgName = imgNameWithPattern.split('.')[0]
           imageSize = data[i].split(' ')[0];
           imageX = imageSize.split('.')[0];
           imageY = imageSize.split('.')[1];
           //这里 250 指的是图片的宽度,可以根据自己的需要调整相册中照片的大小
            li += '<div class="card" style="width:250px">' +
                    '<div class="ImageInCard" style="height:'+ 250 * imageY / imageX + 'px">' +
                    //href 和 src 的链接地址是相册照片外部链接,也可以放博客目录里
                      '<a data-fancybox="gallery" href="/photos/images/' + imgNameWithPattern + '?raw=true" data-caption="' + imgName + '">' +
                        '<img src="/photos/images/' + imgNameWithPattern + '?raw=true"/>' +
                      '</a>' +
                    '</div>' +
                    // '<div class="TextInCard">' + imgName + '</div>' +  //图片下显示文件名作为说明的功能
                  '</div>'
        }
        $(".ImageGrid").append(li);
        $(".ImageGrid").lazyload();
        this.minigrid();
    },
    minigrid: function() {
        var grid = new Minigrid({
            container: '.ImageGrid',
            item: '.card',
            gutter: 12
        });
        grid.mount();
        $(window).resize(function() {
           grid.mount();
        });
    }
}
photo.init();

minigrid.min.js 可以 下载 获得,放在同样的目录下。

然后如果指向让两个文件在相册页加载,需要修改 /themes/next/layout/_scripts/commons.swig为以下内容,这里的判断语句表示如果页面的类型是 picture 就加载 minigrid.min.jsphoto.js(注意,其他的 js 文件你的可能和我不一样,请将直接原本的内容放在 else 中,比如我额外增加了一个 canvasline.js

{% if page.type ==='picture' %}
{%
  set js_commons = [
    'src/utils.js',
    'src/motion.js',
    'src/minigrid.min.js',
    'src/photo.js',
    'src/canvasline.js'
  ]
%}
{% else %}
{%
  set js_commons = [
    'src/utils.js',
    'src/motion.js',
    'src/canvasline.js'
  ]
%}
{% endif %}

{% for common in js_commons %}
  <script type="text/javascript" src="{{ url_for(theme.js) }}/{{ common }}?v={{ version }}"></script>
{% endfor %}

4. 配置样式

按照我在 CSS 自定义样式文件中的 设置,设置好相册的样式。

5. 开启 lazyload 和 fancybox

在主题配置文件中,一步一步按照说明安装和开启 lazyloadfancybox 功能即可,不再赘述。

6. 放入相册

在第一步创建好的 /source/photos/index.md 文档中编辑好自己需要的相册页面内容,在需要放置相册的位置加入以下内容即可:

<div class="ImageGrid"></div>

最后 hexo clean && hexo deploy -g 就可以把相册页设置好了。

总结

终于有了瀑布流的相册页面功能了,之前尝试了好多种方法都不尽如人意,借鉴了 asdfv1929 的方法这次终于搞定,还是很开心的。当然因为 asdfv1929 的方法对主题源文件做了过多的修改,导致步骤看起来有点复杂了,所以我自己稍微进行了改进,这样操作起来更加容易。