抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

前言

功能参考自 AIGISSS
效果查看本站更多中的相册页面

目前已知的问题:
1.不支持pjax
2.分类功能无法使用
3.懒加载无法使用,使用懒加载后图片不显示
4.目前的样式可能稍显单调
优势:
1.可以使用GitHub action自动构建
2.走jsd免费cdn加速,访问快

思路

利用image-size生成图片的json,然后图片存储在GitHub利用jsd加速访问(跟白嫖GitHub做图床一样)。然后通过js生成完整的图片链接信息,生成页面。

步骤

新建照片页面

执行命令新建页面

hexo new page photos

在source/photos/index.md中写入以下内容

---
layout: photos
comments: false
meta:
header: []
footer: []
sidebar: []
---

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

修改主题配置文件

打开_config.volantis.yml文件,添加导航按钮:

        - name: 相册
          icon: fad fa-images # pro
          url: photos/

这里我使用的pro版图标,如果使用默认的图标请把icon改为fas fa-images
pjax排除:
搜索pjax并添加

       - /photos/        # 相册页面不支持pjax

处理照片信息

这里我选择跟博客共用一个仓库,方便action自动部署。当然你也可以使用单独的一个仓库来存储,示例:photos
在博客根目录新建一个photos文件夹,在里面新建一个tool.js文件,并把以下内容粘贴到tool.js中。

const fs = require('fs-extra');
const path = require('path');
const imageSize = require('image-size');

const rootPath="photos/"

class PhotoExtension {
    constructor() {
        this.size = 64;
        this.offset = [0, 0];
    }
}

class Photo {
    constructor() {
        this.dirName = '';
        this.fileName = '';
        this.iconID = '';
        this.extension = new PhotoExtension();
    }
}

class PhotoGroup {
    constructor() {
        this.name = '';
        this.children = [];
    }
}

function createPlotIconsData() {
    let allPlots = [];
    let allPlotGroups = [];

    const plotJsonFile = path.join(__dirname, '../source/photos/photosInfo.json');
    const plotGroupJsonFile = path.join(__dirname, '../source/photos/photos.json');

    if (fs.existsSync(plotJsonFile)) {
        allPlots = JSON.parse(fs.readFileSync(plotJsonFile));
    }

    if (fs.existsSync(plotGroupJsonFile)) {
        allPlotGroups = JSON.parse(fs.readFileSync(plotGroupJsonFile));
    }

    fs.readdirSync(__dirname).forEach(function(dirName) {
        const stats = fs.statSync(path.join(__dirname, dirName));
        const isDir = stats.isDirectory();
        if (isDir) {
            const subfiles = fs.readdirSync(path.join(__dirname, dirName));
            subfiles.forEach(function(subfileName) {
                // 如果已经存在 则不再处理
                // if (allPlots.find(o => o.fileName === subfileName && o.dirName === dirName)) {
                //     return;
                // }

                // 新增标
                const plot = new Photo();
                plot.dirName = dirName;
                plot.fileName = subfileName;
                const imageInfo = imageSize(rootPath+dirName + "/" + subfileName);
                plot.iconID = imageInfo.width + '.' + imageInfo.height + ' ' + subfileName;
                allPlots.push(plot);
                console.log(`RD: createPlotIconsData -> new plot`, plot);

                // 为新增标添加分组 暂时以它所处的文件夹为分组
                let group = allPlotGroups.find(o => o.name === dirName);
                if (!group) {
                    group = new PhotoGroup();
                    group.name = dirName;
                    allPlotGroups.push(group);
                    console.log(`RD: createPlotIconsData -> new group`, group);
                }
                group.children.push(plot.iconID);
            });
        }
    });

    fs.writeJSONSync(plotJsonFile, allPlots);
    fs.writeJSONSync(plotGroupJsonFile, allPlotGroups);
}

createPlotIconsData();

这里的第5行

const rootPath="photos/"

这个是图片的路径
第34、35行

    const plotJsonFile = path.join(__dirname, '../source/photos/photosInfo.json');
    const plotGroupJsonFile = path.join(__dirname, '../source/photos/photos.json');

这个是json的输出路径,可以按需更改。
之后在photos文件夹下新建任意名称的文件夹,再把照片放进去。示例:

之后安装image-size

npm i -S image-size

之后执行命令

node photos/tool.js

查看source/photos/文件夹下是否生成json
这里注意,如果是使用macOS的话,可能因为系统自动生成的.DS_Store文件报错,删除后.DS_Store后再执行一般就不会报错了。

删除命令

find ~ -name ".DS_Store" -delete

看到能正常生成后即可。

修改GitHub action配置

编辑.github/workflows/下的yml文件,添加两个命令

