实用指南:Typecho 系统的 Joe 主题美化技巧持续更新

Joe 主题美化与功能增强全攻略

生命不息,折腾不止,哎,就是玩儿……

本站环境

  • PHP:8.0.2
  • Mysql:8.4.2
  • Typecho:1.2.1 正式版
  • Joe:7.7.1

其他版本的 PHP、Typecho 和 Joe 不确定其可行性,请自行测试~

基础设置

这个其实不用写,安装 Joe 主题后去配置网站基础设置就好了。

开启 gzip 压缩

打开 typecho 目录下的 index.php,并在开头添加

1
ob_start('ob_gzhandler');

robots.txt

在网站根目录下创建并设置 robots.txt, 方便搜索引擎爬虫爬取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
User-agent: *
Allow: /*.html$
Allow: /usr
Allow: /*.png$
Allow: /*.jpg$
Allow: /*.jepg$
Allow: /*.gif$
Allow: /*.bmp$
Disallow: /admin/
Disallow: /install/
Disallow: /var/
Disallow: /config.inc.php
Disallow: /install.php
Disallow: /.js
Disallow: /.css
Disallow: /feed
Sitmap: 你的域名/sitemap.xml

可借助 你的域名 /robots.txt 查看是否设置成功。之后在百度收录平台完成 robots.txt 的更新

美化

网站主题各种颜色修改

位置:主题后台设置 - 全局设置 - 自定义 CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
body {
--theme: #000000;
--background: #ffffff;
--main: #303133;
--routine: #606266;
--minor: #909399;
--seat: #c0c4cc;
--classA: #dcdfe6;
--classB: #e4e7ed;
--classC: #ebeef5;
--classD: #f2f6fc;
--radius-wrap: 10px;
--radius-inner: 15px;
--text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
--box-shadow: 0px 0px 20px -5px rgba(158, 158, 158, 0.22);
}

说明:

  • –theme:主题颜色,用于修改整个网站的主题色彩
  • –background:主体卡片背景颜色
  • –main:文字的颜色,颜色最深的
  • –routine:文字的颜色,颜色稍微次于上面那个
  • –minor:文字的颜色,颜色稍微次于上面那个
  • –seat:文字的颜色,颜色稍微次于上面那个
  • –classA:横线、分割线用的颜色,颜色最深的
  • –classB:横线、分割线用的颜色,颜色稍微次于上面那个
  • –classC:横线、分割线用的颜色,颜色稍微次于上面那个
  • –classD:横线、分割线用的颜色,颜色稍微次于上面那个
  • –radius-wrap:外层包裹的圆角度数
  • –radius-inner:里层包裹的圆角度数
  • –text-shadow:文章标题的字体阴影
  • –box-shadow:主体卡片阴影

右上角搜索框文字修改

修改文件,在主题目录 Joe/public/header.php 中,大概 139 行:
可将 Search 修改为任意字,比如 “搜索”
大概 138 行:可修改默认显示字体,即可将搜索框中 “请输入关键字…” 修改为任意字。

头像呼吸灯

在主题后台设置 - 全局设置 - 自定义 CSS 里添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*头像呼吸光环和鼠标悬停旋转放大*/
.avatar {
border-radius: 50%;
animation: light 4s ease-in-out infinite;
transition: 0.5s;
}
.avatar:hover {
transform: scale(1.15) rotate(720deg);
}
@keyframes light {
0%{box-shadow: 0 0 4px #f00;}
25%{box-shadow: 0 0 16px #0f0;}
50%{box-shadow: 0 0 4px #00f;}
75%{box-shadow: 0 0 16px #0f0;}
100%{box-shadow: 0 0 4px #f00;}
}

文章目录树

目前目录树的结构有很多,比如添加在页面左侧隐藏式的,或者是添加在文章左侧的。
这里采用的是添加在右侧栏当中的,随文章置顶的:

第一步

首先,在 public/aside.php 文件中,添加如下内容,可以在作者卡片之后添加,不过具体想摆放的位置看自己的设计,当前设计是放在作者卡片之后。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--  仅在文章生效,如果需要页面,下面第一行判断加上 || $this->is('page')-->
<?php if ($this->is('post')) : ?>
<section class="joe_aside__item catalogue">
<div class="joe_aside__item-title">
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
p-id="2084"
width="18" height="18">
<path d="M640 192H224c-17.7 0-32-14.3-32-32s14.3-32 32-32h416c17.7 0 32 14.3 32 32s-14.3 32-32 32zM960 544H224c-17.7 0-32-14.3-32-32s14.3-32 32-32h736c17.7 0 32 14.3 32 32s-14.3 32-32 32zM640 896H224c-17.7 0-32-14.3-32-32s14.3-32 32-32h416c17.7 0 32 14.3 32 32s-14.3 32-32 32zM96 192H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h32c17.7 0 32 14.3 32 32s-14.3 32-32 32zM96 544H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h32c17.7 0 32 14.3 32 32s-14.3 32-32 32zM96 896H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h32c17.7 0 32 14.3 32 32s-14.3 32-32 32z"
p-id="2085"></path>
</svg>
<span class="text">目录</span>
<span class="line"></span>
</div>
<div class="joe_aside__item-contain">
<ul class="catalogue-items">
</ul>
</div>
</section>
<?php endif; ?>

第二步

在主题后台设置 - 全局设置 - 自定义 JS 中:添加如下内容,或者你也可以加在 assets/js/joe.global.js 文件中,记得将 joe.global.min.js 也同步更新下,如果你使用的是 joe.global.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
function get_catalogs(article_content) {
const titleTag = ["H1", "H2", "H3"];
let titles = [];
article_content.childNodes.forEach((e, index) => {
const id = "header-" + index;
if (titleTag.includes(e.nodeName)) {
titles.push({
id: id,
text: e.textContent,
level: Number(e.nodeName.substring(1, 2))
});
e.setAttribute("id", id);
}
});
return titles;
}

// 找到目录容器
article_content = document.querySelector('.joe_detail__article');
if (article_content) {
var catalog = get_catalogs(article_content);
if (catalog.length == 0) {
// 无目录,隐藏
$('.catalogue').hide();
} else {
let catalogue = '';
for (let i = 0; i < catalog.length; i++) {
let node = '<li class="catalogue-item"><a href="javascript:;" id="to-' + catalog[i].id + '" to="' + catalog[i].id + '" title="' + catalog[i].text + '">' + catalog[i].text + '</a>';
if (i == catalog.length - 1) {
catalogue += node + '</li>'
} else {
if (catalog[i + 1].level == catalog[i].level) {
catalogue += node + '</li>';
} else if (catalog[i + 1].level > catalog[i].level) {
catalogue += (catalog[i + 1].level > 1) ? node + '<ul class="level-' + catalog[i + 1].level + '">' : node + '</li>';
} else {
if (catalog[i + 1].level - catalog[i].level == -2) {
catalogue += i > 1 ? node + '</li></ul></li></ul></li>' : node + '</li></ul></li>';
} else {
catalogue += i > 1 ? node + '</li></ul></li>' : node + '</li>';
}

}
}
}
document.querySelector('.catalogue-items').innerHTML = catalogue;
$('.catalogue-item > a').on('mouseenter', function () {
$(this).parent().addClass('_active');
});
$('.catalogue-item > a').on('mouseleave', function () {
$(this).parent().removeClass('_active');
});
// 根据目录定位到标题
$('.catalogue-item > a').on('click', function () {
document.removeEventListener("scroll", autoActive);
$('.catalogue-item').removeClass('active');
$(this).parent().addClass('active');
let aim = document.querySelector('#' + $(this).attr('to'));
let aim_top = aim.offsetTop;
let aim_h = aim.clientHeight;
let above_h = document.querySelector('.joe_header__above').clientHeight;
let below_h = document.querySelector('.joe_header__below').clientHeight;
let offset = 0;
let case1 = !document.querySelector('.joe_header__above').className.includes('active');
let case2 = document.getElementsByTagName("html")[0].scrollTop + above_h > aim_top;
if (case1 && case2) {
offset = above_h;
}
window.scrollTo({
top: aim_top - offset - below_h - 10,
behavior: 'smooth'
});
setTimeout(() => {
document.addEventListener("scroll", autoActive);
}, 500);
});
if (catalog.length)
$('.catalogue-item').eq(0).addClass('active');
// 目录侧标题自动定位
let autoActive = function () {
let html_top = document.getElementsByTagName("html")[0].scrollTop; //获得父级卷去的高度
for (let i = 0; i < catalog.length; i++) {
let offset = 0;
let h_id = '#' + catalog[i].id;
let h_offset = document.querySelector(h_id).offsetTop;
let above_h = document.querySelector('.joe_header__above').clientHeight;
let below_h = document.querySelector('.joe_header__below').clientHeight;

if (!document.querySelector('.joe_header').className.includes('active'))
offset = above_h;
if (h_offset + below_h + offset + 10 >= html_top) {
$('.catalogue-item').removeClass('active');
if (i > 0 && i < catalog.length - 1 && document.querySelector('#' + catalog[i].id).offsetTop > html_top + window.innerHeight * 0.2) {
//还没到下一个标题
i--;
}
$('#to-' + catalog[i].id).parent().addClass('active');
break;
}
}
};
document.addEventListener("scroll", autoActive);
}
} else {
// 不是文章,隐藏目录
$('.catalogue').hide();
}

第三步

在主题后台设置 - 全局设置 - 自定义 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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
.joe_aside__item.catalogue {
z-index: 999;
position: sticky;
top: 60px;
margin-bottom: 15px;
transition: top 0.35s;
background: var(--background)
}

.joe_aside__item.catalogue .joe_aside__item-contain {
padding: 0;
margin: 0 0 0 10px;
}

.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items {
border-left: 1px solid var(--classC);
border-bottom: 1px solid var(--background);
padding: 15px
}

.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item {
margin: 0;
padding: 0;
line-height: 26px;
font-size: 16px
}

.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item a {
position: relative;
display: block;
line-height: 26px;
color: var(--main);
transition: color 0.5s
}

.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item a:hover {
color: var(--theme)
}

.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item._active > a, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item.active > a {
color: var(--theme)
}

.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item._active > a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item.active > a::before {
content: "";
position: absolute;
left: -17px;
top: 0;
width: 2px;
height: 26px;
background-color: var(--theme);
transition: height 0.35s
}

.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2.catalogue-item, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item {
font-size: 14px
}

.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item._active > a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item.active > a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item._active > a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item.active > a::before {
left: -34px
}

.joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item .level-3 .catalogue-item, .joe_aside