为 Hexo 自动生成友链页面

1.9k 3 mins
... ...

  友链页面做好了!请看→「魔女の部屋」
  为什么友链的标题是「魔女の部屋」,是看了伍尔芙的《一间只属于自己的房间》之后突发奇想:我们的 blog 是不是也算一种赛博意义上的「只属于自己的房间」呢?
  总之这里是一篇崭新的 hexo 笔记⸺

  先展示一下效果(为了防止之后友链爆仓【?所以只保留了第一行):

  没错!这个友链和之前的标签列表一样也是可以到处搬的,不愧是我.jpg
  又及:不要因为我的 blog 整得花里胡哨就不敢和我换友链啊 QAQ【好古早的颜文字

旧方案

  最原始的友链方案就是手写一连串 dom,后来想到了一个方案是可以用 markdown 的列表半自动生成,大概是这样:

1
2
3
4
5
6
7
8
9
10
<div>

- ![头像](.../avatar.png)
- [友链标题 1](URL)
- 链接描述。
- ![头像](.../avatar.png)
- [友链标题 2](URL)
- 链接描述。

</div>

  优点是多快好省,缺点是 markdown 直接生成的列表没有 classname,如果想写 css 样式只能用 JS 挨个打标(引入了 jQuery):

1
2
3
4
5
6
7
if ($('#link-box').length > 0) {
$('#link-box >ul').addClass('link-list');
$('.link-list >li').addClass('link-item');
$('.link-item').each(function(){
$(this).find('li:first').addClass('link-title')
})
}

  光添加 classname 还不够,如果想做出我想要的效果还需要把链接的 <a> 标签包裹到最外面:

1
2
3
4
5
6
7
8
$('.link-item').each(function(){
var url = $(this).find('a').attr('href');
$(this).wrap(document.createElement("a"));
$(this).parent().attr("href",url).addClass('link-url');
})
$('.link-item').find('a').each(function(){
$(this).replaceWith($('<span>' + this.innerHTML + '</span>'));
})

  折腾一翻也可以半自动生成需要的框架,但是代码很复杂,而且还容易和页面上的其它 JS 打架(比如处理图片的脚本,源文件里还有一堆用来解决这个问题的代码因为写得太蠢就不放出来了),所以虽然成功整出来了也一直不太满意。
  这次折腾新主题的时候突然想到:是不是可以用主题的 ejs 模板直接生成友链页面?

新方案

  首先还是惯例声明本方案使用 ejs 编写,如果你的主题不是用 ejs 写的,大概可以参考一下变量名?
  另外建议阅读一下之前的「为 Hexo 主题添加分类与标签列表」那篇,实现思路几乎是完全一致的,所以这篇笔记我可能会下意识地忽略一些地方……毕竟同一件事描述第二遍就会开始逐渐失去耐心【。

添加链接

  在主题_config.yml 中新起一行写入友链,格式如下:

1
2
3
4
5
6
7
8
9
10
11
link:
-
name: '⸸ 旧都日记。'
url: 'https://rei.eterfinal.ink/'
img: 'https://rei.eterfinal.ink/icon.png'
note: '「ラッタッタ口ずさんだ歌の名を知りたくて。」'
-
name: '链接标题'
url: 'url'
img: '链接图片'
note: '链接描述'

  尝试过把这一段写在站点的 _config.yml 里但是好像没办法读取的样子,只能退而求其次写在主题配置里了。
  需要注意的是这四个信息中都不能出现英文引号,如 one's,我折腾了很久也没试出来避免字符被转义的方法,只能想办法避免掉了。

添加页面

  首先用 hexo new page link 新建一个页面,然后在页面的 front-matter(就是写标题和日期的那部分)添加一行写上 islink: true ,像这样:

1
2
3
4
5
---
title: 魔女の部屋
date: 2025-03-07 22:56:47
islink: true
---

  然后在正文中创建一个 div 用来放置友链列表,像这样:

1
2
3
4
5
6
7
---
title: 魔女の部屋
date: 2025-03-07 22:56:47
islink: true
---

<div id="link-box"></div>

  然后页面的基本构架就完成了,在保留 #link-box 的前提下可以随意添加内容,就像普通文章一样。

EJS 部分

  接下来开始生成我们的友链!
  找到主题目录下的 layout/_partials 文件夹,新建 link.ejs 文件,然后写入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<% if (page.islink && theme.link.length){ %>
// 判断页面是否包含【islink】参数,以及主题配置中是否有【link】内容
<ul id="link-list">
<% theme.link.forEach(function(item) { %>
// 为每一个友链对象生成如下内容
<li id='<%= item.name %>' class='link-item'>
// 创建 id 为友链标题的列表
<a class='link-href' href="<%= item.url %>">
// 创建链接
<img src="<%= item.img %>">
// 友链图片
<span class='link-note'><%= item.note %></span>
// 站点描述
<span class='link-name'><%= item.name %></span>
// 站点标题
</a>
</li>
<% }); %>
</ul>
<% } %>

  具体的元素架构可以按需求自行调整。
  一个小技巧是最后生成的元素会出现在最上层,如果你准备像我一样做一个内容互相重叠的 css 样式,把标题写在最下面可以避免用 z-index 调整图层的问题(这个玩意真的很难搞,谁用谁知道)。

  写完后找到主题的 layout\post.ejs 文件,新建一行将刚才写的内容加入到正式的 layout 中即可,如下:

1
<%- partial('_partials/link', {post: page}) %>

JS 部分

  做完以上操作刷新界面会发现友链出现在了奇怪的地方,需要用 JS 把它调整到合适的位置,也就是刚才新建页面时创建的 div#link-box 中。
  引入 jQuery 后用如下 JS 代码移动友链列表:

1
2
3
4
5
if ($('#link-list').length > 0) {
$(document).ready(function() {
("#link-list").prependTo("#link-box");
})
};

  然后刷新页面就可以看到更改了。

优化建议

  此外还有一些优化上的小建议,如果你像我一样非常依赖 jQuery 的选择器,那么强烈建议修改主题文件将 jQuery 的引用移动到 <head> 中。存放脚本的 layout 文件名一般是 scripts.ejsfooter.ejs ,生成 <head> 的一般就是 head.ejs ,将引用 jQuery 的那一行从前者剪贴到后者即可。
  完成之后就可以直接在 markdown 文件里使用 jQuery 选择器,比如我们的友链界面可以改成下面这个样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
---
title: 魔女の部屋
date: 2025-03-07 22:56:47
islink: true
---

<div id="link-box"></div>
<script type="text/javascript">
$(document).ready(function(){
("#link-list").prependTo("#link-box");
}
});
</script>

  因为 markdown 里直接写入的文本只会作用于当前页面,那么已知当前页面上一定会有友链列表,就不用再检测元素是否存在了。
  同理之前的标签和分类列表也可以按照这个思路优化,虽然可能对页面的加载速度会有一些细微的影响,但维护难度会大大降低。而且这样写整个列表也是可以移动的,只要在其它演示页面把 islink: true 和 JS 代码一起复制过去即可。

彩蛋

广告位 招租 谁来 换友链

  【开玩笑的也不是跟谁都换,但是如果是互 fo 的话ぜひ!