加载中...

Hexo(Matery)自定义(二):增加文章统计


Hexo(Matery)自定义(二):增加文章统计

注意事项

  • 页面预览:点我

  • 想法:偶然看到,甚是喜欢,但奈何原博主没有分享资源

新建统计页面

hexo new page stat

然后在文件内容的双线内添加:

type: stat
layout: stat

新建统计页面模板文件

在主题目录的layout/文件夹下新建stat.ejs模板文件,然后用vim也好,用其他工具也好,写入以下内容:

<style type="text/css">
    /* don't remove. */
    .about-cover {
        height: 75vh;
    }
</style>

<%- partial('_partial/bg-cover') %>

<main class="content">
    <div class="container chip-container">
        <div class="card">
            <div class="card-content">
                <div class="tag-title center-align">
                    <i class="<%= theme.stat.icon %>"></i>&nbsp;&nbsp;<%= theme.stat.title %>
                </div>
            </div>
        </div>

        <div class="card">
            <div class="card-content">
                <% if (theme.stat.text) { %>
                <style>
                    #stat-text {
                        -webkit-text-size-adjust: 100%;
                        line-height: 1.5;
                        font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
                        font-weight: normal;
                        --fa-font-brands: normal 400 1em/1 "Font Awesome 6 Brands";
                        --fa-font-regular: normal 400 1em/1 "Font Awesome 6 Free";
                        --fa-font-solid: normal 900 1em/1 "Font Awesome 6 Free";
                        color: #34495e;
                        text-align: center;
                        float: left;
                        box-sizing: border-box;
                        padding: 0 .75rem;
                        min-height: 1px;
                        opacity: .6;
                        font-size: 1.1rem;
                        width: 83.3333333333%;
                        left: auto;
                        right: auto;
                        margin-left: 8.3333333333%;
                    }
                </style>
                <div id="stat-text">
                    <div class="row">
                        <div class="col l8 offset-l2 m10 offset-m1 s10 offset-s1 center-align text">
                            <%= theme.stat.text %>
                        </div>
                    </div>
                </div>
                <br>
                <hr>
                <% } %>

                <%- page.content %>

                <% if (theme.stat.show_post) { %>
                <h1 id="<%= theme.stat.title %>"><a href="#<%= theme.stat.title %>" class="headerlink" title="<%= theme.stat.title %>"></a><%= theme.stat.title %></h1>
                <%
                    var article_posts = [];
                    site.posts.forEach(post => {
                        article_posts.push(post);
                    });
                    
                    for (var i = 0; i < article_posts.length - 1; i++) {
                        for (var j = 1; j < article_posts.length - i; j++) {
                            if (article_posts[j].date > article_posts[j-1].date) {
                                var tmp = article_posts[j];
                                article_posts[j] = article_posts[j-1];
                                article_posts[j-1] = tmp;
                            }
                        }
                    }
                    
                    var post_date_index = null;
                    article_posts.forEach(post => {
                        pwd = post.password;
                        if ((!(pwd && pwd.length > 0))&&(post.hide != true)) {
                            if (date(post.date, 'YYYY-MM') != post_date_index) {
                                post_date_index = date(post.date, 'YYYY-MM');
                %>

                <h2 id="<%= post_date_index %>"><a href="#<%= post_date_index %>" class="headerlink" title="<%= post_date_index %>"></a><%= post_date_index %></h2>
                            <% } %>
                <p>
                    <code><%= date(post.date, 'YYYY-MM-DD') %></code>&ensp;-
                    <a href="<%- url_for(post.path) %>"><%= post.title %></a>
                </p>
                        <% } %>
                    <% }); %>
                <% } %>

            </div>
        </div>

        <style type="text/css">
            #posts-chart,
            #categories-chart,
            #tags-chart {
                width: 100%;
                height: 300px;
                margin: 0.5rem auto;
                padding: 0.5rem;
            }
        </style>
        <div class="card">
            <div class="card-content">
                <div class="chart col s12 m6 l4" data-aos="zoom-in-up">
                    <div id="posts-chart"></div>
                </div>
            </div>
        </div>
        <div class="card">
            <div class="card-content">
                <div class="chart col s12 m6 l4" data-aos="zoom-in-up">
                    <div id="tags-chart"></div>
                </div>
            </div>
        </div>
        <div class="card">
            <div class="card-content">
                <div class="chart col s12 m6 l4" data-aos="zoom-in-up">
                    <div id="categories-chart"></div>
                </div>
            </div>
        </div>
        <!-- <div class="card">
            <div class="card-content">
                
            </div>
        </div> -->
    </div>

    <% if (site.categories && site.categories.length > 0) { %>
    <%- partial('_widget/category-radar') %>
    <% } %>

            
    <script type="text/javascript" src="<%- theme.jsDelivr.url %><%- url_for(theme.libs.js.echarts) %>"></script>
    <script>
        let postsChart = echarts.init(document.getElementById('posts-chart'));
        let categoriesChart = echarts.init(document.getElementById('categories-chart'));
        let tagsChart = echarts.init(document.getElementById('tags-chart'));
    
        <%
        /* calculate postsOption data. */
        var startDate = moment().subtract(1, 'years').startOf('month');
        var endDate = moment().endOf('month');
    
        var monthMap = new Map();
        var dayTime = 3600 * 24 * 1000;
        for (var time = startDate; time <= endDate; time += dayTime) {
            var month = moment(time).format('YYYY-MM');
            if (!monthMap.has(month)) {
                monthMap.set(month, 0);
            }
        }
    
        // post and count map.
        site.posts.forEach(function (post) {
            var month = post.date.format('YYYY-MM');
            if (monthMap.has(month)) {
                monthMap.set(month, monthMap.get(month) + 1);
            }
        });
    
        // xAxis data and yAxis data.
        var monthArr = JSON.stringify([...monthMap.keys()]);
        var monthValueArr = JSON.stringify([...monthMap.values()]);
        %>
    
        let postsOption = {
            title: {
                text: '<%- __("postPublishChart")  %>',
                top: -5,
                x: 'center'
            },
            tooltip: {
                trigger: 'axis'
            },
            xAxis: {
                type: 'category',
                data: <%- monthArr %>
            },
            yAxis: {
                type: 'value',
            },
            series: [
                {
                    name: '<%- __("postsNumberName")  %>',
                    type: 'line',
                    color: ['#6772e5'],
                    data: <%- monthValueArr %>,
                    markPoint: {
                        symbolSize: 45,
                        color: ['#fa755a','#3ecf8e','#82d3f4'],
                        data: [{
                            type: 'max',
                            itemStyle: {color: ['#3ecf8e']},
                            name: '<%- __("maximum")  %>'
                        }, {
                            type: 'min',
                            itemStyle: {color: ['#fa755a']},
                            name: '<%- __("minimum")  %>'
                        }]
                    },
                    markLine: {
                        itemStyle: {color: ['#ab47bc']},
                        data: [
                            {type: 'average', name: '<%- __("average")  %>'}
                        ]
                    }
                }
            ]
        };
    
        <%
        /* calculate categoriesOption data. */
        var categoryArr = [];
        site.categories.map(function(category) {
            categoryArr.push({'name': category.name, 'value': category.length})
        });
    
        var categoryArrJson = JSON.stringify(categoryArr);
        %>
    
        let categoriesOption = {
            title: {
                text: '<%- __("categoriesChart")  %>',
                top: -4,
                x: 'center'
            },
            tooltip: {
                trigger: 'item',
                formatter: "{a} <br/>{b} : {c} ({d}%)"
            },
            series: [
                {
                    name: '<%- __("categories")  %>',
                    type: 'pie',
                    radius: '50%',
                    color: ['#6772e5', '#ff9e0f', '#fa755a', '#3ecf8e', '#82d3f4', '#ab47bc', '#525f7f', '#f51c47', '#26A69A'],
                    data: <%- categoryArrJson %>,
                    itemStyle: {
                        emphasis: {
                            shadowBlur: 10,
                            shadowOffsetX: 0,
                            shadowColor: 'rgba(0, 0, 0, 0.5)'
                        }
                    }
                }
            ]
        };
    
        <%
        /* calculate tagsOption data. */
        // get all tags name and count,then order by length desc.
        var tagArr = [];
        site.tags.map(function(tag) {
            tagArr.push({'name': tag.name, 'value': tag.length});
        });
        tagArr.sort((a, b) => {return b.value - a.value});
    
        // get Top 10 tags name and count.
        var tagNameArr = [];
        var tagCountArr = [];
        for (var i = 0, len = Math.min(tagArr.length, 10); i < len; i++) {
            tagNameArr.push(tagArr[i].name);
            tagCountArr.push(tagArr[i].value);
        }
    
        var tagNameArrJson = JSON.stringify(tagNameArr);
        var tagCountArrJson = JSON.stringify(tagCountArr);
        %>
    
        let tagsOption = {
            title: {
                text: '<%- __("top10TagsChart")  %>',
                top: -5,
                x: 'center'
            },
            tooltip: {},
            xAxis: [
                {
                    type: 'category',
                    data: <%- tagNameArrJson %>
                }
            ],
            yAxis: [
                {
                    type: 'value'
                }
            ],
            series: [
                {
                    type: 'bar',
                    color: ['#82d3f4'],
                    barWidth : 18,
                    data: <%- tagCountArrJson %>,
                    markPoint: {
                        symbolSize: 45,
                        data: [{
                            type: 'max',
                            itemStyle: {color: ['#3ecf8e']},
                            name: '<%- __("maximum")  %>'
                        }, {
                            type: 'min',
                            itemStyle: {color: ['#fa755a']},
                            name: '<%- __("minimum")  %>'
                        }],
                    },
                    markLine: {
                        itemStyle: {color: ['#ab47bc']},
                        data: [
                            {type: 'average', name: '<%- __("average")  %>'}
                        ]
                    }
                }
            ]
        };
    
        // render the charts
        postsChart.setOption(postsOption);
        categoriesChart.setOption(categoriesOption);
        tagsChart.setOption(tagsOption);
    </script>
            
