Hexo NexT主题美化2.0

前期,对网站一番魔改,视觉效果全面提升。功能诸如主页轮播图、评论邮件通知、标签页美化、归档页美化、相册、文章推荐等。小改的地方包括页面分享功能、鼠标样式、类知乎卡片页…关于魔改,仁者见仁智者见智,在此记录一下相关功能的具体实现。

PS:本站 已集成以下所有功能,全动态配置,欢迎 star、fork !

主页轮播图

  1. 在 /themes/next/layout/_macro/ 目录下,新建 carousel.swig 文件:

    carousel.swig
  2. 在 /themes/next/layout/index.swig 中,找到

1
{% block content %}

在其下方引入新建的 carousel.swig 文件:

1
2
<!--轮播图-->
{% include '_macro/carousel.swig' %}
  1. 在主题配置文件末尾添加:
1
2
3
4
5
6
7
8
9
10
11
12
13
#Home carousel map, from means link, img means picture
carousel:
enable: true
item: [
{
'link': '文章链接地址',
'img': '图片链接地址'
},
{
'link': '文章链接地址',
'img': '图片链接地址'
}
]

轮播图相应的实现逻辑,可参考 Bootstrap 官方 Carousel 实现:

Bootstrap Carousel

可能遇到的问题

  1. the requested content cannot be loaded. please try again later

如点击轮播图出现

KPg5Ax.jpg

可在 /themes/next/source/js/src/utils.js 的 wrapImageWithFancyBox 方法中增加以下第 8 行代码:

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
 wrapImageWithFancyBox: function () {
$('.content img')
.not('[hidden]')
.not('.group-picture img, .post-gallery img')
.each(function () {
var $image = $(this);
/*解决fancybox和图片链接冲突*/
+ if ($(this).hasClass('nofancybox')) return;

var imageTitle = $image.attr('title');
var $imageWrapLink = $image.parent('a');

if ($imageWrapLink.size() < 1) {
var imageLink = ($image.attr('data-original')) ? this.getAttribute('data-original') : this.getAttribute('src');
$imageWrapLink = $image.wrap('<a href="' + imageLink + '"></a>').parent('a');
}

$imageWrapLink.addClass('fancybox fancybox.image');
$imageWrapLink.attr('rel', 'group');

if (imageTitle) {
$imageWrapLink.append('<p class="image-caption">' + imageTitle + '</p>');

//make sure img title tag will show correctly in fancybox
$imageWrapLink.attr('title', imageTitle);
}
});

$('.fancybox').fancybox({
helpers: {
overlay: {
locked: false
}
}
});
}

然后,在 carousel.swig 中,为 img 标签加上:

1
class="nofancybox"
  1. 轮播图锚点(被困扰 N 久)

nlOMHU.gif

点击轮播图左右导航按钮时,a 标签的 href 会锚点到 myCarousel 处,引起页面滚动。可将 href 属性改成 data-target,如下:

1
<a class="left carousel-control" data-target="#myCarousel" href="javascript:void(0);" role="button" data-slide="prev">

以下是本站 carousel.swig 和图标:

carousel.swig icon-slides

注意:部分图片需自己制作,样式微调

valine-admin

刚建站那会,使用了多款评论插件,从 gitalk 到 livere(来必力)到 valine,一路折腾,最终找到了更喜欢的 valine-admin

Valine Admin 是 Valine 评论系统的扩展和增强,主要实现评论邮件通知、评论管理、垃圾评论过滤等功能。支持完全自定义的邮件通知模板,基于 Akismet API 实现准确的垃圾评论过滤

Hexo NexT主题整合步骤如下:

  1. 下载 Valine.min.js 文件,放到 /themes/next/source/js/src/ 下,也可以上传到自己的服务器或主机上(或者直接使用别人提供的外链)。

  2. 修改 /themes/next/layout/_third-party/comments/valine.swig 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{% if theme.valine.enable and theme.valine.appid and theme.valine.appkey %}
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="/js/src/Valine.min.js"></script>

<!-- https://deserts.io/diy-a-comment-system/ -->
<script type="text/javascript">
new Valine({
lang: 'zh-cn',
admin_email: '793458585@qq.com', //博主邮箱
el: '#comments' ,
appId: '{{ theme.valine.appid }}',
appKey: '{{ theme.valine.appkey }}',
emoticon_url: 'https://cloud.panjunwen.com/alu',
emoticon_list: ["吐.png","喷血.png","狂汗.png","不说话.png","汗.png","坐等.png","献花.png","不高兴.png","中刀.png","害羞.png","皱眉.png","小眼睛.png","中指.png","尴尬.png","瞅你.png","想一想.png","中枪.png","得意.png","肿包.png","扇耳光.png","亲亲.png","惊喜.png","脸红.png","无所谓.png","便便.png","愤怒.png","蜡烛.png","献黄瓜.png","内伤.png","投降.png","观察.png","看不见.png","击掌.png","抠鼻.png","邪恶.png","看热闹.png","口水.png","抽烟.png","锁眉.png","装大款.png","吐舌.png","无奈.png","长草.png","赞一个.png","呲牙.png","无语.png","阴暗.png","不出所料.png","咽气.png","期待.png","高兴.png","吐血倒地.png","哭泣.png","欢呼.png","黑线.png","喜极而泣.png","喷水.png","深思.png","鼓掌.png","暗地观察.png"],
placeholder: '{{ theme.valine.placeholder }}',
});

</script>
{% endif %}

主题配置文件中的 valine 可这样配置:

1
2
3
4
5
6
7
8
9
10
valine:
enable: true
appid: your appid #<app_id>
appkey: your appkey #<app_key>
notify: false # mail notifier # 关闭,使用valine-admin发邮件
verify: false # Verification code
placeholder: '&#x270d;写评论' # comment box placeholder
avatar: mm # gravatar style
guest_info: nick,mail,link # custom comment header
pageSize: 10 # pagination size

这样就完成 valine 替换,不过文章标题下方的评论数会不显示,这功能作者目前没有实现,只能先隐藏,详细教程可参考:

Valine: 评论系统

有关 Valine Admin 邮件通知功能,可参考:

Valine Admin 配置手册

我使用的是国际版 Leancloud,要对应于北京时间,可相应减8小时,例如我是这样配置:

1
2
# 北京时间每天早8点检查过去24小时内漏发的通知邮件并补发
0 0 0 * * ?
1
2
# 每天早0点到晚23点每隔30分钟访问云引擎
0 0/30 0-23 * * ?

可根据后边的『下次执行时间』进行调整。

附上我个人正在使用的邮件模板和邮件主题

MAIL_TEMPLATE_ADMIN

1
<div style="border-radius: 10px 10px 10px 10px;font-size:13px; color: #555555;width: 666px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;border:1px solid #eee;max-width:100%;background: #ffffff repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);"><div style="width:100%;background:#49BDAD;color:#ffffff;border-radius: 10px 10px 0 0;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));background-image: -webkit-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;"><p style="font-size:15px;word-break:break-all;padding: 23px 32px;margin:0;background-color: hsla(0,0%,100%,.4);border-radius: 10px 10px 0 0;">您的<a style="text-decoration:none;color: #ffffff;" href="${SITE_URL}"> 『${SITE_NAME}』 </a>上有了新的评论 </p></div><div style="margin:40px auto;width:90%"><p><strong>"${NICK}"</strong> 发表评论:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${COMMENT}</div><p><a style="text-decoration:none; color:#12addb" href="${POST_URL}" target="_blank">[查看详情]</a></p><style type="text/css">a:link{text-decoration:none}a:visited{text-decoration:none}a:hover{text-decoration:none}a:active{text-decoration:none}</style></div></div>

