前言

本文用于 butterfly 魔改,博主没有测试是否适配于其他主题,以及自定义样式 CSS 可能需要一定的前端知识进行优化。 _config.butterfly.yml 配置文件可修改显示 文字描述(文章 description 属性)还是 文章内容(默认截取 500 字),以及推荐文章数量。

1
2
3
4
5
# Related Articles
related_post:
enable: true
limit: 6 # Number of posts displayed
date_type: created # or created or updated 文章日期顯示創建日或者更新日

1
2
3
4
5
6
7
8
# Display the article introduction on homepage
# 1: description
# 2: both (if the description exists, it will show description, or show the auto_excerpt)
# 3: auto_excerpt (default)
# false: do not show the article introduction
index_post_content:
method: 2
length: 500 # if you set method to 2 or 3, the length need to config

效果预览

推荐文章增加描文章描述

推荐文章增加描文章描述

[Blogroot]\themes\butterfly\scripts\helpers\related_post.js 增加以下内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
* Butterfly
* Related Posts
* According the tag
*/

'use strict'

hexo.extend.helper.register('related_posts', function (currentPost, allPosts) {
let relatedPosts = []
currentPost.tags.forEach(function (tag) {
allPosts.forEach(function (post) {
if (isTagRelated(tag.name, post.tags)) {
const relatedPost = {
title: post.title,
path: post.path,
cover: post.cover,
randomcover: post.randomcover,
weight: 1,
+ description: post.description,
+ content: post.content,
updated: post.updated,
created: post.date
}
const 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 ''
}
let result = ''
const hexoConfig = hexo.config
const config = hexo.theme.config

const limitNum = config.related_post.limit || 6
const dateType = config.related_post.date_type || 'created'
const headlineLang = this._p('post.recommend')

relatedPosts = relatedPosts.sort(compare('weight'))

if (relatedPosts.length > 0) {
result += '<div class="relatedPosts">'
result += `<div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>${headlineLang}</span></div>`
result += '<div class="relatedPosts-list">'

for (let i = 0; i < Math.min(relatedPosts.length, limitNum); i++) {
const cover =
relatedPosts[i].cover === false
? relatedPosts[i].randomcover
: relatedPosts[i].cover
const title = this.escape_html(relatedPosts[i].title)
+ const description = this.strip_html(relatedPosts[i].description)
+ const content = this.strip_html(relatedPosts[i].content)
result += `<div><a href="${this.url_for(relatedPosts[i].path)}" title="${title}">`
result += `<img class="cover" src="${this.url_for(cover)}" alt="cover">`
if (dateType === 'created') {
result += `<div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> ${this.date(relatedPosts[i].created, hexoConfig.date_format)}</div>`
} else {
result += `<div class="content is-center"><div class="date"><i class="fas fa-history fa-fw"></i> ${this.date(relatedPosts[i].updated, hexoConfig.date_format)}</div>`
}
result += `<div class="title">${title}</div>`
+ switch (config.index_post_content.method) {
+ case false:
+ break
+ case 1:
+ result += `<div class="info">${description}</div>`
+ break
+ case 2:
+ if (description) {
+ result += `<div class="info">${description}</div>`
+ }
+ else {
+ let expert = content.substring(0, config.index_post_content.length)
+ content.length > config.index_post_content.length ? expert += ' ...' : ''
+ result += `<div class="info">${expert}</div>`
+ }
+ break
+ default:
+ let expert = content.substring(0, config.index_post_content.length)
+ content.length > config.index_post_content.length ? expert += ' ...' : ''
+ result += `<div class="info">${expert}</div>`
+ break
+ }
result += '</div></a></div>'
}

result += '</div></div>'
return result
}
})

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

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

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

上下一篇文章增加文章描述

[Blogroot]\themes\butterfly\layout\includes\pagination.pug 增加以下内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
-
var options = {
prev_text: '<i class="fas fa-chevron-left fa-fw"></i>',
next_text: '<i class="fas fa-chevron-right fa-fw"></i>',
mid_size: 1,
escape: false
}

if is_post()
- let prev = theme.post_pagination === 1 ? page.prev : page.next
- let next = theme.post_pagination === 1 ? page.next : page.prev
nav#pagination.pagination-post
if(prev)
- var hasPageNext = next ? 'pull-left' : 'pull-full'
.prev-post(class=hasPageNext)
- var pagination_cover = prev.cover === false ? prev.randomcover : prev.cover
a(href=url_for(prev.path))
img.prev-cover(src=url_for(pagination_cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of previous post')
.pagination-info
.label=_p('pagination.prev')
.prev_info=prev.title
+ case theme.index_post_content.method
+ when false
+ - break
+ when 1
+ .content!= prev.description
+ when 2
+ if prev.description
+ .content!= prev.description
+ else
+ - const content = strip_html(prev.content)
+ - let expert = content.substring(0, theme.index_post_content.length)
+ - content.length > theme.index_post_content.length ? expert += ' ...' : ''
+ .content!= expert
+ default
+ - const content = strip_html(prev.content)
+ - let expert = content.substring(0, theme.index_post_content.length)
+ - content.length > theme.index_post_content.length ? expert += ' ...' : ''
+ .content!= expert

if(next)
- var hasPagePrev = prev ? 'pull-right' : 'pull-full'
- var pagination_cover = next.cover == false ? next.randomcover : next.cover
.next-post(class=hasPagePrev)
a(href=url_for(next.path))
img.next-cover(src=url_for(pagination_cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of next post')
.pagination-info
.label=_p('pagination.next')
.next_info=next.title
+ case theme.index_post_content.method
+ when false
+ - break
+ when 1
+ .content!= next.description
+ when 2
+ if next.description
+ .content!= next.description
+ else
+ - const content = strip_html(next.content)
+ - let expert = content.substring(0, theme.index_post_content.length)
+ - content.length > theme.index_post_content.length ? expert += ' ...' : ''
+ .content!= expert
+ default
+ - const content = strip_html(next.content)
+ - let expert = content.substring(0, theme.index_post_content.length)
+ - content.length > theme.index_post_content.length ? expert += ' ...' : ''
+ .content!= expert
else
nav#pagination
.pagination
if is_home()
- options.format = 'page/%d/#content-inner'
!=paginator(options)

增加自定义样式

增加自定义样式,其中部分是博主魔改后的样式,仅供参考。

--main: #1677B3--second: #fff--card-border: 1px solid rgba(150,150,150,0.2);--border-radius: .5rem--main-shadow: 0 2px 3px 1px rgba(22, 119, 179, .2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* 推荐文章 */
.relatedPosts>.relatedPosts-list .content {
position: relative;
}

.relatedPosts>.relatedPosts-list>div {
border-radius: var(--border-radius);
}

.relatedPosts>.relatedPosts-list .content .date {
font-size: 1rem;
-webkit-transition: all .6s ease-in-out;
-moz-transition: all .6s ease-in-out;
-o-transition: all .6s ease-in-out;
-ms-transition: all .6s ease-in-out;
transition: all .6s ease-in-out;
}

.relatedPosts>.relatedPosts-list .content .title {
font-size: 1.1rem;
-webkit-transition: all .6s ease-in-out;
-moz-transition: all .6s ease-in-out;
-o-transition: all .6s ease-in-out;
-ms-transition: all .6s ease-in-out;
transition: all .6s ease-in-out;
}

.relatedPosts>.relatedPosts-list>div:hover .cover {
opacity: .1;
}

.relatedPosts>.relatedPosts-list>div:hover {
background: var(--main);
color: var(--second);
box-shadow: var(--main-shadow);
}

.relatedPosts>.relatedPosts-list>div:hover .content .date,
.relatedPosts>.relatedPosts-list>div:hover .content .title {
opacity: 0;
}

.relatedPosts>.relatedPosts-list .content .info {
opacity: 0;
position: absolute;
top: 50%;
left: 0;
right: 0;
padding: 0 1rem;
color: var(--second);
text-align: justify;
word-break: break-all;
-webkit-line-clamp: 3;
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-transition: all .6s ease-in-out;
-moz-transition: all .6s ease-in-out;
-o-transition: all .6s ease-in-out;
-ms-transition: all .6s ease-in-out;
transition: all .6s ease-in-out;
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-o-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}

.relatedPosts>.relatedPosts-list>div:hover .content .info {
opacity: 1;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/* 上下一篇文章 */
#pagination.pagination-post {
border-radius: var(--border-radius);
}

#pagination .prev-post .label,
#pagination .next-post .label {
font-size: 1rem;
-webkit-transition: all .6s ease-in-out;
-moz-transition: all .6s ease-in-out;
-o-transition: all .6s ease-in-out;
-ms-transition: all .6s ease-in-out;
transition: all .6s ease-in-out;
}

#pagination .prev-post .prev_info,
#pagination .next-post .next_info {
font-size: 1.1rem;
-webkit-transition: all .6s ease-in-out;
-moz-transition: all .6s ease-in-out;
-o-transition: all .6s ease-in-out;
-ms-transition: all .6s ease-in-out;
transition: all .6s ease-in-out;
}

#pagination .prev-post,
#pagination .next-post {
border: var(--card-border);
}

#pagination .prev-post:hover img,
#pagination .next-post:hover img {
opacity: .1;
}

#pagination .prev-post:hover a,
#pagination .next-post:hover a {
background: var(--main);
color: var(--second);
box-shadow: var(--main-shadow);
}

#pagination .prev-post:hover .label,
#pagination .next-post:hover .label,
#pagination .prev-post:hover .prev_info,
#pagination .next-post:hover .next_info {
opacity: 0;
}

#pagination .content {
opacity: 0;
position: absolute;
top: 50%;
left: 0;
right: 0;
padding: 0 1rem;
color: var(--second);
text-align: justify;
word-break: break-all;
-webkit-line-clamp: 3;
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-transition: all .6s ease-in-out;
-moz-transition: all .6s ease-in-out;
-o-transition: all .6s ease-in-out;
-ms-transition: all .6s ease-in-out;
transition: all .6s ease-in-out;
-webkit-transform: translateY(-50%);
-moz-transform: translateY(-50%);
-o-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}

#pagination .prev-post:hover .content,
#pagination .next-post:hover .content {
opacity: 1;
}

Hexo 三连

执行 Hexo 三连

1
hexo clean && hexo g && hexo s