给博客添加一个相册页面,以展示自己拍摄的一些照片 (≖ᴗ≖)✧
_config.next.yml
首先新建hexo new page photos
相册页面,将会在source/
下创建photos/index.md
,在其中添加type: photos
之后在主题_config.next.yml
文件中对应位置menu
里添加Photos: /photos/ || image
,这样生成后就能在页面的对应页面选项中有该相册Tab。
1 2
| menu: photos: /photos/ || fas fa-camera-retro
|
scripts
在博客根目录下新建scripts
文件夹,里面将会存放相关js文件。
新建scripts/phototool.js
文件,里面内容如下,主要功能是访问照片文件夹,获取每张照片的size和name,并生成对应的json文件:
命令:Git Bash
中键入 node phototool.js
生成json
注:若出现Error: Cannot find module 'axios'
问题,请在Git Bash
中键入对应命令npm install image-size
进行安装。
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| const axios = require("axios"); const fs = require("fs"); const path = require("path");
const OWNER = "xxxxx"; const REPO = "xxxx"; const BRANCH = "master"; const TOKEN = "ghp_Czclu19lnkjrACxxxxxxxxxxxxxxxxxxxxx"; const API_URL = `https://api.github.com/repos/${OWNER}/${REPO}/contents`; const OUTPATH = "source/images/picX"; const GenerateImg = ["DevOps","docker","rabbitMQ","redis"]
async function fetchFiles(dir = "") { const url = dir ? `${API_URL}/${dir}?ref=${BRANCH}` : `${API_URL}?ref=${BRANCH}`; try { const { data } = await axios.get(url, { headers: { Authorization: `token ${TOKEN}`, }, });
const tasks = data.map(async (item) => { if (item.type === "file" && /\.(jpg|jpeg|png|webp|gif)$/i.test(item.name)) { return { name: item.name, width: 0, height: 0, path: item.path, size: item.size, url: item.html_url }; } else if (item.type === "dir") { if (GenerateImg.includes(item.name)) { const folderData = await fetchFiles(item.path); saveJsonToFile(item.name, folderData); } return null; } });
return (await Promise.all(tasks)).filter(Boolean); } catch (error) { console.error(`获取目录 ${dir} 失败: `, error.message); return []; } }
function saveJsonToFile(folderName, data) { const folderPath = path.join(OUTPATH, folderName); if (!fs.existsSync(folderPath)) { fs.mkdirSync(folderPath, { recursive: true }); } if (data == null) return const filePath = path.join(folderPath, `${folderName}_info.json`); fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8"); console.log(`JSON文件已保存到: ${filePath}`); }
(async function main() { console.log("开始获取GitHub图床数据喵..."); await fetchFiles(); console.log("所有数据已处理完成喵!"); })();
|
文件样例如下:
生成文件的路径source/images/picX/docker/docker_info.json
1 2 3 4 5 6 7 8 9 10
| [ { "name": "Untitled-1.ic5ab26hd.webp", "width": 0, "height": 0, "path": "docker/Untitled-1.ic5ab26hd.webp", "size": 14830, "url": "https://github.com/xxxxx/picx-xxxxxx/blob/master/docker/Untitled-1.ic5ab26hd.webp" }, ]
|
新建scripts/inline-tags.js
文件,里面内容如下,主要功能是注入方法,根据指定的路径生成相册以及图片的Html元素:
inline-tags.js
内容如下,主要功能是访问json文件内容,遍历每行数据,并在页面对应位置上放置代码,展示图片(其中图片链接为自个GitHub相册库中图片的链接):
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 55 56
| 'use strict';
const cosDomain = hexo.config.cos_domain; const cos_base = hexo.config.cos_base;
hexo.extend.injector.register('head_begin', () => {
return ` <link rel="preconnect" href="${cosDomain}" crossorigin="">`; });
hexo.extend.tag.register('dot', function (args) { return `<span class="emphasis-point">${args.join(' ')}</span>`; });
hexo.extend.tag.register('album', function (args) { const photoSrc = cosDomain + '/'; const jsonSrc = cos_base + `/images/picX/${args}` + `/${args}_info.json`; return ` <style> .post-block { padding-left: 10px; padding-right: 10px; } </style> <div class="album" photo-src="${photoSrc}" json-src="${jsonSrc}"></div> `; });
hexo.extend.tag.register('subpagebox', function ([args, delimiter = '|', comment = '%'], content) { console.log(args, delimiter, comment, content); const links = content.split('\n').filter(line => line.trim() !== '').map(line => { const item = line.split(delimiter).map(arg => arg.trim()); const imageSource = cosDomain + '/' + item[1] + '/' + item[2]; if (item[0][0] === comment) return ''; return ` <div class="subpage-box-cover"> <a style="width: 100%;" href="${item[1]}/"> <p class="image-caption">${item[0]}</p> <img alt="${item[0]}" src="${imageSource}"> </a> </div> `; }); return `<div class="subpage-box">${links.join('')}</div>`; }, true);
|
路径photos/index.md
添加内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| --- title: 相册 date: 2024-11-18 15:41:38 type: "photos" comments: false ---
<div class="text-center">岁月无声,光影留痕。</div>
<!-- inline-tags.js 注入的子页面方法subpagebox --> <!-- 文件夹名称 | 文件夹名称 | 对应标签的主封面 --> <!-- redis | redis | logo.491b7w38xo.webp -->
{% subpagebox %} redis | redis | logo.491b7w38xo.webp docker | docker | logo.1027b8euuh.webp rabbitMQ | rabbitMQ | image.5j48e7lwua.webp DevOps | DevOps | logo.7ax7942wpp.svg {% endsubpagebox %}
|
相册菜单子页面
路径photos/docker/index.md
添加内容如下
1 2 3 4 5 6 7
| --- title: docker description: <a href="../">光影集</a> / docker --- <!-- inline-tags.js 注入的子页面方法album --> {% album docker %}
|
添加子页面布局
body-end.njk
新增文件_data/body-end.njk
如下
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| {### 相册 ###} {# <script src="https://cdn.jsdelivr.net/npm/minigrid@3.1.1/dist/minigrid.min.js" integrity="sha256-oexHY81/KuGogn0rnUzhYExxPnIyzC4ErClSXE+jFa8=" crossorigin="anonymous"></script> #} <script src="/resources/minigrid.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script{{ pjax }} type="text/javascript"> var album = document.querySelector(".album"); if (album) { // 相册列表 JSON 数据 var imgDataPath = album.getAttribute('json-src'); // 照片存储路径 var imgPath = album.getAttribute('photo-src'); // 最多显示数量 var imgMaxNum = 50; // 获取窗口大小以决定图片宽度 var windowWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; var imageWidth;
if (windowWidth < 768) { imageWidth = 145; // 移动端图片宽度 } else { imageWidth = 235; }
// 生成相册 var linkDataPath = imgDataPath; var photo = { page: 1, offset: imgMaxNum, init: function () { var that = this; $.getJSON(linkDataPath, function (data) { that.render(that.page, data); }); }, render: function (page, data) { var begin = (page - 1) * this.offset; var end = page * this.offset; if (begin >= data.length) return; var imgNameWithPattern, imgName, imageSize, imageX, imageY, li = ""; for (var i = begin; i < end && i < data.length; i++) { imgNameWithPattern = data[i].path; imgName = data[i].name; imageSize = data[i].size; li += '<div class="card" style="width:' + imageWidth + 'px" >'; li += '<div class="album-photo" style="height:' + imageWidth + 'px" >'; li += '<a class="fancybox fancybox.image" href="' + imgPath + imgNameWithPattern + '" itemscope="" itemtype="http://schema.org/ImageObject" itemprop="url" data-fancybox="group" rel="group" data-caption="' + imgName + '" title="' + imgName + '">'; li += '<img data-src="' + imgPath + imgNameWithPattern + '" src="' + imgPath + imgNameWithPattern + '" alt="' + imgName + '" data-loaded="true">'; li += '</a>'; li += '</div>'; li += '</div>'; } album.insertAdjacentHTML('beforeend', li); this.minigrid(); }, minigrid: function () { var grid = new Minigrid({ container: '.album', item: '.card', gutter: 12 }); grid.mount(); window.addEventListener('resize', function () { grid.mount(); }); } }; photo.init(); } </script>
|
引入布局js minigrid.min.js
可以使用远程直接引入
1
| <script src="https://cdn.jsdelivr.net/npm/minigrid@3.1.1/dist/minigrid.min.js" integrity="sha256-oexHY81/KuGogn0rnUzhYExxPnIyzC4ErClSXE+jFa8=" crossorigin="anonymous"></script>
|
也可以下载下来本地引入
1
| <script src="/resources/minigrid.min.js"></script>
|
新增相册页面样式
styles.styl
新增文件_data/styles.styl
如下
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
.subpage-box { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 1.5em; margin-bottom: 3em; }
.subpage-box-cover { margin: 2px; flex: 0 0 30%; background: #333; display: flex; height: 200px; }
.subpage-box-cover a { border-bottom: none; }
.subpage-box-cover img { width: 100%; height: 100%; margin: 0; object-fit: cover; opacity: 0.9;
&:hover{ opacity: 0.7; } }
.subpage-box-cover .image-caption { display: flex; position: relative; z-index: 999; margin: 0; width: 100%; height: 0%; transform: translate(-50%, -50%); left: 50%; top: 50%; justify-content: center; align-items: center; font-size: 1.5em; font-weight: bold; color: white; }
//对齐 .text-center { text-align: center; }
.text-left { text-align: left; }
.text-right { text-align: right; }
.posts-expand .post-body img { }
figcaption { margin: -10px auto 1em; color: #999; font-size: 0.875em; line-height: 1; text-align: center; }
.group-picture { margin-bottom: 5px; }
.group-picture-column .image-caption { margin-top: 10px; }
.group-picture .group-picture-row { display: inline-flex; }
.album { width: 100%; max-width: 1080px; margin: 0 auto; }
.album .card { overflow: hidden; transition: .3s ease-in-out; }
img[src$='#200x'] { width:200px; } img[src$='#250x'] { width:250px; } img[src$='#300x'] { width:300px; } img[src$='#350x'] { width:350px; } img[src$='#400x'] { width:400px; } img[src$='#450x'] { width:450px; } img[src$='#500x'] { width:500px; } img[src$='#550x'] { width:550px; } img[src$='#600x'] { width:600px; } img[src$='#650x'] { width:650px; } img.fancybox-image { width:100%; }
|
替换主题文件
_config.next.yml
1 2 3
| custom_file_path: bodyEnd: source/_data/body-end.njk style: source/_data/styles.styl
|
End
提交博客修改:
hexo clean
hexo g
hexo d
最后可以看看效果了。
最终的效果
总结
以上就是添加相册功能大概流程,因为步骤比较多,且是通过后期回忆步骤进行记录,所以可能存在些许问题,还请原谅,并请把出现的问题在本文下面的评论中点出,我会进行修改。
后续的实现:
- 将照片上传至GitHub相册库时,由于照片分辨率较高,其都达到了两三M以上,上传速度较慢,导致上传进度缓慢。后期想通过代码将照片进行压缩后再上传至相册库。
- 相册展示整个操作流程为:先上传照片到git库,再生成json文件,之后便是正常的clean、g、d,后期想把压缩、上传照片和生成json文件整合到一起。
- 目前的照片展示都是所有照片一整块放一起进行瀑布流显示,后期想将照片根据其旅游场景或类别、时间不同进行分类至对应文件夹,并根据类别或时间线显式展示出不同文件夹下的照片。
参考链接:
hexo主题中添加相册功能