MAIL_TEMPLATE

1
<div style="border-radius: 10px 10px 10px 10px;font-size:13px;color: #555555;width: 666px;font-family:'Century Gothic','Trebuchet MS','Hiragino Sans GB',微软雅黑,'Microsoft Yahei',Tahoma,Helvetica,Arial,'SimSun',sans-serif;margin:50px auto;border:1px solid #eee;max-width:100%;background: #ffffff repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 1px 5px rgba(0, 0, 0, 0.15);"><div style="width:100%;background:#49BDAD;color:#ffffff;border-radius: 10px 10px 0 0;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));background-image: -webkit-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;"><p style="font-size:15px;word-break:break-all;padding: 23px 32px;margin:0;background-color: hsla(0,0%,100%,.4);border-radius: 10px 10px 0 0;">您在<a style="text-decoration:none;color: #ffffff;" href="${SITE_URL}">『${SITE_NAME}』</a>上的留言有新回复啦!!!</p></div><div style="margin:40px auto;width:90%"><p>"<strong>${PARENT_NICK}</strong>" 同学,您曾发表评论:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${PARENT_COMMENT}</div><p>"<strong>${NICK}</strong>" 给您的回复如下:</p><div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:14px;color:#555555;">${COMMENT}</div><p>您可以点击:<a style="text-decoration:none; color:#12addb" href="${POST_URL}">[回复的完整内容] </a>进行查看。欢迎再次光临<a style="text-decoration:none; color:#12addb" href="${SITE_URL}"> 『${SITE_NAME}』</a>!!!</p><style type="text/css">a:link{text-decoration:none}a:visited{text-decoration:none}a:hover{text-decoration:none}a:active{text-decoration:none}</style></div></div>

MAIL_SUBJECT_ADMIN

1
叮咚!『${SITE_NAME}』上有了新评论!

MAIL_SUBJECT

1
${PARENT_NICK},您在『${SITE_NAME}』上的评论收到了回复

另外:点击邮件中的链接跳转至相应评论,可在 /themes/next/layout/_third-party/comments/valine.swig 中添加如下代码:

1
2
3
4
5
6
7
8
9
10
<script>
if(window.location.hash){
var checkExist = setInterval(function() {
if ($(window.location.hash).length) {
$('html, body').animate({scrollTop: $(window.location.hash).offset().top-90}, 1000);
clearInterval(checkExist);
}
}, 100);
}
</script>

具体效果,可在下方的评论区体验哦~

彩色标签页

在 /themes/next/layout/ 目录下,新增 tag-color.swig 文件,填入如下内容:

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
<script type="text/javascript">
var alltags = document.getElementsByClassName('tag-cloud-tags');
var tags = alltags[0].getElementsByTagName('a');
for (var i = tags.length - 1; i >= 0; i--) {
var r=Math.floor(Math.random()*75+130);
var g=Math.floor(Math.random()*75+100);
var b=Math.floor(Math.random()*75+80);
tags[i].style.background = "rgb("+r+","+g+","+b+")";
}
</script>

<style>
.tag-cloud-tags{
/*font-family: Helvetica, Tahoma, Arial;*/
/*font-weight: 100;*/
text-align: center;
counter-reset: tags;
}
.tag-cloud-tags a{
border-radius: 6px;
padding-right: 5px;
padding-left: 5px;
margin: 8px 5px 0px 0px;
}
.tag-cloud-tags a:before{
content: "🔖";
}

.tag-cloud-tags a:hover{
box-shadow: 0px 5px 15px 0px rgba(0,0,0,.4);
transform: scale(1.1);
/*box-shadow: 10px 10px 15px 2px rgba(0,0,0,.12), 0 0 6px 0 rgba(104, 104, 105, 0.1);*/
transition-duration: 0.15s;
}
</style>

在同级目录的 page.swig 中引入 tag-color.swig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    <div class="tag-cloud">

<!-- 目前共计xxx个标签
<div class="tag-cloud-title">
{{ _p('counter.tag_cloud', site.tags.length) }}
</div>
-->

<div class="tag-cloud-tags">
{{ tagcloud({min_font: 10, max_font: 15, amount: 300, color: true, start_color: '#ccc', end_color: '#111'}) }}
</div>
</div>

+ {% include 'tag-color.swig' %}

{% elif page.type === 'categories' %}
<div class="category-all-page">
<div class="category-all-title">
{{ _p('counter.categories', site.categories.length) }}
</div>
<div class="category-all">
{{ list_categories() }}
</div>
</div>

hexo 三连,打开 我的标签页 看看效果吧

KP2ivQ.jpg

以下是文章底部的标签样式

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
/*文章底部标签样式*/
.posts-expand .post-tags a {
-webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24);
-moz-box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24);
box-shadow: 0 1px 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24);
font-family: 'Comic Sans MS', sans-serif;
transition: .2s ease-out;
padding: 3px 5px;
margin: 5px;
background: #f5f5f5;
border-bottom: none;
border-radius: 15px;

+mobile(){
padding: 1px 3px;
font-size: 8px;
}

&:hover {
background: rgba(100,154,182,0.902);
color: #fff;
-webkit-box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
-moz-box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.19);
}
}

代码拷入 /themes/next/source/css/_custom/custom.styl 即可,效果参考文章末尾处的标签。其它自定义标签样式,可参考:

Hexo NexT主题之自定义标签页

归档页美化

  1. 修改 /themes/next/layout/_macro/post-collapse.swig 后的代码如下:
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
{% macro render(post) %}

<article class="my-post post-type-{{ post.type | default('normal') }}" itemscope itemtype="http://schema.org/Article">
<header class="my-post-header">

<div class="my-post-meta">
<time class="my-post-time" itemprop="dateCreated"
datetime="{{ moment(post.date).format() }}"
content="{{ date(post.date, config.date_format) }}" >
{{ date(post.date, 'MM-DD') }}
</time>
</div>

<{% if theme.seo %}h3{% else %}h2{% endif %} class="my-post-title">
{% if post.link %}{# Link posts #}
<a class="my-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="my-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 %}>

</header>
</article>

{% endmacro %}

