Ethan's Blog

记录和思考

Hexo 相关文章的代码实现

以前使用 WordPress 的时候,每次自己写主题总要加上一个功能:相关文章。总感觉用户看完文章后可能会想看看还有什么相关的文章,以便更加全面的了解这个问题。转到 Hexo 后,对 Hexo 的代码进行了一点研究,也摸索着写了一个主题,今天花了一个下午的时间,为自己 Hexo 博客加上了相关文章功能。

相关文章的实现方式大概可以分为两个大类:一是使用第三方服务,例如无觅、友荐、bShare、阿里云的云推荐以及百度推荐等。这种方式的优点是对相关文章的分析可能更强大,在如何定义文章是否相关上可能更加全面,缺点是需要引入较多的外站 js 文件等。第二类是自己写代码实现。现在网上对 Hexo 的相关文章实现第一类的文章非常多,而我更倾向于使用第二种方法,于是下午自己代码实现了 Hexo 的相关文章功能。

首先说一下 Hexo 实现相关文章的原理。我实现的是基于 tag 相关的相关文章,也就是说两篇文章重合的 tag 数量越多则认为这两篇文章越相关。这个原理虽然比较简单,但我觉得对于个人博客来说,只要 tag 管理设置得当,也够用了。

实现代码如下:

hexo.extend.helper.register('related_posts', function(currentPost, allPosts){
    var relatedPosts = [];
    currentPost.tags.forEach(function (tag) {
        allPosts.forEach(function (post) {
            if (isTagRelated(tag.name, post.tags)) {
                var relatedPost = {
                    title: post.title,
                    path: post.path,
                    weight: 1
                };

                var index = findItem(relatedPosts, 'path', post.path);

                if (index != -1) {
                    relatedPosts[index].weight += 1;
                } else{
                    if (currentPost.path != post.path) {
                        relatedPosts.push(relatedPost);
                    };
                };
            };
        });
    });

    if (relatedPosts.length == 0) {return ''};

    var result = '<h3>相关文章:</h3><ul class="related-posts">';
    relatedPosts = relatedPosts.sort(compare('weight'));
    for (var i = 0; i < Math.min(relatedPosts.length, 10); i++) {
        result += '<li><a href="/' + relatedPosts[i].path + '">' + relatedPosts[i].title + '</a></li>';
    };
    result += '</ul>';

    // console.log(relatedPosts);
    return result;
});

function isTagRelated (tagName, TBDtags) {
    var result = false;
    TBDtags.forEach(function (tag) {
        if (tagName == tag.name) {
            result = true;
        };
    })

    return result;
}

function findItem (arrayToSearch, attr, val) {
    for (var i = 0; i < arrayToSearch.length; i++) {
        if (arrayToSearch[i][attr] == val) {
            return i
        };
    };

    return -1;
}

function compare (attr) {
    return function (a, b) {
        var val1 = a[attr];
        var val2 = b[attr];
        return val2 - val1;
    }
}

使用方法很简单,在自己主题文件夹下的 script 文件夹中建立一个 related_post.js 的文件,然后将上面代码拷入,再到需要调用相关文章的页面模板中添加 <%- related_posts(post, site.posts) %> 即可。注意传入的两个参数分别为当前文章和网站的所有文章。最后,再稍微调整下样式即可。

一般来说,添加的位置为主题模板 post 中,以 ejs 模板为例,则为主题目录下的 layout/post.ejs 文件,在最后添加以下代码即可:

<%- related_posts(post, site.posts) %>

写代码和写文章都不容易,我最近搜了一下自己以前写的文章,发现很多被转载也不留原文作者和链接,总之,愿意转载的朋友希望你能以链接形式注明本文地址。

相关文章: