life is like a dream

如何在Hexo中实现自适应响应式相册功能

    教程     Hexo

  1. 技术选型
  2. 相册文件夹
  3. 相册页面
  4. 脚本
  5. photo.js
  6. css
  7. 自动构建

用最清晰简洁的方法整合一个响应式相册
示意图

效果

技术选型

  • 由于我选用的主题使用了fancyBox作为图片弹出展示的框架,查看后表示很不错,能满足需要
    http://fancyapps.com/fancybox/3/
  • 图片加载可能会太慢,所以还需要一个图片延迟加载插件 Lazyload
  • 想使用瀑布流作为展示,粗略了解了下,便使用开源的MiniGrid,原因是它很小巧也刚好满足需求(ps:它的文档让我看了很捉急,不完善的文档是个大坑)

相册文件夹

按照Hexo官方给的建议

资源(Asset)代表 source 文件夹中除了文章以外的所有文件,例如图片、CSS、JS 文件等。比方说,如果你的Hexo项目中只有少量图片,那最简单的方法就是将它们放在 source/images 文件夹中。然后通过类似于 ![](/images/image.jpg) 的方法访问它们。
对于那些想要更有规律地提供图片和其他资源以及想要将他们的资源分布在各个文章上的人来说,Hexo也提供了更组织化的方式来管理资源。这个稍微有些复杂但是管理资源非常方便的功能可以通过将 config.yml 文件中的 post_asset_folder 选项设为 true 来打开。

1
post_asset_folder: true

然后就可以在文件夹source下新建一个相册文件夹Images,将照片放入这个文件夹

相册页面

我们需要一个相册页面以加载所有照片

1
2
3
4
5
6
7
8
9
10
11
12

---
title: 相册
noDate: 'true'
---
<script src="https://cdn.bootcss.com/jquery_lazyload/1.9.7/jquery.lazyload.js"></script>
<script src="https://unpkg.com/minigrid@3.1.1/dist/minigrid.min.js"></script>

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

<script src="/js/photo.js"></script>

这里使用noDate来自定义一些HTML数据,加载一些JS文件(minigrid在bootcss中还是1.*的版本,只好使用它推荐的cdn了),其中photo.js是自定义的,用来加载照片,稍后提到。
现在,我们就有一个相册页面了,接下来的问题是怎么批量加载那些照片。

脚本

大家可以集思广益,使用别的方式。(毕竟我不是专业的前端)
在博客主文件夹下新建tool.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
"use strict";

const fs = require("fs");
const sizeOf = require('image-size');
const path = "./source/Images";
const outputfile = "./source/Images/output.json";
var dimensions;

let arr = [];
function tryToSave() {
arr = JSON.stringify(arr, null, "\t")
fs.writeFile(outputfile, arr, e => {
if(e) console.log(e);
else console.log("SAVE OVER");
})
}
function tryToReadDir() {
fs.readdir(path, (err, files) => {
if (err) return;

files.forEach((fileName) => {
fs.stat(path + "/" + fileName, function (err, stats) {
if (err) return;

if (stats.isFile()) {
dimensions = sizeOf(path + "/" + fileName);
// console.log(dimensions.width, dimensions.height);
arr.push(dimensions.width
+ '.' + dimensions.height
+ ' ' + fileName);
count();
}
})
})

var countNum = 0;
var count = function() {
countNum++;
if(countNum === files.length) {
tryToSave();
}
}
});
}

fs.exists(outputfile, function (exists) {
if(exists)
fs.unlink(outputfile, e => {
console.log("remove file done!!! exception: " + e)
tryToReadDir();
})
else
tryToReadDir();
});

每次在相册中更新照片后都要在控制台node tool.js一下,以便更新数据。
它会生成一个json文件,带有每张照片的长宽及文件名。
需要它的宽高是因为我们需要它满足瀑布流样式。
output.json样式类似于:

1
2
3
4
5
6
7
[
"3120.4160 发票.jpg",
"516.516 头像.jpg",
"402.180 录音.jpeg",
"720.758 截图1.jpg",
"720.978 截图2.jpg"
]

photo.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
photo ={
page: 1,
offset: 20,
init: function () {
var that = this;
$.getJSON("/photo/output.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, li = "";
for (var i = begin; i < end && i < data.length; i++) {

li += '<div class="card">' +
'<div class="ImageInCard">' +
'<a data-fancybox="gallery" href="/Images/' + data[i] + '">' +
'<img src="/Images/' + data[i] + '"/>' +
'</a>' +
'</div>' +
'<div class="TextInCard">'+data[i].split('.')[0]+'</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();

js文件也可以放在Images文件夹下,只需要将相册页面加载的<script src="/js/photo.js"></script>改成<script src="/Images/photo.js"></script>即可。

css

这个样式是我自己写的,大家可以按照自己的想法自行更改:

1
2
3
4
5
.ImageGrid {width: 100%;max-width: 1040px;margin: 0 auto; text-align: center;}
.card {overflow: hidden;transition: .3s ease-in-out; border-radius: 8px; background-color: #ddd;}
.ImageInCard {}
.ImageInCard img {padding: 0 0 0 0;}
.TextInCard {line-height: 54px; background-color: #ffffff; font-size: 24px;}

自动构建

我是使用过travis-ci自动构建的。(用过以后表示很鸡肋)
如果你也使用了这个的话,在travis.yml中的script或者before_script,添加一句node tool.js,就可以将相册脚本也加入自动构建(需要注意的是必须在hexo g前执行):

1
2
3
script:
- node tool.js
- hexo g
page PV:  ・  site PV:  ・  site UV: