Hexo自定义主题(二)

标签: Hexo 分类: 前端 创建时间:2019-03-27 08:24:30 更新时间:2023-10-20 11:23:25

接上一篇文章:Hexo自定义主题(一)

1.404页面

404页面的生成,一种方式是直接生成一个404.html放到source文件夹根目录下,另一种是使用hexo new page 404生成一个模板的404页面(在source文件夹下,会生成一个404文件夹,文件夹里有index.md和index文件夹,在index.md编写页面即可)。在本地调试的时候,可能还是会出现Cannot GET这样的字符串,但是发布到github上,就可以看出效果来了。因为使用的是new page方式,所以在主题的layout文件夹下如果存在page.swig,hexo会默认已它为模板生成html,只需要在page.swig中定义模板的样式,就可以使用自定义的header,footer等元素就可以保留了。很多人使用腾讯的公益404页面,但是可能会出现问题。

意思是要使用https这种网址。
使用hexo new page “page”新建的page页,默认使用page.swig模板创建,如果想使用其他的模板文件,可以在page的顶部输入layout:other(你想要的layout布局名,只要能通过if区分开你想加载的swig即可),然后在page.swig使用page.layout属性加载不同的子swig文件,这样就可以做到不同的page使用不同的layout了。page.swig中就像这样

1
2
3
4
5
6
7
{% if page.layout=="page" %}
{% set layout='./_page/index.swig' %}
{% include layout %}
{% else %}
{% set layout='./_page/'+page.layout+'.swig' %}
{% include layout %}
{% endif %}

因为swig中的extends标签,是将当前模板扩展为一个父级模板。该标签必须在模板的最前面。再用include引入一层就可以了,在“./_page/index.swig”中,就可以使用“extends ‘../_layout.swig’”了。
至于新建页面的css,js等的引用,你可以直接通过标签的方式写道index.md中,不过在渲染的时候,可能生成的html,css和js就要在文章内部了,而不是在head或者body底部,其实也不影响文章呈现,因为hexo默认是根据模板生成html,你的page.swig中的page.content在哪,你md中的js,css就在哪里了,如果不想让page页面生成时经过模板,可以将layout设置为false,跳过模板,就把index.md当成一个独立的html,head想写啥写啥,body想放哪放哪,script想放开头就放开头,想放结尾就放结尾,还有一种方式是用hexo生成器,生成一个页面。

1
2
3
4
5
6
7
hexo.extend.generator.register('archive', function(locals){
return {
path: 'archives/index.html',
data: locals.posts,
layout: ['archive', 'index']
}
});

2.hexo的page页面中使用图片

使用hexo new page [name]命令默认会在source文件夹下生成一个name的文件夹,name文件夹下包含两个文件一个是index.md和index文件夹,在index.md文件中可以写任何html语句。

1
2
3
4
## markdown中这样的html语句
<div>
<img src="/404/index/m.png"/>
</div>

在index.md中同样可以使用图片,例入“<img src=’/404/index/m.png’/>”,new page时会生成一个index文件夹,将照片放到文件夹中,使用决定路径进行引用即可,也可以自己添加和index文件夹同级的文件夹,将图片等资源放到里面。(使用带斜杠的引用方式的副作用是,当博客放在二级目录的时候,会不会出现找不到引用资源的问题?还有待研究)还可以直接引入带http字样的图片。

3.hexo 文章页面中使用html

在markdown中虽然可以编写html,markdown中对html也是兼容的,但是要想编写大段的html,为html标签添加css等样式,在md文件中编写,就力不从心了。在编写的style标签和html标签中,如果在写的时候,为了美观,输入了回车键,进行了换行,hexo的markdown渲染引擎会自动加入一个<br>标签,甚至时css也会给你添加<br>,使css变成了普通文本,无效了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
## markdown中这样的html语句
<div>
<img src="/404/index/m.png"/>
</div>
## 经过渲染之后
<div>
<br>
<img src="/404/index/m.png">
<br>
</div>
## md文件中的css
<style type="text/css">
.bg{
width:50%;
}
</style>
## 渲染后的css
<style type="text/css"><br> .bg{<br> width:50%;<br> }<br></style>

更加hexo对文章的渲染流程,先执行before_post_render过滤器,然后使用 Markdown 或其他渲染器渲染(根据扩展名而定),然后使用Nunjucks渲染,最后执行 after_post_render 过滤器,那么我们可以改变渲染器,将md后缀改为html,那么hexo就会使用html渲染器而不是Markdown渲染器进行渲染了,就会避免加入不必要的换行符了。