rm -rf source/photos/*.json
node photos/tool.js

这个image-size有个弊端就是如果不删除之前生成json,删除照片后再生成的json里也会有已删除的照片信息,所以建议每次修改照片后生成json前都先删除之前生成的json。
示例:

添加ejs

在themes/volantis/layout/目录下新建photos.ejs,并粘贴以下内容:

<%- js(theme.plugins.jquery) %>
<link rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css">
<script src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/minigrid@3.1.1/dist/minigrid.min.js"></script>
<script src="../js/photos.js"></script>
<%- partial('_pre') %>
<% page.comments = false; %>
<div class='l_main<%- page.sidebar == false ? ' no_sidebar' : '' %>'>
    <%- partial('_partial/article', {post: page, index: false}) %>
</div>
<%- partial('_partial/side') %>

添加photos.js

在themes/volantis/source/js目录下新建photos.js,并粘贴以下内容:

var imgDataPath = "./photos.json"; //图片名称高宽信息json文件路径
var imgPath = "https://cdn.jsdelivr.net/gh/Goopher97/blog_volantis_auto@main/photos/"; //图片访问路径
var imgMaxNum = 50; //图片显示数量

var windowWidth =
    window.innerWidth ||
    document.documentElement.clientWidth ||
    document.body.clientWidth;
if (windowWidth < 768) {
    var imageWidth = 145; //图片显示宽度(手机端)
} else {
    var imageWidth = 250; //图片显示宽度
}

const photo = {
    page: 1,
    offset: imgMaxNum,
    init: function () {
        var that = this;
        $.getJSON(imgDataPath, function (data) {
            that.render(that.page, data);
            //that.scroll(data);
            that.eventListen(data);
        });
    },
    constructHtml(options) {
        const {
            imageWidth,
            imageX,
            imageY,
            name,
            imgPath,
            imgName,
            imgNameWithPattern,
        } = options;
        const htmlEle = `<div class="card lozad" style="width:${imageWidth}px">
                  <div class="ImageInCard" style="height:${ (imageWidth * imageY) / imageX }px">
                    <a data-fancybox="gallery" href="${imgPath}${name}/${imgNameWithPattern}" data-caption="${imgName}" title="${imgName}">
                            <img src="${imgPath}${name}/${imgNameWithPattern}">
                    </a>
                  </div>
                </div>`;
        return htmlEle;
    },
    render: function (page, data = []) {
        this.data = data;
        if (!data.length) return;
        var html,
            imgNameWithPattern,
            imgName,
            imageSize,
            imageX,
            imageY,
            li = "";

        let liHtml = "";
        let contentHtml = "";

        data.forEach((item, index) => {
            const activeClass = index === 0 ? "active" : "";
            liHtml += `<li class="nav-item" role="presentation">
          <a class="nav-link ${activeClass} photo-tab" id="home-tab" photo-uuid="${item.name}" data-toggle="tab" href="#${item.name}"  role="tab" aria-controls="${item.name}" aria-selected="true">${item.name}</a>
        </li>`;
        });
        const [initData = {}] = data;
        const {children = [], name} = initData;
        children.forEach((item, index) => {
            imgNameWithPattern = item.split(" ")[1];
            imgName = imgNameWithPattern.split(".")[0];
            imageSize = item.split(" ")[0];
            imageX = imageSize.split(".")[0];
            imageY = imageSize.split(".")[1];
            let imgOptions = {
                imageWidth,
                imageX,
                imageY,
                name,
                imgName,
                imgPath,
                imgNameWithPattern,
            };
            li += this.constructHtml(imgOptions);
        });
        contentHtml += ` <div class="tab-pane fade show active"  role="tabpanel" aria-labelledby="home-tab">${li}</div>`;

        const ulHtml = `<ul class="nav nav-tabs" id="myTab" role="tablist">${liHtml}</ul>`;
        const tabContent = `<div class="tab-content" id="myTabContent">${contentHtml}</div>`;

        $("#imageTab").append(ulHtml);
        $(".ImageGrid").append(tabContent);
        this.minigrid();
    },
    eventListen: function (data) {
        let self = this;
        var html,
            imgNameWithPattern,
            imgName,
            imageSize,
            imageX,
            imageY,
            li = "";
        $('a[data-toggle="tab"]').on("shown.bs.tab", function (e) {
            $(".ImageGrid").empty();
            const selectId = $(e.target).attr("photo-uuid");
            const selectedData = data.find((data) => data.name === selectId) || {};
            const {children, name} = selectedData;
            let li = "";
            children.forEach((item, index) => {
                imgNameWithPattern = item.split(" ")[1];
                imgName = imgNameWithPattern.split(".")[0];
                imageSize = item.split(" ")[0];
                imageX = imageSize.split(".")[0];
                imageY = imageSize.split(".")[1];
                let imgOptions = {
                    imageWidth,
                    imageX,
                    imageY,
                    name,
                    imgName,
                    imgPath,
                    imgNameWithPattern,
                };
                li += self.constructHtml(imgOptions);
            });
            $(".ImageGrid").append(li);
            self.minigrid();
        });
    },
    minigrid: function () {
        var grid = new Minigrid({
            container: ".ImageGrid",
            item: ".card",
            gutter: 12,
        });
        grid.mount();
        $(window).resize(function () {
            grid.mount();
        });
    },
};
photo.init();

这里注意第一二行,如果使用单独的仓库存放照片,记得修改加速的链接和json的链接。

添加photos.styl样式

在themes/volantis/source/css/_other目录下新建photos.styl文件,并粘贴以下内容:

.ImageGrid {
  width: 100%;
  max-width: 1040px;
  margin: 0 auto;
  text-align: center;
}
.card {
  display: flex;
  float: left;
  overflow: hidden;
  transition: .3s ease-in-out;
  border-radius: 8px;
  background-color: rgba(255, 255, 255, 0);
  padding: 1.4px;
}
.ImageInCard {
  display block
}
.ImageInCard img {
  padding: 0;
  border-radius: 8px;
  width:100%;
  height:100%;
}

记得引入这个样式文件,在style.styl文件中添加:

@import '_other/*'

最后

如果大佬完善了,请给我留言,让我学习学习。

评论