主要修改:一是将 post-meta 这个 div 移到前面 header 标签下;二是将所有的 class 属性都加上 my-,例如 my-post-meta,这样改动是为了不影响其它页面引用的样式。

  1. 在 /themes/next/source/css/_custom/custom.styl 新增如下样式:
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
/* 归档页样式 began */
.page-archive .archive-page-counter {
font-size: 18px;
background-color: #49b1f5;
padding-left: 10px;
padding-right: 10px;
border-radius: 8px;
color: #fff;
+mobile() {
font-size: 16px;
}
}
.my-post-time{
font-size: 11px;
position: absolute;
color: #fff;
background-color: #49b1f5;
border-radius: 5px;
padding-left: 5px;
padding-right: 5px;
margin-left: 15px;
}
.mypost{
position: relative;
margin-bottom: 1rem;
-webkit-transition: all .2s ease-in-out;
-moz-transition: all .2s ease-in-out;
-o-transition: all .2s ease-in-out;
-ms-transition: all .2s ease-in-out;
transition: all .2s ease-in-out;
}
a.my-post-title-link:before{
top: 10px;
width: 18px;
height: 18px;
content: "📚";
margin-right: 5px;
font: normal normal normal 14px/1 FontAwesome;
font-size: 15px;
line-height: 18px;
}
.my-post:hover{
transform: scale(1.1);
box-shadow: 10px 10px 15px 2px rgba(0,0,0,.12), 0 0 6px 0 rgba(104, 104, 105, 0.1);
border-radius: 30px;
width: 400px;
padding: 1px 10px;
margin-left: 25px;
font-size: 16px;
transition-duration: 0.15s;
+mobile(){
width: 260px;
margin-left: 18px;
}
//display:flex;
}
a.my-post-title-link{
text-decoration: none;
font-size: 15px;
font-weight: 400;
+mobile() {
font-size: 14px;
}
}
.my-post-title{
display: block;
margin-left: 4.5rem;
color: #4c4948;
text-decoration: none;
font-size: .8rem;
cursor: pointer;
+mobile() {
//margin-left: 4rem;
}
}
.my-post-header{
position: top;
margin-bottom: 1rem;
-webkit-transition: all .2s ease-in-out;
-moz-transition: all .2s ease-in-out;
-o-transition: all .2s ease-in-out;
-ms-transition: all .2s ease-in-out;
transition: all .2s ease-in-out;
}
//.my-post-title-link{
// font-size: 16px;
// font-weight: 500;
//}
.my-post-meta{
position: absolute;
color: #99a9bf;
width: 80px;
color: #114142;
}
div.post-block.tag .collection-title h2 {
border-width: 1px;
border-style: solid;
border-color: #3f3f3f;
border-radius: 20px;
font-size: 22px;
background-color: #b4e8fa;
padding: 2px 15px;
letter-spacing: 1.5px;
box-sizing: border-box;
color: #3f3f3f;
display: inline-block;
margin: 10px 0 10px;
text-align: center;
+mobile(){
font-size: 18px;
}
}
.category-list-link:hover{
transform: scale(1.1);
box-shadow: 10px 10px 15px 2px rgba(0,0,0,.12), 0 0 6px 0 rgba(104, 104, 105, 0.1);
border-radius: 8px;
padding: 1px 1px;
margin-left: 5px;
font-size: 16px;
transition-duration: 0.15s;
//display:flex;
}
/* 归档页样式 end */

根据需要调整对应的样式,效果可查看:

归档页样式效果

相册

相册功能可参考兰州小红鸡,使用的是腾讯云 cos 作为相册存储桶。实名认证后,赠送 50GB 标准存储容量,有效期 6 个月,但是访问或下载对象产生的外网下行流量是单独计费的,可以购买 COS 下行流量包,具体可参考官网。

相册调试开始的这两天,我每天刷掉了 5G 左右的流量,费用大概 5 块钱吧,欠费第二天就被禁用了,需要充值缴费,要么删数据。腾讯嘛,你懂的。虽然流量也不是很贵,但对我这种负债的人来说,还是想想其他办法吧,主要是免费的用惯了,哈哈~

期间也考虑使用七牛云图床,对象存储的官方 SDK 挺全,也能通过 api 获取到图片。主要是不想整这么复杂,再者我还没绑定域名,其融合 CDN 加速域名会在 30 个自然日后自动回收。当然了,它的 CDN-HTTP 流量也是按量收费,貌似没腾讯的贵。基本是类似的一个套路吧。

考虑到自己这相册也不常用,放上些个性化图片就行,无需经常更新,所以就选择用免费的图床链接来实现。完整代码:

index.md

部分逻辑参考小红鸡的做法,这里代码做了简化,将图片标题、链接写成 json 格式即可。自定义排序,拷贝代码到你的网站即可看到效果,其他样式按需修改,效果:

我的相册——时光留影

文章推荐

文章结束时,开启相关文章推荐功能,会根据文章标签的相关度推荐相关的文章,效果像这样:

KP2m5V.jpg

  1. 该功能需要依赖 hexo-related-popular-posts 插件:
1
npm install hexo-related-popular-posts --save
  1. 在 /themes/next/layout/_macro/ 目录下,新建 post-related.swig 文件,内容如下:
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
{% set popular_posts = popular_posts_json(theme.related_posts.params, post) %}
{% if popular_posts.json and popular_posts.json.length > 0 %}
<div class="popular-posts-header">
<i class="fa fa-{{ theme.related_posts.icon }}"></i>
{{ theme.related_posts.title | default(__('post.related_posts')) }}
</div>

<details>
<summary>点击查看</summary>
<ul class="popular-posts">
{% for popular_post in popular_posts.json %}
<li class="popular-posts-item">
{% if popular_post.date and popular_post.date != '' %}
<div class="popular-posts-date">{{ popular_post.date }}</div>
{% endif %}
{% if popular_post.img && popular_post.img != '' %}
<div class="popular-posts-img"><img src="{{ popular_post.img }}" /></div>
{% endif %}
<div class="popular-posts-title"><a href="{{ popular_post.path }}" rel="bookmark">{{ popular_post.title }}</a></div>
{% if popular_post.excerpt && popular_post.excerpt != '' %}
<div class="popular-posts-excerpt"><p>{{ popular_post.excerpt }}</p></div>
{% endif %}
</li>
{% endfor %}
</ul>
</details>

{% endif %}

在同级别的 post.swig 中 END POST BODY 上方(POST 文章末尾)引入:

1
2
3
4
 <!-- 相关文章推荐 -->
{% if theme.related_posts.enable and (theme.related_posts.display_in_home or not is_index) %}
{% include 'post-related.swig' with { post: post } %}
{% endif %}
  1. 主题配置文件末尾加入如下配置:
1
2
3
4
5
6
7
8
9
10
11
12
# Dependencies: https://github.com/tea3/hexo-related-popular-posts
related_posts:
enable: true
title: 相关文章
icon: graduation-cap
display_in_home: false
params:
maxCount: 10
#PPMixingRate: 0.0
#isDate: false
#isImage: false
#isExcerpt: false
  1. 可选配置,在 /themes/next/source/css/_custom/custom.styl 中添加:
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
/*相关文章推荐 pc样式设置*/
summary{
outline: 0;
cursor: pointer;
margin-top: 15px;
+mobile() {/*手机端*/
font-size: 14px;
margin-top: 10px;
}
}
details{
margin-left: 20px;
}
details .popular-posts{
+mobile() {
margin: 5px -12px;
}
}
.popular-posts-header {
margin-top: 45px;
font-size: 20px;
font-weight: 900;
border-bottom: 1px solid #eee;
+mobile() {/*手机端*/
font-size: 18px;
margin-top: 25px;
}
}
ul.popular-posts .popular-posts-item .popular-posts-title a {
border-bottom: 1px solid #999;
&:hover{
border-bottom: none;
}
}

shareJS 分享

之前用的百度分享样式不大美观,加载不稳定,不支持 https(虽然改好了)等多种原因,遂使用 shareJS 进行了替换,文档里提供了多种安装方式,简单说下我的步骤。

  1. github 下载 zip 文件,将解压的文件夹 dist 放到 next/source/ 目录

  2. 在 next/layout/_layout.swig 中 body 标签内部引入:

1
2
3
<!--share.js-->
<link rel="stylesheet" href="/dist/css/share.min.css">
<script src="/dist/js/social-share.min.js"></script>
  1. 在 /themes/next/layout/_partials/share/ 目录下新增 sharejs.swig 文件,添加如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div
data-weibo-title="分享到微博"
data-qq-title="分享到QQ"
data-douban-title="分享到豆瓣"
class="social-share"
class="share-component"

