---
title: 照片墙开发记录
date: 2019-05-12 15:17:29
tags:
- 前端
- Hexo
categories:
- 前端杂烩
---
依稀记得刚使用hexo的时候, 大部分的照片墙解决方案还是调用**Instagram**的接口
毕竟这是个很方便上传和管理照片的平台
如今墙一天比一天高, 这方案也基本不灵了
现在博客用上了对象存储作为图片库, 照片墙实现起来也可以有另一套办法了
先整理一下思路, 大概是以下几个步骤
1. 上传图片到对象存储仓库, 这个可以写个脚本跑一遍就可以了
但是考虑到页面加载这些图片时候的性能问题
计划是把100张图作为一组, 每组一个目录, 这个目录当中除了这100张图片, 还有一个json文件, 是该组的文件列表
为动态加载提供方便
2. 创建自定义页面, 这个hexo本身就支持, 直接在里面写html代码即可
但是由于hexo本身对于md文件的渲染策略, 每一行都会加上`
`
在普通文章里面没什么, 在这个纯html页面就会影响DOM结构, 修改hexo的渲染策略会影响所有页面
所以要注意这个md文件正文不能有换行
3. 照片墙页面的布局, 这个准备采用瀑布流的模式, 跟已被关闭的Google plus ~~(深切缅怀🕯)~~ 一样的布局结构
4. 分页加载以及滚动加载的一些实现
### 上传图片
根据这次的需要改造一下图片上传的js脚本
跟之前的差不多, 不过这次引入一个[images](https://www.npmjs.com/package/images)库
这个库有一些对图片进行操作的API, 准备用它来获取到图片的宽高, 也写入到json文件里面
```javascript
const argv = {
rootPath: 'F:\\WallPaper\\', // 本地图片所在位置
prefix: 'photo-wall',
step: 100
}
const listImages = require('./list_images')
// 当前本地存在的所有图片
const imagesList = listImages(argv.rootPath, argv.prefix)
const setting = require('./auth_info.json'),
fs = require('fs'),
path = require('path'),
nos = require('@xgheaven/nos-node-sdk'),
images = require('images')
const client = new nos.NosClient(setting)
_uploadObject(imagesList)
/**
* 上传文件对象
* @param {Array} filesList 待上传的文件列表
* @param {Number} index 索引值
* @param {Array} group 文件的分组信息
*/
function _uploadObject(filesList, index=0, groups=[]) {
if(index >= filesList.length) {
groups[groups.length-1].end = index
uploadList(filesList, groups)
return
}
if(!groups.length) { // 对于空对象, 放入第一个分组
groups.push({start:index})
}
let img = images(path.resolve(argv.rootPath, filesList[index].name))
filesList[index].width = img.width()
filesList[index].height = img.height()
let objectKey = filesList[index].name.replace(argv.prefix, `${argv.prefix}/${groups.length}`)
let body = fs.createReadStream(path.resolve(argv.rootPath, filesList[index].name))
filesList[index].name = objectKey
if((index + 1) % argv.step === 0) {
// 到达一个分组的末尾
groups[groups.length-1].end = index
uploadList(filesList, groups)
groups.push({start:index+1})
}
client.putObject({objectKey, body}).then(result => {
// eTag是上传后远端校验的md5值, 用于和本地进行比对
let eTag = result.eTag.replace(/"/g,'')
if(filesList[index].md5 === eTag) {
console.log(`${filesList[index].name} 上传成功, md5:${eTag}`)
} else {
console.warn(`${filesList[index].name} 上传出错, md5值不一致`)
console.warn(`===> 本地文件: ${filesList[index].md5}, 接口返回: ${eTag}`)
}
_uploadObject(filesList, ++index, groups)
})
}
/**
* 上传文件列表json
* @param {Array} filesList
* @param {Array} groups
*/
function uploadList(filesList, groups) {
client.putObject({
objectKey: `${argv.prefix}/${groups.length}/list.json`,
body: Buffer.from(JSON.stringify({
start: groups[groups.length-1].start,
end: groups[groups.length-1].end,
files: filesList.slice(groups[groups.length-1].start, groups[groups.length-1].end+1)
}))
}).then(result => {
console.log(result.eTag)
})
}
```
其中需要对文件名进行替换修改, 改为在该分组内的正确目录
执行完成后, 对象存储仓库的photo-wall目录下就已经有若干个数字命名的子目录了
每个子目录里面都有至多100张图片和一个json文件
比如第一组中json文件的内容为
```json
{
"start":0,
"end":99,
"files":[{"name":"xxx.png","md5":"xxxx","width":300,"height":200}...]
}
```
### 创建自定义页面
在source目录下创建`photo_wall`目录, 其中创建`index.md`文件
```md
---
title: 照片墙
date: 2019-05-12 15:50:10
pageid: PhotoWall
---