4.响应式页面

1
2
3
4
5
6
7
@media (min-width: 768px){ //>=768的设备 }
@media (min-width: 992px){ //>=992的设备 }
@media (min-width: 1200){ //>=1200的设备 }

@media (max-width: 1199){ //<=1199的设备 }
@media (max-width: 991px){ //<=991的设备 }
@media (max-width: 767px){ //<=768的设备 }

5.在脚本中使用hexo的配置

在主题的根目录的scripts中的js脚本文件,每次hexo部署和生成文章时都是自动调用执行的,可以是任意文件名。在其中使用编写hexo的生成器,函数等内容,如何获取主题的相关配置?

1
2
3
4
//主题的配置文件theme/_config.yml
console.log(hexo.theme)
//站点的主配置文件_config.yml
console.log(hexo.theme.context.config);

6.添加萌萌的看娘

我发现了一个奇怪的现象,屌丝程序员一半都喜欢看动画片,像我就是,而更多的人也喜欢二次元的萌妹甚至超过了现实中的女人,所以在很多使用了Hexo和WordPress搭建的博客中,在左下角或着右下角会有一些萌萌的妹子,不仅可以跟随鼠标有相应的动作,还有些有声音有简单的语言,看起来就很想玩。

所以我尝试着收集了些网站,供大家参考,感兴趣的可以在自己的博客中加入萌妹,其实不止止是萌妹,还有些好玩的背景动画,比如Next主题的背景中鼠标可以点击会动的线等。

7.归档页中按年份将文章分类

hexo的分档页面默认是以分页的形式出现,如果在配置文件中添加了archive_generator的配置,则Hexo在生成的时候会使用相关配置,否则会使用index_generator的配置。类似于next主题。

1
2
3
4
5
6
7
8
index_generator:
per_page: 5
archive_generator:
per_page: 20
yearly: true
monthly: true
tag_generator:
per_page: 10

现在我自定义的归档页面,有一个需求就是归档页面不再分页了,而是左侧有个年份列表,右侧是每一年的时间轴文章,该如何实现呢?
主要思想就是遍历全部的文章,将同一年的文章放到同一个对象中,然后遍历每一个对象,将相关的文章放到对应分类下。这里有个问题就是swig语法时不支持array.push这种语法的,那么如何在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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//文章列表数组实例
/**
* postObj={
* "2019":[
* {name:"",url:"",date:""},
* {name:"",url:"",date:""},
* {name:"",url:"",date:""},
* ],
* "2018":[
* {name:"",url:"",date:""},
* {name:"",url:"",date:""},
* {name:"",url:"",date:""},
* ],
* }
*
*/

<ul>
{% set postObj={} %}
{% for post in site.posts %}
{% set post.year = date(post.date, 'YYYY') %}
{% if !postObj[post.year] %}
{% set temp=[] %}
{% set length=temp.length %}
{% set temp[length] ={name:post.title,url:url_for(post.path),date:date(post.date,"MM月D日")} %}
{% set postObj[post.year]=temp %}
{% else %}
{% set temp=postObj[post.year] %}
{% set length=temp.length %}
{% set temp[length] ={name:post.title,url:url_for(post.path),date:date(post.date,"MM月D日")} %}
{% endif %}
{% endfor %}
{% for year,postArray in postObj %}
<li>
<span>{{year}}</span>
<ul class="layui-timeline">
{% for post in postArray%}
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis">&#xe63f;</i>
<div class="layui-timeline-content layui-text">
<h3 class="layui-timeline-title">{{post.date}}</h3>
<div><a href="{{post.url}}" target="_blank">{{post.name}}</a></div>
</div>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>

8.添加搜索框

文章写的越来越多,自然就需要一个搜索框方便的查询,但是对于一个静态站点来说,要实现添加搜索框还是挺不容易的。有两种方式,一种就是通过插件生成本地的索引文件,随页面一起下载,借助javascript实现在索引文件中查找内容,并跳转,这统称为本地搜索;另一种就是借助于其他专业站点的形式,例如Algolia,原理就是在搜索网站上注册你站点的地址,然后插件网站会收集你站点的文章的信息,然后在自己数据库中生成索引,在搜索时,实际上是通过在插件站点服务器上搜索,返回内容,然后供你调用。
本地搜索的缺点主要是如果文章很多,搜索文件可能会很大,随页面一起加载,就会拖慢网站的加载速度。第三方搜索网站搜索呢,缺点主要是会有索引条数和搜索次数的限制。下面我给大家演示下,我自定义主题时集成Algolia搜索的过程。

(1)官网注册账号

进入官网,注册账号,确认邮件然后填写基本信息

(2)进入控制面板

登录官网,点击DASHBOADR,进入控制面板。

(3)生成Indices页面

点击控制面板右侧Indices选项

输入页面名称

(4)安装hexo-algoliasearch

进入工程目录(不是主题文件夹),执行:npm install hexo-algoliasearch –save

(5)编写配置文件

在站点配置文件_config.yml中增加如下内容,其中appId,apiKey,adminApiKey,indexName根据algolia网站中配置,点击Algolia控制面板的API keys选项可以查看,apiKey就是“Search-Only API Key”。hexo-algoliasearch的github上,会要求配置文件中有plugins:hexo-algoliasearch一项,但是实际上写了会出错,只会生成一个indexed,不写,hexo也能自动识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## 这个插件配置可以去掉
## plugins:
## - hexo-algoliasearch

algolia:
appId: "Z7A3XW4R2I"
apiKey: "12db1ad54372045549ef465881c17e743"
adminApiKey: "40321c7c207e7f73b63a19aa24c4761b"
chunkSize: 5000
indexName: "my-hexo-blog"
fields:
- content:strip:truncate,0,500
- permalink
- tags
- title

(6)执行hexo algolia

(7)添加搜索代码

添加搜索的代码比较简单,先引入js文件,然后编写查询语句,至于样式和按钮,这里就不详细说明了,只要适时调用index.search就可以了。

1
2
3
4
5
6
7
8
<script src="https://cdn.jsdelivr.net/algoliasearch/3/algoliasearchLite.min.js"></script>
<script type="text/javascript">
var client = algoliasearch('appId', 'apiKey');
var index = client.initIndex('indexName');
index.search('hexo', (err, { hits } = {}) => {
console.log(hits);
});
</script>

返回的结果类似于这个,然后解析其中的内容即可。官网上也提供了直接加载searchUI的说明,详见参考文章。

9.将页面中的style和script抽取出来,放到页面的head区域

这个想法是这样的,因为有时候你想在页面中写一些css样式,或者是一些script脚本,如果单纯的将代码写道文章中(建议将html写道后缀为html文件的中,而不是md文件中,md文件会自动转义,在vscode中显示不好,像style标签,不能换行),最后经过渲染,可能你的css和script都会在页面的body区域了,这个时候,我想用代码把他们抽出来,放到页面的head区域和body的最底部,符合代码书写的规范。

首先就要定义过滤器,然后就是安装cheeio(nodejs端使用的精简版jquery,适合操作html),然后抽取里面的style和script,将其放到变量data的styles和scripts数组中,然后就是修改负责页面渲染的swig文件,变量page.styles和page.scripts,将内容分别填充到head区域和body区域。

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
var cheerio = require('cheerio');
//主要进行图片的处理
hexo.extend.filter.register('after_post_render', function(data){
let content=data.content;
data.scripts=[];
data.styles=[];
//提取文章中的style和scripts分别将其放置到页面的head区域和body区域,而不是内容区域
var $ = cheerio.load(content, {
ignoreWhitespace: false,
xmlMode: false,
lowerCaseTags: false,
decodeEntities: false
});
$('style').each(function(index,item){
var text=$(this).html().trim();
$(this).remove();
data.styles.push(text.replace(/[\r\n]/g,""));
})
$('script').each(function(index,item){
var text=$(this).html().trim();
$(this).remove();
data.scripts.push(text.replace(/[\r\n]/g,""));
})
content=$.html().replace(/[\r\n]/g,"");
data.content=content;
return data;
});

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
{% extends '../_layout.swig' %}
{% block title %}{{ page.title }} | {{theme.title}}{% endblock %}

{% block head %}
{% for item in page.styles %}
<style>
{{item}}
</style>
{% endfor %}
{% endblock %}
{% block content %}
<div class="layui-row">
<div class="layui-col-xs12 layui-col-sm10 layui-col-sm-offset1 layui-col-md6 layui-col-md-offset3 layui-col-lg6 layui-col-lg-offset3">
{{page.content}}
</div>
</div>
{% endblock %}
{% block scripts %}
{% for item in page.scripts %}
<script>
{{item}}
</script>
{% endfor %}
{% endblock %}
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。