{#
data-disabled="twitter,facebook"
#}

data-disabled="qzone,google+,linkedin"
data-description="Share.js - 一键分享到微博,QQ空间,腾讯微博,人人,豆瓣...">
分享到:
</div>
  1. 在 /themes/next/layout/post.swig 中 <div class="post-spread"> 标签内部 endif 前引入:
1
2
{% elseif theme.share_js %}
{% include '_partials/share/sharejs.swig' %}
  1. 主题配置文件增加:
1
share_js: true

鼠标样式

在 /themes/next/source/css/_custom/custom.styl 添加样式:

1
2
3
4
5
6
7
/* 鼠标样式 */
* {
cursor: url(/images/default.cur),auto;
}
:link {
cursor: url(/images/pointer.cur),auto
}

用到的两个文件:default.cur、pointer.cur 位于 images 目录下,因为是 .cur 这种静态光标文件,编辑器打开是一堆 ASCII 码,这里就不贴了,直接附上链接,当然,你也可以在浏览器里获取。

default.cur pointer.cur

鼠标点击特效(4种)

常用的 4 种特效为大家所列如下:

鼠标点击特效

在主题 _config.yml 中添加动态配置项:

1
2
3
cursor_effect:
enabled: true
type: love # fireworks:礼花 | explosion:爆炸 | love:浮出爱心 | text:浮出文字

在 /themes/next/layout/_custom/custom.swig 中,添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
{% if theme.cursor_effect %}
{% if theme.cursor_effect.type == "fireworks" %}
<script src="/js/cursor/fireworks.js"></script>
{% elseif theme.cursor_effect.type == "explosion" %}
<canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 1; pointer-events: none;" ></canvas>
<script src="//cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script>
<script src="/js/cursor/explosion.min.js"></script>
{% elseif theme.cursor_effect.type == "love" %}
<script src="/js/cursor/love.min.js"></script>
{% elseif theme.cursor_effect.type == "text" %}
<script src="/js/cursor/text.js"></script>
{% endif %}
{% endif %}

如果是第一次使用这个 custom.swig,则需要在 /themes/next/layout/_layout.swig 中引入

1
{% include '_custom/custom.swig' %}

这里主要用到 /themes/next/source/js/cursor/ 目录的 4 个 JS 文件,下边分别贴一下代码

fireworks.js
fireworks.js
explosion.min.js
1
"use strict";function updateCoords(e){pointerX=(e.clientX||e.touches[0].clientX)-canvasEl.getBoundingClientRect().left,pointerY=e.clientY||e.touches[0].clientY-canvasEl.getBoundingClientRect().top}function setParticuleDirection(e){var t=anime.random(0,360)*Math.PI/180,a=anime.random(50,180),n=[-1,1][anime.random(0,1)]*a;return{x:e.x+n*Math.cos(t),y:e.y+n*Math.sin(t)}}function createParticule(e,t){var a={};return a.x=e,a.y=t,a.color=colors[anime.random(0,colors.length-1)],a.radius=anime.random(16,32),a.endPos=setParticuleDirection(a),a.draw=function(){ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.fillStyle=a.color,ctx.fill()},a}function createCircle(e,t){var a={};return a.x=e,a.y=t,a.color="#F00",a.radius=0.1,a.alpha=0.5,a.lineWidth=6,a.draw=function(){ctx.globalAlpha=a.alpha,ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.lineWidth=a.lineWidth,ctx.strokeStyle=a.color,ctx.stroke(),ctx.globalAlpha=1},a}function renderParticule(e){for(var t=0;t<e.animatables.length;t++){e.animatables[t].target.draw()}}function animateParticules(e,t){for(var a=createCircle(e,t),n=[],i=0;i<numberOfParticules;i++){n.push(createParticule(e,t))}anime.timeline().add({targets:n,x:function(e){return e.endPos.x},y:function(e){return e.endPos.y},radius:0.1,duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule}).add({targets:a,radius:anime.random(80,160),lineWidth:0,alpha:{value:0,easing:"linear",duration:anime.random(600,800)},duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule,offset:0})}function debounce(e,t){var a;return function(){var n=this,i=arguments;clearTimeout(a),a=setTimeout(function(){e.apply(n,i)},t)}}var canvasEl=document.querySelector(".fireworks");if(canvasEl){var ctx=canvasEl.getContext("2d"),numberOfParticules=30,pointerX=0,pointerY=0,tap="mousedown",colors=["#FF1461","#18FF92","#5A87FF","#FBF38C"],setCanvasSize=debounce(function(){canvasEl.width=2*window.innerWidth,canvasEl.height=2*window.innerHeight,canvasEl.style.width=window.innerWidth+"px",canvasEl.style.height=window.innerHeight+"px",canvasEl.getContext("2d").scale(2,2)},500),render=anime({duration:1/0,update:function(){ctx.clearRect(0,0,canvasEl.width,canvasEl.height)}});document.addEventListener(tap,function(e){"sidebar"!==e.target.id&&"toggle-sidebar"!==e.target.id&&"A"!==e.target.nodeName&&"IMG"!==e.target.nodeName&&(render.play(),updateCoords(e),animateParticules(pointerX,pointerY))},!1),setCanvasSize(),window.addEventListener("resize",setCanvasSize,!1)}"use strict";function updateCoords(e){pointerX=(e.clientX||e.touches[0].clientX)-canvasEl.getBoundingClientRect().left,pointerY=e.clientY||e.touches[0].clientY-canvasEl.getBoundingClientRect().top}function setParticuleDirection(e){var t=anime.random(0,360)*Math.PI/180,a=anime.random(50,180),n=[-1,1][anime.random(0,1)]*a;return{x:e.x+n*Math.cos(t),y:e.y+n*Math.sin(t)}}function createParticule(e,t){var a={};return a.x=e,a.y=t,a.color=colors[anime.random(0,colors.length-1)],a.radius=anime.random(16,32),a.endPos=setParticuleDirection(a),a.draw=function(){ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.fillStyle=a.color,ctx.fill()},a}function createCircle(e,t){var a={};return a.x=e,a.y=t,a.color="#F00",a.radius=0.1,a.alpha=0.5,a.lineWidth=6,a.draw=function(){ctx.globalAlpha=a.alpha,ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.lineWidth=a.lineWidth,ctx.strokeStyle=a.color,ctx.stroke(),ctx.globalAlpha=1},a}function renderParticule(e){for(var t=0;t<e.animatables.length;t++){e.animatables[t].target.draw()}}function animateParticules(e,t){for(var a=createCircle(e,t),n=[],i=0;i<numberOfParticules;i++){n.push(createParticule(e,t))}anime.timeline().add({targets:n,x:function(e){return e.endPos.x},y:function(e){return e.endPos.y},radius:0.1,duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule}).add({targets:a,radius:anime.random(80,160),lineWidth:0,alpha:{value:0,easing:"linear",duration:anime.random(600,800)},duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule,offset:0})}function debounce(e,t){var a;return function(){var n=this,i=arguments;clearTimeout(a),a=setTimeout(function(){e.apply(n,i)},t)}}var canvasEl=document.querySelector(".fireworks");if(canvasEl){var ctx=canvasEl.getContext("2d"),numberOfParticules=30,pointerX=0,pointerY=0,tap="mousedown",colors=["#FF1461","#18FF92","#5A87FF","#FBF38C"],setCanvasSize=debounce(function(){canvasEl.width=2*window.innerWidth,canvasEl.height=2*window.innerHeight,canvasEl.style.width=window.innerWidth+"px",canvasEl.style.height=window.innerHeight+"px",canvasEl.getContext("2d").scale(2,2)},500),render=anime({duration:1/0,update:function(){ctx.clearRect(0,0,canvasEl.width,canvasEl.height)}});document.addEventListener(tap,function(e){"sidebar"!==e.target.id&&"toggle-sidebar"!==e.target.id&&"A"!==e.target.nodeName&&"IMG"!==e.target.nodeName&&(render.play(),updateCoords(e),animateParticules(pointerX,pointerY))},!1),setCanvasSize(),window.addEventListener("resize",setCanvasSize,!1)};
love.min.js
1
!function(e,t,a){function n(){c(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),o(),r()}function r(){for(var e=0;e<d.length;e++)d[e].alpha<=0?(t.body.removeChild(d[e].el),d.splice(e,1)):(d[e].y--,d[e].scale+=.004,d[e].alpha-=.013,d[e].el.style.cssText="left:"+d[e].x+"px;top:"+d[e].y+"px;opacity:"+d[e].alpha+";transform:scale("+d[e].scale+","+d[e].scale+") rotate(45deg);background:"+d[e].color+";z-index:99999");requestAnimationFrame(r)}function o(){var t="function"==typeof e.onclick&&e.onclick;e.onclick=function(e){t&&t(),i(e)}}function i(e){var a=t.createElement("div");a.className="heart",d.push({el:a,x:e.clientX-5,y:e.clientY-5,scale:1,alpha:1,color:s()}),t.body.appendChild(a)}function c(e){var a=t.createElement("style");a.type="text/css";try{a.appendChild(t.createTextNode(e))}catch(t){a.styleSheet.cssText=e}t.getElementsByTagName("head")[0].appendChild(a)}function s(){return"rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"}var d=[];e.requestAnimationFrame=function(){return e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)}}(),n()}(window,document);
text.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
var a_idx = 0;
jQuery(document).ready(function($) {
$("body").click(function(e) {
var a = new Array("富强", "民主", "文明", "和谐", "自由", "平等", "公正" ,"法治", "爱国", "敬业", "诚信", "友善");
var $i = $("<span/>").text(a[a_idx]);
var x = e.pageX,
y = e.pageY;
$i.css({
"z-index": 99999,
"top": y - 28,
"left": x - a[a_idx].length * 8,
"position": "absolute",
"color": "#ff7a45"
});
$("body").append($i);
$i.animate({
"top": y - 180,
"opacity": 0
}, 1500, function() {
$i.remove();
});
a_idx = (a_idx + 1) % a.length;
});
});

