Hexo 主题修改:为博客实现更多功能

Navigation
  1. 1. 快速导航
    1. 1.1. 文章内容插入快速导航
    2. 1.2. 快速导航主体
    3. 1.3. CSS 样式
    4. 1.4. 增强效果
  2. 2. 返回顶部
    1. 2.1. 主体 Action
  3. 3. Swiftype 搜索
    1. 3.1. 获取安装代码
    2. 3.2. 修改原先搜索框架
    3. 3.3. 选择插入位置
    4. 3.4. 配置参数

主要介绍快速导航、返回顶部、Swiftype 搜索等功能的实现,代码实现细节直戳 GitHub

快速导航

Hexo 已经内置支持快速导航(即文章目录),只是有些主题没有提供支持。

文章内容插入快速导航

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ..\layout\_partial\article.ejs
// 各主题结构可能存在出入
<article class="<%= item.layout %>">
// ...
<div class="entry">
<% if (item.excerpt && index){ %>
<%- item.excerpt %>
<% } else { %>
<% if (!index){ %>
// 插入快速导航
<%- partial('toc') %>
<% } %>
<%- item.content %>
<% } %>
</div>
// ...
</article>
<% if(!index && item.toc){ %>
// 插入快速导航 action js
<%- partial('toc_action') %>
<% } %>

快速导航主体

1
2
3
4
5
6
7
8
// ..\layout\_partial\extra\toc.ejs
<% if(item.toc && item.toc != false){ %>
<div id="toc" class="toc-article">
// 多语言支持
<strong class="toc-title"><%= __('navigation') %></strong>
<%- toc(item.content) %>
</div>
<% } %>

CSS 样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ..\source\css\_partial\article.styl
.toc-article
float right
#toc
background #eee
margin 0 0 .5em 1.5em
padding 1em
border 2px solid color-link
line-height 1em
font-size .8em
strong
padding .3em 0
ol
margin-left 0
.toc
padding 0
li
list-style-type none
.toc-child
padding-left 1.5em

以上就基本实现了快速导航,有些细节需要根据自身主题进行修改调试。下面就 toc action 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
// ..\layout\_partial\extra\toc_action.ejs
// 底部添加快速导航开关图标(移动设备上可关闭,不影响阅读)
<div id="menu-nav" class="footer-btn">
<a title="<%= __('quick_nav') %>"><img src="/img/list.png"/></a>
</div>
<script type="text/javascript">
$(function(){
var toc = $('#toc');
var nav = $('#menu-nav');
var toccopy;
var status = true;
if ($(window).width() <= 583)
status = false;
var first = true;
var position = toc.position();
var wid = toc.width();
$(window).scroll(onScroll);
$(nav).click(opennav);
function tocout() {
if (first && status) {
// 复制 toc 副本,将源 toc 浮起,toccopy 占位使得源 toc 浮起后不影响文档流
toccopy = $(toc).clone();
$(toccopy).insertAfter(toc);
toc.css('float','');
toc.css('position','fixed');
onResize();
toc.css('z-index','99');
toc.css('width',wid);
$(window).resize(onResize);
first = false;
// toccopy 占位但隐藏(仍占据文档流)
toccopy.css('visibility', 'hidden');
}
}
// 当 toc 超出窗口范围时,浮起固定位置
function onScroll() {
var top = $(window).scrollTop();
if(top >= position.top + 30){
tocout();
$(nav).stop().fadeTo(300, 1); // fade back in
$(nav).animate({bottom: "25px"}, { queue: false, duration: 10 });
}else{
hidNav();
$(window).off("resize", onResize);
$(nav).stop().fadeTo(300, 0); // fade out
$(nav).animate({bottom: "-200px"}, { queue: false, duration: 10 });
}
}
// 响应式支持
function onResize() {
var width = $(window).width();
var left = $('#sidebar').position().left;
if (width > 883){
toc.css('top', '88px');
toc.css('left', left - 18);
} else{
var top = $('#nav-top').innerHeight();
toc.css('top', top);
var fix = $('#main-col').width() - toc.width() - 35;
toc.css('left', left + fix);
if($(window).scrollTop() >= position.top + 30){
$(nav).stop().fadeTo(300, 1); // fade back in
$(nav).animate({bottom: "25px"}, { queue: false, duration: 10 });
}
}
}
function hidNav() {
toc.css('position','');
toc.css('float','right');
$(toccopy).remove();
first = true;
}
function opennav() {
if (status) {
status = false;
hidNav();
} else {
status = true;
tocout();
}
}
});
</script>

返回顶部

主体 Action

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
// ..\layout\_partial\extra\to_top.ejs
<div id="totop" class="footer-btn">
<a title="<%= __('return_top') %>"><img src="/img/scrollup.png"/></a>
</div>
<script type="text/javascript">
$(function(){
// When to show the scroll link
// higher number = scroll link appears further down the page
var upperLimit = 800;
// Our scroll link element
var scrollElem = $('#totop');
// Scroll to top speed
var scrollSpeed = 500;
// Show and hide the scroll to top link based on scroll position
scrollElem.hide();
$(window).scroll(function () {
var scrollTop = $(document).scrollTop();
if ( scrollTop > upperLimit ) {
$(scrollElem).stop().fadeTo(300, 1); // fade back in
$(scrollElem).animate({bottom: "50px"}, { queue: false, duration: 10 });
} else {
$(scrollElem).stop().fadeTo(300, 0); // fade out
$(scrollElem).animate({bottom: "-200px"}, { queue: false, duration: 10 });
}
});
// Scroll to top animation on click
$(scrollElem).click(function(){
$('html, body').animate({scrollTop:0}, scrollSpeed);
$(scrollElem).animate({bottom: "-200px"}, { queue: false, duration: 10 });
return false;
});
});
</script>

Swiftype 搜索

Swiftype 是一个很好用的站内搜索服务,使用它可以很大程度地改善目前静态博客的搜索体验。

获取安装代码

1
2
3
4
5
6
7
8
9
10
11
// ..\layout\_partial\extra\swiftype_search.ejs
<% if (theme.swiftype_search.enable){ %>
<script type="text/javascript">
(function(w,d,t,u,n,s,e){w['SwiftypeObject']=n;w[n]=w[n]||function(){
(w[n].q=w[n].q||[]).push(arguments);};s=d.createElement(t);
e=d.getElementsByTagName(t)[0];s.async=1;s.src=u;e.parentNode.insertBefore(s,e);
})(window,document,'script','//s.swiftypecdn.com/install/v1/st.js','_st');
_st('install','<%- theme.swiftype_search.install_code %>');
</script>
<% } %>

修改原先搜索框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ..\layout\_widget\search.ejs
<div class="search">
<% if (theme.swiftype_search.enable) { %>
<form>
<input id="<%- theme.swiftype_search.search_input_selector %>" type="search" placeholder="<%= __('search') %>">
</form>
<div id="st-results-container"></div>
<% } else { %>
<form action="//google.com/search" method="get" accept-charset="utf-8">
<input type="search" name="q" results="0" placeholder="<%= __('search') %>">
<input type="hidden" name="q" value="site:<%- config.url.replace(/^https?:\/\//, '') %>">
</form>
<% } %>
</div>

选择插入位置

1
2
3
// ..\layout\_partial\sidebar.ejs
// 添加如下代码,插入
<%- partial('extra/swiftype_search') %>

配置参数

1
2
3
4
5
// ..\_config.yml
swiftype_search:
enable: true
install_code: *****************
search_input_selector: st-search-input