</main>

配置

在主题配置文件中添加:

# 统计
stat:
  title: 文章统计  # 标题
  text: 身处不幸的时候,更应该竭尽全力。  # 一言
  icon: far fa-bar-chart  # 图标
  show_post: true  # 是否显示文章统计

添加菜单导航,生成静态文件即可

解释

  • 获取所有文章信息
var article_posts = [];
site.posts.forEach(post => {
    article_posts.push(post);
});
  • 按发布时间前后排序

我写的比较草率,你有更好的排序算法直接更改即可,应该可以提高生成效率

for (var i = 0; i < article_posts.length - 1; i++) {
    for (var j = 1; j < article_posts.length - i; j++) {
        if (article_posts[j].date > article_posts[j-1].date) {
            var tmp = article_posts[j];
            article_posts[j] = article_posts[j-1];
            article_posts[j-1] = tmp;
        }
    }
}
  • 遍历所有文章信息,忽略加密文章和隐藏文章,再根据文章日期分类
var post_date_index = null;
article_posts.forEach(post => {
    pwd = post.password;
    if ((!(pwd && pwd.length > 0))&&(post.hide != true)) {
        if (date(post.date, 'YYYY-MM') != post_date_index) {
            post_date_index = date(post.date, 'YYYY-MM');

Over!


文章作者: 知蝉
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 知蝉 !
评论
  目录