打字特效 (评论、留言)

此功能主要通过 JS 监听页面的 input 输入框事件来实现。首先在主题 _config.yml 中添加动态配置项

1
2
3
4
typing_effect:
enabled: true
colorful: true # 礼花
shake: false # 震动

在 /themes/next/layout/_custom/custom.swig 中引入依赖

1
2
3
4
5
6
7
8
{% if theme.typing_effect %}
<script src="/js/src/activate-power-mode.min.js"></script>
<script>
POWERMODE.colorful = {{ theme.typing_effect.colorful }};
POWERMODE.shake = {{ theme.typing_effect.shake }};
document.body.addEventListener('input', POWERMODE);
</script>
{% endif %}

其中的 activate-power-mode.min.js 位于 /themes/next/source/js/src/ 目录,代码如下:

1
(function webpackUniversalModuleDefinition(root,factory){if(typeof exports==='object'&&typeof module==='object')module.exports=factory();else if(typeof define==='function'&&define.amd)define([],factory);else if(typeof exports==='object')exports["POWERMODE"]=factory();else root["POWERMODE"]=factory()})(this,function(){return(function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId])return installedModules[moduleId].exports;var module=installedModules[moduleId]={exports:{},id:moduleId,loaded:false};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.loaded=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.p="";return __webpack_require__(0)})([function(module,exports,__webpack_require__){'use strict';var canvas=document.createElement('canvas');canvas.width=window.innerWidth;canvas.height=window.innerHeight;canvas.style.cssText='position:fixed;top:0;left:0;pointer-events:none;z-index:999999';window.addEventListener('resize',function(){canvas.width=window.innerWidth;canvas.height=window.innerHeight});document.body.appendChild(canvas);var context=canvas.getContext('2d');var particles=[];var particlePointer=0;POWERMODE.shake=true;function getRandom(min,max){return Math.random()*(max-min)+min}function getColor(el){if(POWERMODE.colorful){var u=getRandom(0,360);return'hsla('+getRandom(u-10,u+10)+', 100%, '+getRandom(50,80)+'%, '+1+')'}else{return window.getComputedStyle(el).color}}function getCaret(){var el=document.activeElement;var bcr;if(el.tagName==='TEXTAREA'||(el.tagName==='INPUT'&&el.getAttribute('type')==='text')){var offset=__webpack_require__(1)(el,el.selectionStart);bcr=el.getBoundingClientRect();return{x:offset.left+bcr.left,y:offset.top+bcr.top,color:getColor(el)}}var selection=window.getSelection();if(selection.rangeCount){var range=selection.getRangeAt(0);var startNode=range.startContainer;if(startNode.nodeType===document.TEXT_NODE){startNode=startNode.parentNode}bcr=range.getBoundingClientRect();return{x:bcr.left,y:bcr.top,color:getColor(startNode)}}return{x:0,y:0,color:'transparent'}}function createParticle(x,y,color){return{x:x,y:y,alpha:1,color:color,velocity:{x:-1+Math.random()*2,y:-3.5+Math.random()*2}}}function POWERMODE(){{var caret=getCaret();var numParticles=5+Math.round(Math.random()*10);while(numParticles--){particles[particlePointer]=createParticle(caret.x,caret.y,caret.color);particlePointer=(particlePointer+1)%500}}{if(POWERMODE.shake){var intensity=1+2*Math.random();var x=intensity*(Math.random()>0.5?-1:1);var y=intensity*(Math.random()>0.5?-1:1);document.body.style.marginLeft=x+'px';document.body.style.marginTop=y+'px';setTimeout(function(){document.body.style.marginLeft='';document.body.style.marginTop=''},75)}}};POWERMODE.colorful=false;function loop(){requestAnimationFrame(loop);context.clearRect(0,0,canvas.width,canvas.height);for(var i=0;i<particles.length;++i){var particle=particles[i];if(particle.alpha<=0.1)continue;particle.velocity.y+=0.075;particle.x+=particle.velocity.x;particle.y+=particle.velocity.y;particle.alpha*=0.96;context.globalAlpha=particle.alpha;context.fillStyle=particle.color;context.fillRect(Math.round(particle.x-1.5),Math.round(particle.y-1.5),3,3)}}requestAnimationFrame(loop);module.exports=POWERMODE},function(module,exports){(function(){var properties=['direction','boxSizing','width','height','overflowX','overflowY','borderTopWidth','borderRightWidth','borderBottomWidth','borderLeftWidth','borderStyle','paddingTop','paddingRight','paddingBottom','paddingLeft','fontStyle','fontVariant','fontWeight','fontStretch','fontSize','fontSizeAdjust','lineHeight','fontFamily','textAlign','textTransform','textIndent','textDecoration','letterSpacing','wordSpacing','tabSize','MozTabSize'];var isFirefox=window.mozInnerScreenX!=null;function getCaretCoordinates(element,position,options){var debug=options&&options.debug||false;if(debug){var el=document.querySelector('#input-textarea-caret-position-mirror-div');if(el){el.parentNode.removeChild(el)}}var div=document.createElement('div');div.id='input-textarea-caret-position-mirror-div';document.body.appendChild(div);var style=div.style;var computed=window.getComputedStyle?getComputedStyle(element):element.currentStyle;style.whiteSpace='pre-wrap';if(element.nodeName!=='INPUT')style.wordWrap='break-word';style.position='absolute';if(!debug)style.visibility='hidden';properties.forEach(function(prop){style[prop]=computed[prop]});if(isFirefox){if(element.scrollHeight>parseInt(computed.height))style.overflowY='scroll'}else{style.overflow='hidden'}div.textContent=element.value.substring(0,position);if(element.nodeName==='INPUT')div.textContent=div.textContent.replace(/\s/g,"\u00a0");var span=document.createElement('span');span.textContent=element.value.substring(position)||'.';div.appendChild(span);var coordinates={top:span.offsetTop+parseInt(computed['borderTopWidth']),left:span.offsetLeft+parseInt(computed['borderLeftWidth'])};if(debug){span.style.backgroundColor='#aaa'}else{document.body.removeChild(div)}return coordinates}if(typeof module!="undefined"&&typeof module.exports!="undefined"){module.exports=getCaretCoordinates}else{window.getCaretCoordinates=getCaretCoordinates}}())}])});

