zoukankan      html  css  js  c++  java
  • 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-archivehexo-generator-index中去除相册的展示。 
      修改插件的libgenerator.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插件的libgenerator.js文件添加如下注释的代码:

         function generate(path, posts, options) {
    options = options || {};
    options.archive = true;
    options.postLength = allPosts.length; //新增的

      修改归档的展示页面代码(themes extlayoutarchive.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 extlayoutphoto.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 extlayout\_macropost-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 extsourcecss\_customcustom.styl):

        box{ 100%;}
    .box li{ float:left; 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{
    25%;
    height: 0;
    padding-bottom: 25%;
    position: relative;
    display: inline-block;
    text-align: center;
    margin:0px;
    }

    .thumb img{
    display: inline;
    margin: auto;
    max- 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 extlanguageszh-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
    ---


    ![test](http://tupian.enterdesk.com/2014/mxy/06/09/4/4.jpg)
    ![test](http://img5.duitang.com/uploads/item/201508/10/20150810153526_2ifjW.jpeg)
    通过`Hexo server`启动服务,访问`http://localhost:4000/photos/`即可看到生成的相册界面。

      

    心得 总结

         
      安装Hexo之后,插件默认存放在blog ode_modules目录下。 
      插件开发的核心文件:index.js,package.json,generator.js 
      关于插件开发的Demo:Plugin Demo

     

     
  • 相关阅读:
    Mysql之数据库设计
    jQuery取得select选中的值
    抛java.lang.NoClassDefFoundError: org.joda.time.ReadablePeriod错误
    JS限制并且显示textarea字数
    myBaits association的使用
    IOS-Plist文件存储(1)
    Golang基于学习总结
    freemarker定义自己的标签错误(八)
    教你使用vim表白
    Cocos2d-x 3.2 大富翁游戏项目开发-第八部分 角色的散步路径
  • 原文地址:https://www.cnblogs.com/LuisYang/p/9356488.html
Copyright © 2011-2022 走看看