惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
Google DeepMind News
Google DeepMind News
罗磊的独立博客
Martin Fowler
Martin Fowler
博客园_首页
Stack Overflow Blog
Stack Overflow Blog
Last Week in AI
Last Week in AI
The GitHub Blog
The GitHub Blog
B
Blog
C
Check Point Blog
WordPress大学
WordPress大学
G
Google Developers Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
量子位
月光博客
月光博客
U
Unit 42
Engineering at Meta
Engineering at Meta
有赞技术团队
有赞技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
大猫的无限游戏
大猫的无限游戏
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Y
Y Combinator Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Vercel News
Vercel News
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - 【当耐特】
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Jina AI
Jina AI
S
Secure Thoughts
aimingoo的专栏
aimingoo的专栏
D
Darknet – Hacking Tools, Hacker News & Cyber Security
I
Intezer
Latest news
Latest news
V
Vulnerabilities – Threatpost
D
Docker
Attack and Defense Labs
Attack and Defense Labs
Help Net Security
Help Net Security
S
Security @ Cisco Blogs
Forbes - Security
Forbes - Security
MongoDB | Blog
MongoDB | Blog
云风的 BLOG
云风的 BLOG
L
LINUX DO - 热门话题
P
Palo Alto Networks Blog
Cloudbric
Cloudbric
Spread Privacy
Spread Privacy

贰猹の小窝

个人哔哔: 谈薪时间-该问hr哪些问题 个人哔哔: 秋招与未来 个人哔哔: 2022年度总结与全新的大饼 猹的魔改日记-文章页抛弃卡片、丢弃小菜单以及布局重构 猹的魔改日记-小小的重写个页脚 回忆录: 知心友与白月光 rust写个操作系统——课程实验blogos移至armV8深度解析:实验八下 内存管理 rust写个操作系统——课程实验blogos移至armV8深度解析:实验八上 内存管理 HNU工训综合项目二:基于485总线的评分系统速通指北 rust写个操作系统——课程实验blogos移至armV8深度解析:实验七 死锁与简单处理 rust写个操作系统——课程实验blogos移至armV8深度解析:实验六 GPIO关机 rust写个操作系统——课程实验blogos移至armV8深度解析:实验五 输入 rust写个操作系统——课程实验blogos移至armV8深度解析:实验四 中断 rust写个操作系统——课程实验blogos移至armV8深度解析:实验二 Hello World 关于linux: 设备树浅析(更新中) rust写个操作系统——课程实验blogos移至armV8深度解析:实验一 环境配置 rust写个操作系统——课程实验blogos移至armV8深度解析 猹的魔改日记-小菜单和复制/F12提示栏 个人哔哔: 一年期至,又一年始(不定时写完)
从零开始的异世界主题开发生活-hexo事件管理与扩展使用
noionion · 2023-01-05 · via 贰猹の小窝

前言

想起一年半以前,想要对我的初版博客进行整体的魔改,然后设计了我的首版卡片(并不会写但是设计粗来了)。然而一年半过去了,我的博客经历了大大小小的魔改调整,文章页改完了卡片反而觉得不搭了。改着改着又不太喜欢文章卡片式设计等等。

种种原因到我想放弃 butterfly。用店长的话说就是,魔改到现在也不算在坚守 bf 了。

于是我开始寻思着要不要换主题,而 stellar 很合我心意,但又有我很中意但又太复杂且定位不符的 wiki 功能。于是思来想去,决定自己开发一个主题吧,也学一学自己拒绝了两年的前端。

废话完了,开始讲记录吧。hexo 主题的开发对于我这个前端半生不熟的人来讲还是很有难度的。本身也没有画过时间系统的学习前端。js 最多就是魔改 bf 的时候稍微模仿着写一点点的程度,css 也就只有常用的一些相对熟悉一点,动画、布局、定位这些毫无经验。因此记录是必要,本身写项目就是一种很好的学习方式。

另外记录的是 hexo 本身开发的经历,给一些不满足于魔改的想开发主题的朋友做做参考也行。

友情感谢 @mufanc 同学在开发 rust 博客框架途中被我拐来(甚至弃坑)trefoil 主题的开发,这里着重感谢!


hexo 开发常用-事件系统与扩展api使用

事件: hexo.on

hexo 的文档可谓一塌糊涂,令人开发都不知道何处动笔,只能参考前人主题去做些尝试。当还没确定布局的时候,需要想好自己要哪些脚本进行辅助构建。hexo.on 提供的事件钩子可以让我在一些阶段进行一些数据的构建(例如 stellar 的 wiki 数据结构),也可以在使用 hexo 的时候出现 banner 来体现使用了自己的主题。

hexo 事件文档

比如在 hexo 运行开始,提示一条主题使用语句:

hexo.on('ready', () => {
const { version } = require('../../package.json')
hexo.log.info(` Welcome to trefoil! ${version} `)
})

运行出现如下字样:

