Hexo 相册实践
灵感
想给自已的blog添加一个相册功能、给生活中的点点滴滴留影记录。搜寻网络上给Next主题添加相册功能的基本上没有,只能重头到尾开始一点点的实践。
大致的想法:
1. 相册展示类似于归档一样,按时间戳来分类
2.每一个时间节点都是一个小相册,展示的时候上面是相册的标题,下面是几张经典图片的缩略图
3.点击标题,进行相册的详细页面,可以看到更多关于这个小相册的图片
4.相册展示的特效类似于Lawlite
实践
插件开发实践
由于Hexo基于NodeJS开发的,通过插件的方式集成一些第三方的功能。比如归档是 通过hexo-generator-archive实现的,标签页是通过hexo-generator-tag实现的。更多Hexo插件请看Hexo Plugins.这里就不过多讨论。
本次实践修改的插件有:
1.hexo-generator-archive
2.hexo-generator-index
2.hexo-generator-category
4.hexo-generator-photo[自已新增的]
每一个小相册都是一个MD文件,每次首页和归档生成的时候都会把相册加载进去。我想让相册和博客进行区别,所以在MD文件的开头会声明一个属性isPhoto,true表示相册、false表示普通博客文章。
hexo-generator-archive和hexo-generator-index中去除相册的展示。
修改插件的\lib\generator.js文件,在exports函数,变量声明完加上如下一段代码。
//过滤所有的文章
function filterPhoto(posts){
var tmp = [];
posts.forEach(function(post) {
var isPhoto = post.isPhoto; //相册
if(!isPhoto){
tmp.push(post);
}
});
posts.data = tmp;
posts.length = tmp.length;
}
//hexo-generator-index中调用
filterPhoto(posts);
//hexo-generator-archive中调用
filterPhoto(allPosts);
归档的时候会显示所有文章的总数(包含相册),通过下列方式去除掉。
在hexo-generator-archive插件的\lib\generator.js文件添加如下注释的代码:
function generate(path, posts, options) {
options = options || {};
options.archive = true;
options.postLength = allPosts.length; //新增的
修改归档的展示页面代码(themes\next\layout\archive.swig):
将site.posts.length改为page.postLength即可。
新增hexo-generator-photo插件,自动生成相册时间戳界面,参考hexo-generator-archive插件。
拷贝hexo-generator-archive的源码,主要修改以下几个文件:
1.index.js:
/* global hexo */
'use strict';
var assign = require('object-assign');
// when archive disabled pagination, per_page should be 0.
var per_page;
if (hexo.config.photo === 1) {
per_page = 0;
} else if (typeof hexo.config.per_page === 'undefined') {
per_page = 10;
} else {
per_page = hexo.config.per_page;
}
hexo.config.photo_generator = assign({
per_page: per_page,
yearly: true,
monthly: true,
daily: false
}, hexo.config.photo_generator);
hexo.extend.generator.register('photo', require('./lib/generator'));
2.package.json:
{
"name": "hexo-generator-photo",
"version": "0.0.1",
"description": "photo generator for Hexo.",
"main": "index",
"scripts": {
"eslint": "eslint .",
"jscs": "jscs .",
"test": "mocha test/index.js",
"test-cov": "istanbul cover --print both _mocha -- test/index.js"
},
"directories": {
"lib": "./lib"
},
"repository": "hexojs/hexo-generator-photo",
"homepage": "http://hexo.io/",
"keywords": [
"hexo",
"generator",
"photo"
],
"author": "",
"license": "",
"devDependencies": {
"chai": "^1.9.1",
"eslint": "^1.10.3",
"eslint-config-hexo": "^1.0.2",
"hexo": "^3.1.1",
"istanbul": "^0.4.1",
"jscs": "^2.7.0",
"jscs-preset-hexo": "^1.0.1",
"mocha": "^2.0.1"
},
"dependencies": {
"hexo-pagination": "0.0.2",
"object-assign": "^2.0.0"
}
}
3.generator.js:
'use strict';
var pagination = require('hexo-pagination');
var fmtNum = function(num) {
return num < 10 ? '0' + num : num;
};
module.exports = function(locals) {
var config = this.config;
var photoDir = config.photo_dir;
var paginationDir = config.pagination_dir || 'page';
var allPosts = locals.posts.sort('-date');
var perPage = config.photo_generator.per_page;
var result = [];
if (!allPosts.length) return;
function screenPhoto(posts){
var tmp = [];
posts.forEach(function(post) {
var isPhoto = post.isPhoto; //相册
if(isPhoto){
tmp.push(post);
}
});
posts.data = tmp;
posts.length = tmp.length;
}
screenPhoto(allPosts);
if (photoDir[photoDir.length - 1] !== '/') photoDir += '/';
function generate(path, posts, options) {
options = options || {};
options.photo = true;
options.postLength = allPosts.length;
result = result.concat(pagination(path, posts, {
perPage: perPage,
layout: ['photo', 'index'],
format: paginationDir + '/%d/',
data: options
}));
}
generate(photoDir, allPosts);
if (!config.photo_generator.yearly) return result;
var posts = {};
// Organize posts by date
allPosts.forEach(function(post) {
var date = post.date;
var year = date.year();
var month = date.month() + 1; // month is started from 0
if (!posts.hasOwnProperty(year)) {
// 13 arrays. The first array is for posts in this year
// and the other arrays is for posts in this month
posts[year] = [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]
];
}
posts[year][0].push(post);
posts[year][month].push(post);
// Daily
if (config.photo_generator.daily) {
var day = date.date();
if (!posts[year][month].hasOwnProperty(day)) {
posts[year][month].day = {};
}
(posts[year][month].day[day] || (posts[year][month].day[day] = [])).push(post);
}
});
var Query = this.model('Post').Query;
var years = Object.keys(posts);
var year, data, month, monthData, url;
// Yearly
for (var i = 0, len = years.length; i < len; i++) {
year = +years[i];
data = posts[year];
url = photoDir + year + '/';
if (!data[0].length) continue;
generate(url, new Query(data[0]), {year: year});
if (!config.photo_generator.monthly && !config.photo_generator.daily) continue;
// Monthly
for (month = 1; month <= 12; month++) {
monthData = data[month];
if (!monthData.length) continue;
if (config.photo_generator.monthly) {
generate(url + fmtNum(month) + '/', new Query(monthData), {
year: year,
month: month
});
}
if (!config.photo_generator.daily) continue;
// Daily
for (var day = 1; day <= 31; day++) {
var dayData = monthData.day[day];
if (!dayData || !dayData.length) continue;
generate(url + fmtNum(month) + '/' + fmtNum(day) + '/', new Query(dayData), {
year: year,
month: month,
day: day
});
}
}
}
return result;
};
hexo执行调用Hexo-generator-photo插件:
网站根目录的package.json文件中添加如下一行:
"hexo-server": "^0.2.0", //下面添加,不要遗漏","
"hexo-generator-photo":"^0.0.1"
相册样式调整
新增相册的swig文件(themes\next\layout\photo.swig):
{% extends '_layout.swig' %}
{% import '_macro/post-collapse-photo.swig' as post_template %}
{% import '_macro/sidebar.swig' as sidebar_template %}
{% block title %}{{ __('title.photo') }} | {{ config.title }}{% endblock %}
{% block page_class %} page-archive {% endblock %}
{% block content %}
<section id="posts" class="posts-collapse">
{% for post in page.posts %}
{# Show year #}
{% set year %}
{% set post.year = date(post.date, 'YYYY') %}
{% if post.year !== year %}
{% set year = post.year %}
<div class="collection-title">
<h2 class="archive-year motion-element" id="archive-year-{{ year }}">{{ year }}</h2>
</div>
{% endif %}
{# endshow #}
{{ post_template.render(post) }}
{% endfor %}
</section>
{% include '_partials/pagination.swig' %}
{% endblock %}
{% block sidebar %}
{{ sidebar_template.render(false) }}
{% endblock %}
{% block script_extra %}
{% if theme.use_motion %}
<script type="text/javascript" id="motion.page.archive">
$('.archive-year').velocity('transition.slideLeftIn');
</script>
{% endif %}
{% endblock %}
添加相册子标题模板(themes\next\layout\_macro\post-collapse-photo.swig):
{% macro render(post) %}
<article class="post post-type-{{ post.type | default('normal') }}" itemscope itemtype="http://schema.org/Article">
<header class="post-header2">
<{% if theme.seo %}h3{% else %}h2{% endif %} class="post-title">
{% if post.link %}{# Link posts #}
<a class="post-title-link post-title-link-external" target="_blank" href="{{ url_for(post.link) }}" itemprop="url">
{{ post.title or post.link }}
<i class="fa fa-external-link"></i>
</a>
{% else %}
<a class="post-title-link" href="{{ url_for(post.path) }}" itemprop="url">
{% if post.type === 'picture' %}
{{ post.content }}
{% else %}
<span itemprop="name">{{ post.title | default(__('post.untitled')) }}</span>
{% endif %}
</a>
{% endif %}
</{% if theme.seo %}h3{% else %}h2{% endif %}>
<div>
<ul class="box">
{% for photo in post.photos %}
<figure class="thumb"><img src="{{photo}}" alt=""></figure>
{% endfor %}
</ul>
</div>
<div class="post-meta">
<time class="post-time" itemprop="dateCreated"
datetime="{{ moment(post.date).format() }}"
content="{{ date(post.date, config.date_format) }}" >
{{ date(post.date, 'MM-DD') }}
</time>
</div>
</header>
</article>
{% endmacro %}
新增样式(themes\next\source\css\_custom\custom.styl):
box{ width:100%;}
.box li{ float:left; width:100px; height:80px; margin-right:10px; padding:0; margin:5px; overflow:hidden;list-style:none;}
.posts-collapse .post-header2 {
position: relative;
transition-duration: 0.2s;
transition-timing-function: ease-in-out;
transition-delay: 0s;
transition-property: border;
}
.thumb{
width: 25%;
height: 0;
padding-bottom: 25%;
position: relative;
display: inline-block;
text-align: center;
margin:0px;
}
.thumb img{
display: inline;
margin: auto;
max-width: 100%;
height: auto;
}
相册配置
站点文件配置(_config.yml)新增如下配置:
# Directory节点添加如下配置
photo_dir: photos //添加Photo生成目录
//Photo生成配置
photo_generator:
per_page: 3 //默认展示的条数
yearly: true
monthly: true
主题文件配置(_config.yml)新增如下配置
menu: //menu节点添加如下一行
photos: /photos/
menu_icons: //menu节点下添加如下一行
photos: book
中文显示(themes\next\languages\zh-Hans.yml):
title: //节点下添加如下一行
photo: 相册
menu: //节点下添加如下一行
photos: 相册
测试
source\_posts目录下添加相册的MD文件,内容如下:
---
title: 王二狗是个大帅哥
date: 2017-06-17 10:26:32
comments: false
photos: ["http://img5.duitang.com/uploads/item/201508/10/20150810153526_2ifjW.jpeg","http://img5.duitang.com/uploads/item/201508/10/20150810153526_2ifjW.jpeg","http://img5.duitang.com/uploads/item/201508/10/20150810153526_2ifjW.jpeg","http://img5.duitang.com/uploads/item/201508/10/20150810153526_2ifjW.jpeg","http://img5.duitang.com/uploads/item/201508/10/20150810153526_2ifjW.jpeg","http://img5.duitang.com/uploads/item/201508/10/20150810153526_2ifjW.jpeg","http://img5.duitang.com/uploads/item/201508/10/20150810153526_2ifjW.jpeg","http://img5.duitang.com/uploads/item/201508/10/20150810153526_2ifjW.jpeg"]
isPhoto: true
---


通过`Hexo server`启动服务,访问`http://localhost:4000/photos/`即可看到生成的相册界面。

心得 总结
安装Hexo之后,插件默认存放在blog\node_modules目录下。
插件开发的核心文件:index.js,package.json,generator.js
关于插件开发的Demo:Plugin Demo
Hexo 相册实践的更多相关文章
- Hexo构建Blog系列
Hexo是一个开源构建blog框架,基于nodejs研发.可以自由切换主题,插件等功能,实现自已酷炫博客需求. 下面是基于hexo实践所产出的一些心得,供大家参考. 基础 Hexo 搭建 Hexo 与 ...
- hexo博客进阶-相册和独立域名
之前我已经写了一篇文章详细的讲述了如何使用hexo搭建github博客.如果还没有看的可以去看看,hexo搭建博客 其实,根据这篇文章的过程我们就能够搭建一个专属于自己,并且非常美观的博客了.但是如果 ...
- QQ 相册后台存储架构重构与跨 IDC 容灾实践
欢迎大家前往云加社区,获取更多腾讯海量技术实践干货哦~ 作者简介:xianmau,2015 年加入腾讯 TEG 架构平台部,一直负责 QQ 相册平台的维护和建设,主导相册上传架构重构和容灾优化等工作. ...
- hexo主题中添加相册功能
博客已迁移至http://lwzhang.github.io. 基本上所有的hexo主题默认都没有实现相册功能,一方面相册功能的需求较少,毕竟hexo主要是写博客用的:另一方面实现相册功能比较麻烦,比 ...
- 如何在Hexo中实现自适应响应式相册功能
用最清晰简洁的方法整合一个响应式相册 效果 技术选型 由于我选用的主题使用了fancyBox作为图片弹出展示的框架,查看后表示很不错,能满足需要 http://fancyapps.com/fancyb ...
- 应用集成-在Hexo、Hugo博客框架中使用Gitalk基于Github上仓库项目的issue无后端服务评论系统实践
关注「WeiyiGeek」公众号 设为「特别关注」每天带你玩转网络安全运维.应用开发.物联网IOT学习! 希望各位看友[关注.点赞.评论.收藏.投币],助力每一个梦想. 本章目录 目录 0x00 Gi ...
- hexo静态博客的安装及应用实践记录
1. 必须要安装 nodejs,git 2. 安装hexo node install -g hexo 3. npm源的问题使在安装时有卡住的问题而导致无法安装,则需要更改npm的源 npm confi ...
- 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践
提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...
- 快速web开发中的前后端框架选型最佳实践
这个最佳实践是我目前人在做的一个站点,主要功能: oauth登录 发布文章(我称为"片段"),片段可以自定义一些和内容有关的指标,如“文中人物:12”.支持自定义排版.插图.建立相 ...
随机推荐
- ubuntu下不用拔盘就可以重新识别usb设备
#!/bin/sh # Usage: ./resetusb ARGUMENT(The keyword for your usb device) var1=$ keyword=${var1:=Stora ...
- Implement Stack using Queues 用队列实现栈
Implement the following operations of a stack using queues. push(x) -- Push element x onto stack. po ...
- IOS开发的哪些异常之异常断点
从Android开发的异常报错到IOS的异常闪退,经历了不一样的处理过程.对于IOS的异常报错刚開始总是非常茫然,永远仅仅告诉你有异常.然后就跳到main.m文件,却不曾我告诉她在那出现.真是吊人胃口 ...
- POJ 3074 Sudoku DLX精确覆盖
DLX精确覆盖.....模版题 Sudoku Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 8336 Accepted: ...
- UNIX环境高级编程之第4章:文件和文件夹-习题
4.1 stat函数是尾随符号链接的,所以用stat替换lstat不会显示符号链接的信息 4.2 在一个目录下先再shell中输入umask shell进程再进行创建文件的操作.其权限抖都会被屏蔽 4 ...
- 设计url 通过分发的方式 Xadmin_demo
如 urlpatterns = [ url(r'^Xadmin/',([ url(r'^add/$', views.add) url(r'^delete/$', views.delete) ], No ...
- Python TurtleWorld configuration and simple test
TurtleWorld provides a set of functions for drawing lines by steering turtles around the screen. You ...
- sicily 1000. LinkedList
Description template <typename E> class LinkedList { private: // inner class: linked-list ...
- 基于python3-sklearn,Flask 的回归预测系统
看到一副图片挺有意思,放在片头 序 "傍晚小街路面上沁出微雨后的湿润,和煦的西风吹来,抬头看看天边的晚霞,嗯明天又是一个好天气.走到水果摊旁,挑了个根蒂蜷缩.敲起来声音浊响的青绿西瓜,一边满 ...
- P1452 Beauty Contes
题目背景 此处省略1W字^ ^ 题目描述 贝茜在牛的选美比赛中赢得了冠军”牛世界小姐”.因此,贝西会参观N(2 < = N < = 50000)个农场来传播善意.世界将被表示成一个二维平面 ...