代码块复制功能

依赖 clipboard.js 实现,个性化配置可参考官方文档。在 /themes/next/layout/_custom/custom.swig 引入下载的 JS

1
2
<script type="text/javascript" src="/js/src/clipboard.min.js"></script>
<script type="text/javascript" src="/js/src/clipboard-use.js"></script>

位于 /themes/next/source/js/src/ 目录下的 clipboard.min.js 和 clipboard-use.js 代码分别如下

1
2
3
4
5
6
7
/*!
* clipboard.min.js v2.0.4
* https://zenorocha.github.io/clipboard.js
*
* Licensed MIT © Zeno Rocha
*/
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return function(n){var o={};function r(t){if(o[t])return o[t].exports;var e=o[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}return r.m=n,r.c=o,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=0)}([function(t,e,n){"use strict";var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}return function(t,e,n){return e&&o(t.prototype,e),n&&o(t,n),t}}(),a=o(n(1)),c=o(n(3)),u=o(n(4));function o(t){return t&&t.__esModule?t:{default:t}}var l=function(t){function o(t,e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,o);var n=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}(this,(o.__proto__||Object.getPrototypeOf(o)).call(this));return n.resolveOptions(e),n.listenClick(t),n}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}(o,c.default),i(o,[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===r(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=(0,u.default)(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new a.default({action:this.action(e),target:this.target(e),text:this.text(e),container:this.container,trigger:e,emitter:this})}},{key:"defaultAction",value:function(t){return s("action",t)}},{key:"defaultTarget",value:function(t){var e=s("target",t);if(e)return document.querySelector(e)}},{key:"defaultText",value:function(t){return s("text",t)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],e="string"==typeof t?[t]:t,n=!!document.queryCommandSupported;return e.forEach(function(t){n=n&&!!document.queryCommandSupported(t)}),n}}]),o}();function s(t,e){var n="data-clipboard-"+t;if(e.hasAttribute(n))return e.getAttribute(n)}t.exports=l},function(t,e,n){"use strict";var o,r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i=function(){function o(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}return function(t,e,n){return e&&o(t.prototype,e),n&&o(t,n),t}}(),a=n(2),c=(o=a)&&o.__esModule?o:{default:o};var u=function(){function e(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),this.resolveOptions(t),this.initSelection()}return i(e,[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action=t.action,this.container=t.container,this.emitter=t.emitter,this.target=t.target,this.text=t.text,this.trigger=t.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"selectFake",value:function(){var t=this,e="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return t.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[e?"right":"left"]="-9999px";var n=window.pageYOffset||document.documentElement.scrollTop;this.fakeElem.style.top=n+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.container.appendChild(this.fakeElem),this.selectedText=(0,c.default)(this.fakeElem),this.copyText()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=(0,c.default)(this.target),this.copyText()}},{key:"copyText",value:function(){var e=void 0;try{e=document.execCommand(this.action)}catch(t){e=!1}this.handleResult(e)}},{key:"handleResult",value:function(t){this.emitter.emit(t?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:"copy";if(this._action=t,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(t){if(void 0!==t){if(!t||"object"!==(void 0===t?"undefined":r(t))||1!==t.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&t.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(t.hasAttribute("readonly")||t.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=t}},get:function(){return this._target}}]),e}();t.exports=u},function(t,e){t.exports=function(t){var e;if("SELECT"===t.nodeName)t.focus(),e=t.value;else if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName){var n=t.hasAttribute("readonly");n||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),n||t.removeAttribute("readonly"),e=t.value}else{t.hasAttribute("contenteditable")&&t.focus();var o=window.getSelection(),r=document.createRange();r.selectNodeContents(t),o.removeAllRanges(),o.addRange(r),e=o.toString()}return e}},function(t,e){function n(){}n.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,a=o.length;i<a;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=n},function(t,e,n){var d=n(5),h=n(6);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!d.string(e))throw new TypeError("Second argument must be a String");if(!d.fn(n))throw new TypeError("Third argument must be a Function");if(d.node(t))return s=e,f=n,(l=t).addEventListener(s,f),{destroy:function(){l.removeEventListener(s,f)}};if(d.nodeList(t))return a=t,c=e,u=n,Array.prototype.forEach.call(a,function(t){t.addEventListener(c,u)}),{destroy:function(){Array.prototype.forEach.call(a,function(t){t.removeEventListener(c,u)})}};if(d.string(t))return o=t,r=e,i=n,h(document.body,o,r,i);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,a,c,u,l,s,f}},function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},function(t,e,n){var a=n(7);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=a(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},function(t,e){if("undefined"!=typeof Element&&!Element.prototype.matches){var n=Element.prototype;n.matches=n.matchesSelector||n.mozMatchesSelector||n.msMatchesSelector||n.oMatchesSelector||n.webkitMatchesSelector}t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}}])});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*页面载入完成后,创建复制按钮*/
!function (e, t, a) {
/* code */
var initCopyCode = function(){
var copyHtml = '';
copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
//fa fa-globe可以去字体库替换自己想要的图标
copyHtml += ' <i class="fa fa-clipboard"></i><span>复制</span>';
copyHtml += '</button>';
$(".highlight .code pre").before(copyHtml);
new ClipboardJS('.btn-copy', {
target: function(trigger) {
return trigger.nextElementSibling;
}
});
}
initCopyCode();
}(window, document);

可根据需要在 /themes/next/source/css/_custom/custom.styl 加 CSS

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
.highlight{
//position: relative;
position: static;
}
highlight-wrap {
background: #008b89;
}
.btn-copy {
display: inline-block;
cursor: pointer;
background-color: #eee;
background-image: linear-gradient(#fcfcfc,#eee);
border: 1px solid #d5d5d5;
border-radius: 3px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-appearance: none;
font-size: 13px;
font-weight: 700;
line-height: 20px;
color: #333;
-webkit-transition: opacity .3s ease-in-out;
-o-transition: opacity .3s ease-in-out;
transition: opacity .3s ease-in-out;
padding: 2px 6px;
position: absolute;
right: 5px;
top: 5px;
opacity: 0;
}
.btn-copy span {
margin-left: 5px;
}
.highlight:hover .btn-copy{
opacity: 1;
}

类知乎卡片链接

  1. 在 /themes/next/source/js/src/ 下新建 linkcard.js ,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
window.onload=function(){
var LinkCards=document.getElementsByClassName('LinkCard');
if(LinkCards.length != 0){
var LinkCard=LinkCards[0];
var link=LinkCard.href;
var title=LinkCard.innerText;
LinkCard.innerHTML="<style type=text/css>.LinkCard,.LinkCard:hover{text-decoration:none;border:none!important;color:inherit!important}.LinkCard{position:relative;display:block;margin:5px auto;width:330px;box-sizing:border-box;border-radius:12px;max-width:100%;overflow:hidden;color:inherit;text-decoration:none}.ztext{word-break:break-word;line-height:1.6}.LinkCard-backdrop{position:absolute;top:0;left:0;right:0;bottom:0;background-repeat:no-repeat;-webkit-filter:blur(20px);filter:blur(20px);background-size:cover;background-position:center}.LinkCard,.LinkCard:hover{text-decoration:none;border:none!important;color:inherit!important}.LinkCard-content{position:relative;display:flex;align-items:center;justify-content:space-between;padding:12px;border-radius:inherit;background-color:rgba(246,246,246,0.88)}.LinkCard-text{overflow:hidden;width:260px;}.LinkCard-title{white-space: nowrap;display:-webkit-box;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis;max-height:calc(16px * 1.25 * 2);font-size:16px;font-weight:500;line-height:1.25;color:#1a1a1a}@media(max-width: 767px){.LinkCard-title{font-size:13px;}}.LinkCard-meta{display:flex;margin-top:4px;font-size:14px;line-height:20px;color:#999;white-space:nowrap}.LinkCard-imageCell{margin-left:28px;border-radius:30px;width:70px;}.LinkCard-image{display:block;width:60px;height:auto;border-radius:inherit}</style><span class=LinkCard-backdrop style=background-image:url(https://zhstatic.zhihu.com/assets/zhihu/editor/zhihu-card-default.svg)></span><span class=LinkCard-content><span class=LinkCard-text><span class=LinkCard-title>"+title+"</span><span class=LinkCard-meta><span style=display:inline-flex;align-items:center><svg class="+"'Zi Zi--InsertLink'"+" fill=currentColor viewBox="+"'0 0 24 24'"+" width=17 height=17><path d="+"'M6.77 17.23c-.905-.904-.94-2.333-.08-3.193l3.059-3.06-1.192-1.19-3.059 3.058c-1.489 1.489-1.427 3.954.138 5.519s4.03 1.627 5.519.138l3.059-3.059-1.192-1.192-3.059 3.06c-.86.86-2.289.824-3.193-.08zm3.016-8.673l1.192 1.192 3.059-3.06c.86-.86 2.289-.824 3.193.08.905.905.94 2.334.08 3.194l-3.059 3.06 1.192 1.19 3.059-3.058c1.489-1.489 1.427-3.954-.138-5.519s-4.03-1.627-5.519-.138L9.786 8.557zm-1.023 6.68c.33.33.863.343 1.177.029l5.34-5.34c.314-.314.3-.846-.03-1.176-.33-.33-.862-.344-1.176-.03l-5.34 5.34c-.314.314-.3.846.03 1.177z'"+" fill-rule=evenodd></path></svg></span>"+link+"</span></span><span class=LinkCard-imageCell><img class=LinkCard-image alt=图标 src=/images/linkcard.png></span></span>";

for (var i = LinkCards.length - 1; i >= 1; i--) {
LinkCard=LinkCards[i];
title=LinkCard.innerText;
link=LinkCard.href;
LinkCard.innerHTML="<span class=LinkCard-backdrop style=background-image:url(https://zhstatic.zhihu.com/assets/zhihu/editor/zhihu-card-default.svg)></span><span class=LinkCard-content><span class=LinkCard-text><span class=LinkCard-title>"+title+"</span><span class=LinkCard-meta><span style=display:inline-flex;align-items:center><svg class="+"'Zi Zi--InsertLink'"+" fill=currentColor viewBox="+"'0 0 24 24'"+" width=17 height=17><path d="+"'M6.77 17.23c-.905-.904-.94-2.333-.08-3.193l3.059-3.06-1.192-1.19-3.059 3.058c-1.489 1.489-1.427 3.954.138 5.519s4.03 1.627 5.519.138l3.059-3.059-1.192-1.192-3.059 3.06c-.86.86-2.289.824-3.193-.08zm3.016-8.673l1.192 1.192 3.059-3.06c.86-.86 2.289-.824 3.193.08.905.905.94 2.334.08 3.194l-3.059 3.06 1.192 1.19 3.059-3.058c1.489-1.489 1.427-3.954-.138-5.519s-4.03-1.627-5.519-.138L9.786 8.557zm-1.023 6.68c.33.33.863.343 1.177.029l5.34-5.34c.314-.314.3-.846-.03-1.176-.33-.33-.862-.344-1.176-.03l-5.34 5.34c-.314.314-.3.846.03 1.177z'"+" fill-rule=evenodd></path></svg></span>"+link+"</span></span><span class=LinkCard-imageCell><img class=LinkCard-image alt=图标 src=/images/linkcard.png></span></span>";
}
}
}

需要修改 /images/linkcard.png 为你自己的图片。附上我在用的:linkcard.png

  1. 在 /themes/next/layout/_layout.swig 中 body 结束标签前,引入刚才新建的 js:
1
<script type="text/javascript" src="/js/src/linkcard.js"></script>

使用方式:

1
<a href="https://www.liaofuzhan.com/photos/" class="LinkCard">我的相册——时光留影</a>

效果:

我的相册——时光留影

文章首字下沉

在 themes/next/source/css/_custom/custom.styl 中添加如下样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.post-body>p:first-child::first-letter{
float: left;
/* height: 32px;*/
margin-top: 14px;
margin-right: 6px;
color: #555;
font-size: 42px;
line-height: 28px;
font-style: normal;
font-weight: 400;
+mobile(){
margin-top: 10px;
margin-right: 4px;
font-size: 26px;
line-height: 20px;
}
}

这是设置 class = post-body 这个 div 下的第一个 p 标签的样式,数值按需调整,效果:

Me2j8x.jpg

文章评分功能

NexT 主题中已经集成了widgetpack 的星级评分功能,只需注册账号后,修改主题配置:

1
2
3
4
5
6
# Star rating support to each article.
# To get your ID visit https://widgetpack.com
rating:
enable: true
id: your id #<app_id>
color: ff9800

可以在 widgetpack 控制台中修改评分认证

KPgc3F.jpg

有三个选项,根据需要设置。

canvas粒子时钟

网上看到一款不错的 canvas 粒子时钟,遂整合到自己网站中来了,操作步骤:

  1. 在 /themes/next/layout/_custom/ 目录下,新建 clock.swig 文件,内容如下:

    clock.swig
  2. 在 /themes/next/layout/_macro/sidebar.swig 中引入:

1
{% include '../_custom/clock.swig' %}

可根据自己的偏好来设置具体位置,我是加在了侧栏的末尾:

uiJDPJ.gif

另一款样式可参考:

HTML5 Canvas 实现会跳舞的时间动画

网站运行时间

  1. 在 /themes/next/layout/_custom/ 下新建 runtime.swig,拷贝如下内容:
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
<div id="days"></div>
</script>
<script language="javascript">
function show_date_time(){
window.setTimeout("show_date_time()", 1000);
BirthDay=new Date("08/07/2019 20:00:00");
today=new Date();
timeold=(today.getTime()-BirthDay.getTime());
sectimeold=timeold/1000
secondsold=Math.floor(sectimeold);
msPerDay=24*60*60*1000
e_daysold=timeold/msPerDay
daysold=Math.floor(e_daysold);
e_hrsold=(e_daysold-daysold)*24;
hrsold=setzero(Math.floor(e_hrsold));
e_minsold=(e_hrsold-hrsold)*60;
minsold=setzero(Math.floor((e_hrsold-hrsold)*60));
seconds=setzero(Math.floor((e_minsold-minsold)*60));
document.getElementById('days').innerHTML="已运行"+daysold+"天"+hrsold+"时"+minsold+"分"+seconds+"秒";
}
function setzero(i){
if (i<10)
{i="0" + i};
return i;
}
show_date_time();
</script>

修改 BirthDay 为你建站的时间

  1. 在 /themes/next/layout/_macro/sidebar.swig 中引入:
1
{% include '../_custom/runtime.swig' %}

网站动态背景图片

在 /themes/next/source/css/_custom/custom.styl 中设置 body 属性

1
2
3
4
5
6
body {
background:url(https://source.unsplash.com/random/1600x900);
background-repeat: no-repeat;
background-attachment:fixed;
background-position:50% 50%;
}

其中的 url 可根据 Unsplash Source 这个网站来生成,比如随机选择、根据指定用户选择等等,效果:

KPrR8H.jpg

其它的背景点击特效—波浪、线条、水纹波动等,可以在主题 _config.yml 中 canvas 系列进行设置,如 canvas_nest、canvas_ribbon。 motion 配置项则是设置诸如侧栏、文章标题的加载动画。

网站 logo 炫彩效果

PC 端只显示在左上角 logo 位置,移动端效果如下

移动端效果

我使用的是 NexT 5 的 Pisces(主题 _config.yml 中 scheme 配置),主要设置样式为 site-meta,其它的主题类型需要自己调整。在 /themes/next/source/css/_custom/custom.styl 中添加以下 css ,如果之前已经设置了,根据情况进行替换:

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
.site-title{
background-image: linear-gradient(
to right,
orangered,
orange,
gold,
lightgreen,
cyan,
dodgerblue,
mediumpurple,
hotpink,
orangered
);
background-size: 110vw;
-webkit-background-clip: text;
color: rgba(0,0,0,0.1); /* transparent IE 不支持 */
animation: sliding 30s linear infinite;
}
@keyframes sliding{
to{
background-position: -2000vw;
}
}

.site-meta,
.site-subtitle {
color: rgba(0,0,0,0.1); /* transparent IE 不支持 */
animation: hue 1.5s linear infinite;
background-image: linear-gradient(to right bottom, rgb(255,0,0), rgb(255,128,0), rgb(255,255,0), rgb(0,255,0), rgb(0,255,128), rgb(0,255,255), rgb(0,128,255), rgb(0,0,255), rgb(128,0,255), rgb(255,0,255), rgb(255,0,128));
-webkit-background-clip: text;
}
@keyframes hue {
from {
filter: hue-rotate(0);
}
to {
filter: hue-rotate(-360deg);
}
}

.site-meta{
background: #ecf9f8;
+mobile(){
padding: 10px 0;
background-image: linear-gradient(90deg,#f79533 0,#f37055 15%,#ef4e7b 30%,#a166ab 44%,#5073b8 58%,#1098ad 72%,#07b39b 86%,#6dba82 100%)!important;
}
}

其它炫彩字体效果可参考:

CSS 3 立体文字最佳实践

旋转魔方(个性化返回顶部)

效果 1 :

K9t8nH.gif

效果 2 :

K9tGBd.gif

之前回到顶部功能使用的是一张图片,大屏幕下计算会有问题,然后自己就在魔方里加了个方法来实现,正好移动端也能用。

KP2qiV.jpg

说一下这个猫的配置吧,给有需要的朋友。只需在 /themes/next/source/css/_custom/custom.styl 添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.back-to-top {
//right: 60px;
width: 70px; //图片素材宽度
height: 900px; //图片素材高度
top: -900px;
bottom: unset;
transition: all .5s ease-in-out;
background: url("/images/scroll.png");
//隐藏箭头图标
> i {
display: none;
}
&.back-to-top-on {
bottom: unset;
top: 100vh < (900px + 200px) ? calc( 100vh - 900px - 200px ) : 0px;
}
}

然后修改 background 里的 url 为图片地址。 下载图片 保存为 scroll.png 放到 /themes/next/source/images/ 目录即可。

魔方一

100素材网 看到的,自己修改了下大小就放网站里来了。在 /themes/next/layout/_custom/ 下新建 cube-mini.swig(名字随便吧 -.- ),内容如下:

cube-mini.swig

当然,也可以直接扒 100 素材网的样式再修改。

魔方二

样式来自 FEWY,初始时魔方比较大,我已调整。在 /themes/next/layout/_custom/ 下新建 cube-hollow.swig,内容如下:

cube-hollow.swig
引用
  1. 在 /themes/next/layout/_custom/custom.swig 中引入新建的文件
1
2
3
4
5
6
7
8
<!-- 旋转魔方 -->
{% if theme.cube.enable %}
{% if theme.cube.type == "mini" %}
{% include 'cube-mini.swig' %}
{% elseif theme.cube.type == "hollow" %}
{% include 'cube-hollow.swig' %}
{% endif %}
{% endif %}
  1. 在主题 _config.yml 中新建以下动态配置项
1
2
3
cube:
enable: true
type: hollow # mini | hollow

图片链接替换成你自己的,hexo 三连,移动端也有效果了,enjoy!

一些建议

图片压缩

可以使用 WebP 格式 的图片替代 JPG、PNG 等,比如这样: 示例图片,在 Chrome 和 FireFox 都正常,IE 和 Safari 目前还不兼容,毕竟是谷歌推出的技术。我们也可通过修改 hexo 代码,增加 webp 图片支持,比如 这篇文章,不过也有点麻烦 -.-!

下边推荐一个不错的网站,在线 JPG to WebP,再 WebP to JPG,图片就会被压缩,支持 GIF 、Video 等多种格式转换。

Online GIF maker and image editor

比如我上传本地 JPG 图片,下方显示:

1
File size: 509.99KiB, width: 1182px, height: 1182px, type: png

转换成 webp 后,大小仅有 26 kb 左右,即上边的示例图片:

1
File size: 26.34KiB (-94.84%), width: 1182px, height: 1182px, frames: 1, type: webp

拷贝转换后的 webp 图片地址,再选择 WebP to JPG 选项,粘贴进输入框,upload 后,在 image quality factor、Background color 默认情况下,转回 JPG :

1
File size: 59.33KiB (+125.26%), width: 1182px, height: 1182px, type: jpg

相比 webp,图片又变大了,但相比原图,却是小了很多,压缩了好几倍,清晰度没什么太大变化。部分图片压缩效果可能没那么理想,比如本身就不大的图片,有时候反而还压大了。转 PNG 图片会大一些,可先转为 JPG,对清晰度要求不高的,可以尝试多转换几次。

点击查看

本文标题:Hexo NexT主题美化2.0

文章作者:北宸

发布时间:2019年09月21日 - 15:55:24

最后更新:2023年08月19日 - 13:26:00

原始链接:https://www.liaofuzhan.com/posts/2114475547.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------------本文结束 感谢您的阅读-------------------
🌞