PS C:\MyPersonProject\blog\theme-trefoil-demotest> hexo s
INFO Validating config
INFO Welcome to trefoil! 0.0.1
INFO Start processing
INFO Hexo is running at http://localhost:4000/ . Press Ctrl+C to stop.

而在主题开发中,最常用的是 generateBeforegenerateAfter 这两个事件。以 generateBefore 为例:

例如我想在 trefoil 主题中构建一个轻量化的类似 wiki 的合集功能,需要在文章渲染前对所有原始 maekdown 文件的 front-matter 进行统计并构建对象,就需要在这个阶段进行构建(其实可以在过滤器相似的阶段来构建,但这明显不是过滤器应该做的事),然后将其设为全局变量供文章渲染阶段使用。

hexo.on('generateBefore', () => {
const series_dist = {}
const posts = hexo.locals.get('posts')

hexo.locals.set('series_dist', () => series_dist)
})

过滤器 hexo.extend.filter

过滤器是 hexo 中主观上觉得 api 相对完全的一个功能(因为可以说只有它有完整的调用事件列表,相比 hexo.on 能干的事感觉多了不少),甚至也只能在过滤器中去干一些感觉就不应该由它做的事。

前人在过滤器最常见使用的两个功能是修改渲染前/后文件和选择性生成css。后者我还没使用到,前者倒是已经实战了一下。

比如渲染前加入 abbrlink:(这部分代码是 mufanc 帮我写的,我为了合集功能做的主副标题特性与现有的 abbrlink 插件不兼容)

hexo.extend.filter.register('before_post_render', function (data) {
if (data.abbrlink || data.layout !== 'post') return

const config = this.theme.config.abbrlink || this.config.abbrlink || {};
if (!config.enable) return

const mirror = front.parse(data.raw);

const abbrlink = hash(data.title, data.subtitle, data.series_name, data.series_index);
mirror.abbrlink = abbrlink;
data.abbrlink = abbrlink;

fs.writeFileSync(data.full_source, '---\n' + front.stringify(mirror), 'utf-8')

hexo.log.info(`Generate link [${abbrlink}] for post [${data.source}][${data.title+(data.subtitle?(': '+data.subtitle):'')}]`);
}, 15);

它向渲染前的原始文件开头的 front-matter 加入了 abbrlink 参数。而下面这个栗子则是向渲染后的 html DOM 进行代码插入,我需要向代码块中插入几行行代码来实现代码复制和代码展开功能:

hexo.extend.filter.register('after_post_render', function (data) {
const config = this.theme.config
if (config.code.height_limit_enable) {
if (!data.permalink.match(/.*(?:\.html|\/)$/)) {
return;
}

let $ = cheerio.load(data.content)
$('<figcaption></figcaption>').insertBefore('figure.highlight table:not(figcaption + *)')
$('figure.highlight figcaption').append('<i class="ri-file-copy-line"></i>')
$('figure.highlight table').before('<div class="code-expand-btn"><i class="ri-arrow-down-s-fill"></i></div>')
data.content = $.html();
}
});

原先的 DOM 结构如下:

<figure class='highlight'>
<figcaption> /*可能不存在的标题*/
<span>标题</span>
</figcaption>
<table>
<tr>
<td class='gutter'>...</td> /*可能不存在的序号*/
<td class='code'><pre>...</pre></td> /*代码块*/
</tr>
</table>
</figure>

经过过滤器修改后的结构如下:

<figure class='highlight'>
<figcaption> /*必定存在的figcaption*/
<span>标题</span> /*可能不存在的标题*/
<i class="ri-file-copy-line"></i> /*复制图标*/
</figcaption>
<div class="code-expand-btn"><i class="ri-arrow-down-s-fill"></i></div> /*展开图标*/
<table>
<tr>
<td class='gutter'>...</td> /*可能不存在的序号*/
<td class='code'><pre>...</pre></td> /*代码块*/
</tr>
</table>
</figure>

足见过滤器功能之强大。

生成器 hexo.extend.generator

生成器用于生成文章路由,比如我们无需创建 md 文件就可以利用模版生成 404 页面:

hexo.extend.generator.register('404', function (locals) {
return {
path: '/404.html',
layout: ['404']
}
});

这部分功能也还没怎么用。

辅助函数 hexo.extend.helper

辅助函数帮助您在模板中快速插入内容,有点类似与 pug 中的 mixin。但是显然用 js 功能会更加强大一点,同时也可以与前面我们生成的合集数据结构对接。

例如从合集数据结构中生成合集目录供模板调用:

hexo.extend.helper.register('__series_toc', function (page) {
const series_dist = hexo.locals.get('series_dist')
const toc_str = []

return toc_str.join('')
})

之后我就可以在文章页模版使用辅助函数进行调用:

!=__series_toc(page)

结语

文档不能不吐槽,api 提供的我感觉 hexo 的项目结构也不咋合理。但能用还是别自己造轮子了,起码能用。。。